Compare commits

..

91 Commits

Author SHA1 Message Date
David Snopek
4b0ee13327 gdextension: Sync with upstream commit fe0e8e55752b0c2e64997025717b491703e0f8ad (4.1.4-stable) 2024-04-17 13:02:32 -05:00
David Snopek
e4978558e6 Merge pull request #1441 from dsnopek/4.1-cherrypicks-9
Cherry-picks for the godot-cpp 4.1 branch - 9th batch
2024-04-17 12:58:30 -05:00
Chris Cranford
30ebe5fdf9 Fix PropertyInfo to use hint/usage default constants
(cherry picked from commit e160966163)
2024-04-17 11:01:33 -05:00
thimenesup
e897dbe58a Fix Projection create_orthogonal being incorrect
Title

(cherry picked from commit e4ae69f607)
2024-04-17 11:00:56 -05:00
Thaddeus Crews
28a6609c0b Implement verbose toggle from godot repo
(cherry picked from commit b05c21bb1d)
2024-04-17 10:58:41 -05:00
dependabot[bot]
7f3e725a8a Bump mymindstorm/setup-emsdk from 13 to 14
Bumps [mymindstorm/setup-emsdk](https://github.com/mymindstorm/setup-emsdk) from 13 to 14.
- [Release notes](https://github.com/mymindstorm/setup-emsdk/releases)
- [Commits](https://github.com/mymindstorm/setup-emsdk/compare/v13...v14)

---
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>
(cherry picked from commit 32ca574f49)
2024-04-17 10:58:31 -05:00
Thaddeus Crews
8e5d7c9268 Use GDREGISTER defines in example
(cherry picked from commit a537b4af4d)
2024-04-17 10:58:16 -05:00
David Snopek
974e6c6f86 Merge pull request #1411 from dsnopek/4.1-cherrypicks-8
Cherry-picks for the godot-cpp 4.1 branch - 8th batch
2024-04-08 13:09:01 -05:00
A Thousand Ships
c8fa4c0fd0 Fix incorrect utility call signature
(cherry picked from commit d055b575fb)
2024-04-08 11:40:05 -05:00
ytnuf
594a93f8ac Change cmake_minimum_required to match actual requirements
This is because target_link_options was added in v3.13
So this wouldn't build with cmake v3.12

Likewise in CMAKE_CXX_STANDARD only supports value of 17 starting with
cmake v3.9
So the test wouldn't build properly with cmake v3.6

(cherry picked from commit 5c12bd2287)
2024-04-08 11:39:53 -05:00
Thaddeus Crews
9e48c45bfc Enforce template syntax typename over class
(cherry picked from commit 87f5fb0691)
2024-04-08 11:39:21 -05:00
David Snopek
76d6ce7136 Avoid creating most objects that Godot is going to use placement new to initialize
(cherry picked from commit c4fde852e6)
2024-04-08 11:30:23 -05:00
bruvzg
e99d7b3b7e [Packed*Array] Add support for initializer lists.
(cherry picked from commit 8c98a90f32)
2024-04-08 11:29:39 -05:00
A Thousand Ships
07e245e3e4 Fix invalid void return in BitField
(cherry picked from commit 7ed8ef7221)
2024-03-11 13:33:57 -05:00
Marc Gilleron
ed576f8318 Fix explicit namespaces in macros
(cherry picked from commit e607790647)
2024-03-11 13:33:44 -05:00
David Snopek
f7a9d32f32 Fix _notification with parent and child classes
(cherry picked from commit 23c010900c)
2024-03-11 13:31:19 -05:00
bruvzg
08da55cd0b [Core] Improve CowData and Memory metadata alignment.
(cherry picked from commit b173a4d935)
2024-03-11 13:11:26 -05:00
Fabio Alessandrelli
670c4d0eac [SCons] Split targets.py, apply flags from tools
Split `targets` tool logic, moving all the compiler-specific flags to a
new `common_compiler_flags.py` file, and everything else (CPPDEFINES,
optimize option logic, dev build logic, etc) to the `godotcpp` tool.

The default tools now apply the common compiler flags by importing the
file and explicitly calling `configure`.

(cherry picked from commit 16df4bff30)
2024-03-11 13:06:57 -05:00
Fabio Alessandrelli
bab62a4d72 [SCons] Add support for custom build tools and platforms
Use with:

`scons platform=os2 custom_tools=/path/to/tools`

(assuming you have an `os2.py` inside `/path/to/tools/`)

(cherry picked from commit baaad7ada2)
2024-03-11 13:01:23 -05:00
DaylilyZeleen
1ac8627b2e Fix object return value of builtin types' methods.
(cherry picked from commit 6a3753c076)
2024-03-11 12:59:32 -05:00
bruvzg
6202bf141e Switch to 64-bit ints.
(cherry picked from commit 59a5a8b104)
2024-03-11 12:59:19 -05:00
David Snopek
4b63d795e4 Merge pull request #1373 from dsnopek/4.1-cherrypicks-7
Cherry-picks for the godot-cpp 4.1 branch - 7th batch
2024-02-16 09:37:17 -06:00
MJacred
2cc967787a Update README: fix godot-cpp issue tracker url
(cherry picked from commit 8a535d0ecc)
2024-01-24 08:44:28 -06:00
nightblade9
6884ca9be0 Update README.md with basic pre-requisites
(cherry picked from commit ee169b201b)
2024-01-22 15:53:49 -06:00
Daylily-Zeleen
dde0bbb93d Remove "godot" namespace when binding global constants.
(cherry picked from commit bd40a94424)
2024-01-22 15:53:49 -06:00
A Thousand Ships
1c03aa7746 Add missing OP_POWER operator to Variant
(cherry picked from commit f037a697eb)
2024-01-22 15:53:49 -06:00
ArchLinus
82475b215b Add an error message if android NDK is not installed
(cherry picked from commit 718d0baea3)
2024-01-22 15:53:49 -06:00
Aaron Franke
49098fbdc7 Allow detecting when building as a GDExtension
(cherry picked from commit e17c7bf530)
2024-01-22 15:53:49 -06:00
dependabot[bot]
756190705e Bump actions/setup-python from 4 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
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>
(cherry picked from commit a7becb43e6)
2024-01-22 15:53:49 -06:00
Rémi Verschelde
2e42c7020e CMake: Remove hardcoded warnings list and forcing -Werror on library builds
The CMake buildsystem should be completely reviewed to properly match
what is done by SCons, instead of making its own arbitrary decisions on
how godot-cpp should be compiled.

Currently the SCons setup doesn't include warning options, so CMake
shouldn't either. Options similar to upstream Godot's SCons setup could
be added, and then replicated for CMake.

(cherry picked from commit 41517eacb1)
2024-01-22 15:53:49 -06:00
David Snopek
e9273e8528 Avoid error from -Werror=type-limits on GCC 11
(cherry picked from commit cad5be53b1)
2024-01-22 15:53:49 -06:00
David Snopek
b1bd58d7da Send NOTIFICATION_POSTINITIALIZE to extension classes
(cherry picked from commit 20c4e843b0)
2024-01-22 15:53:49 -06:00
LAK132
d5a2e8e797 Fix file list issues when trying to build with meson via cmake
(cherry picked from commit 39c139c814)
2024-01-22 15:53:49 -06:00
Bytzo
6bb4b1d321 Prevent CMake from always including debug symbols
(cherry picked from commit db884e9b1d)
2024-01-22 15:53:49 -06:00
DmitriySalnikov
51aeda7437 [Scons] Set the minimum Android API level to 21
(cherry picked from commit 79d2a9c456)
2024-01-22 15:53:49 -06:00
dependabot[bot]
cd904155a8 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>
(cherry picked from commit 78bf5a42ed)
2024-01-22 15:53:49 -06:00
bruvzg
b622b11df3 [iOS] Fix initialisation/termination of multiple statically linked extensions.
(cherry picked from commit adc9def046)
2024-01-22 15:53:49 -06:00
Rémi Verschelde
92449b46e1 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.

(cherry picked from commit eea33b4133)
2024-01-22 15:53:49 -06:00
Thaddeus Crews
e8b6887b36 Add missing int→Variant conversions
(cherry picked from commit bcac96c8c2)
2024-01-22 15:53:49 -06:00
Rémi Verschelde
631cd5fe37 Merge pull request #1306 from dsnopek/4.1-cherrypicks-6
Cherry-picks for the godot-cpp 4.1 branch - 6th batch
2023-11-13 20:28:26 +01:00
Alex Drozd
731a10a4ea ignoring venv in .gitignore
(cherry picked from commit 92dd34ae96)
2023-11-13 13:00:24 -06:00
Thaddeus Crews
a1ae58448c fix is_msvc and use_hot_reload variables
(cherry picked from commit 648b8c4489)
2023-11-13 13:00:24 -06:00
Thaddeus Crews
805cdde0b7 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

(cherry picked from commit 6eb5d450bd)
2023-11-13 13:00:24 -06:00
Fredia Huya-Kouadio
29335d8f5c Update the environment variables used to access the Android NDK toolchain
(cherry picked from commit 86dbd5fa0d)
2023-11-13 13:00:24 -06:00
Rémi Verschelde
c5f47b2a4e 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.

(cherry picked from commit 306774b5a4)
2023-11-13 19:15:07 +01:00
Rémi Verschelde
df5b1a9a69 gdextension: Sync with upstream commit fc79201851a16215f9554884aa242ed957801b10 (4.1.3-stable) 2023-11-09 13:25:22 +01:00
Rémi Verschelde
04b34077d8 Merge pull request #1281 from dsnopek/4.1-cherrypicks-5
Cherry-picks for the godot-cpp 4.1 branch - 5th batch
2023-10-24 11:38:55 +02:00
David Snopek
9d813310bb Add protections against registering classes that didn't use GDCLASS()
(cherry picked from commit a61cdc8860)
2023-10-23 10:11:04 -05:00
Rémi Verschelde
ef8a499eac SCons: Disable C++ exception handling by default
Counterpart to https://github.com/godotengine/godot/pull/80612.

(cherry picked from commit bf1c03ab5f)
2023-10-23 10:10:59 -05:00
gilzoide
698da13d66 Fix return value and r_valid value in Variant::iter_init and iter_next
(cherry picked from commit 60dfa3445a)
2023-10-22 14:47:10 -05:00
Adam Scott
8295486fdb 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.

(cherry picked from commit 2d5024ac8e)
2023-10-22 14:46:58 -05:00
Thaddeus Crews
7704a9d054 Let gdextension_dir function as only argument
(cherry picked from commit 7a5cbcac21)
2023-10-22 14:46:48 -05:00
David Snopek
f7ffc4fe4d Automatically register only engine classes whose header has been included
(cherry picked from commit b507b3e591)
2023-10-22 14:46:26 -05:00
Fabio Alessandrelli
62cb5eac47 [SCons] Rename javascript tool to web
And clean it up a bit.

(cherry picked from commit 18bfa133ab)
2023-10-22 14:03:20 -05:00
Mikael Hermansson
03ea717742 Declare explicit specializations for CharStringT
(cherry picked from commit 6e05b978b8)
2023-10-22 14:03:10 -05:00
Rémi Verschelde
e389f7a50c Merge pull request #1261 from dsnopek/4.1-cherrypicks-4
Cherry-picks for the godot-cpp 4.1 branch - 4th batch
2023-10-12 18:08:12 +02:00
Nick Maltbie
0b1c8bcac3 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.

(cherry picked from commit 2b4bcbb0ce)
2023-10-09 08:43:36 -05:00
Matthew Murphy
857d8e3a56 Fix variant call compiler error
Co-authored-by: David Snopek <dsnopek@gmail.com>
(cherry picked from commit ca3e25de04)
2023-10-09 08:43:23 -05:00
David Snopek
ec6e51b3a4 Handle missing instance binding callbacks by finding the closest parent
(cherry picked from commit 52ca3ef547)
2023-10-09 08:42:55 -05:00
Adam Scott
f8054cca80 Add support to import custom variables from parent SConstruct (redux)
(cherry picked from commit 982e01ec7f)
2023-10-09 08:42:43 -05:00
A Thousand Ships
59ebcfd744 Fix allocation size overflow check in CowData
(cherry picked from commit 06ffc7e952)
2023-10-09 08:42:31 -05:00
A Thousand Ships
205beacc5b Replace ERR_FAIL_COND with ERR_FAIL_NULL where applicable
(cherry picked from commit 1e5767693e)
2023-10-09 08:42:16 -05:00
Rémi Verschelde
3b3f357de9 CI: Fix MinGW install error by pinning to earlier version
Works around https://github.com/egor-tensin/setup-mingw/issues/14.

(cherry picked from commit 0369f6fea0)
2023-10-04 15:21:01 +02:00
Rémi Verschelde
48b92acf8c gdextension: Sync with upstream commit 399c9dc393f6f84c0b4e4d4117906c70c048ecf2 (4.1.2-stable) 2023-10-04 12:02:54 +02:00
Rémi Verschelde
4eed2d7be0 Merge pull request #1244 from dsnopek/4.1-cherrypicks-3
Cherry-picks for the godot-cpp 4.1 branch - 3rd batch
2023-09-20 23:48:26 +02:00
David Snopek
bc82ae8b0b Add static methods to ClassDB for the methods bound to the ClassDB singleton
(cherry picked from commit 6f913563d8)
2023-09-19 21:30:03 -05:00
David Snopek
590e267902 Load 'print_error_with_message' function
(cherry picked from commit 634ed09ec0)
2023-09-19 21:29:29 -05:00
David Snopek
3be7ec4162 Check that GDExtension is opened by compatible Godot version
(cherry picked from commit fecb2959b4)
2023-09-19 21:27:40 -05:00
DmitriySalnikov
dd8e1def67 [SCons] Fixed crashes in several scripts
(cherry picked from commit 0e5975dd26)
2023-09-19 21:23:20 -05:00
David Snopek
dcd7a69512 Ensure that PtrToArg specializations for native structs are used
(cherry picked from commit 3cd3f24150)
2023-09-19 21:22:54 -05:00
dependabot[bot]
354ed1e79d 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>
(cherry picked from commit 5d4ff63930)
2023-09-19 21:22:20 -05:00
A Thousand Ships
014132d4c0 Ensure const correctness for wrappers
(cherry picked from commit f651df5e7a)
2023-09-19 21:21:20 -05:00
David Snopek
bc980b59ff Merge pull request #1227 from dsnopek/4.1-cherrypicks-2
Cherry-picks for the godot-cpp 4.1 branch - 2nd batch
2023-09-02 12:38:20 -05:00
A Thousand Ships
c3771fb065 Fix formatting of compatibility_minimum examples
Without quotes the values is parsed as a float, breaking in various
cases.

(cherry picked from commit b3596a18e1)
2023-09-01 17:08:03 -05:00
Fabio Alessandrelli
63755b2a32 [SCons] Move the GodotCPP build to its own tool.
(cherry picked from commit f8b4f60cb9)
2023-09-01 17:07:53 -05:00
David Snopek
ce5dd378d9 Clarify versions and examples in the README
(cherry picked from commit 1588dc8437)
2023-09-01 17:07:41 -05:00
A Thousand Ships
c6fe6533f9 Fix link to test project in readme
Also updated format for library paths

(cherry picked from commit e586e11637)
2023-09-01 17:07:30 -05:00
A Thousand Ships
170a691a7e Add remaining component-wise min/max functions to Vector*
(cherry picked from commit 52eb77efd4)
2023-09-01 17:07:18 -05:00
Rémi Verschelde
738ef9baf8 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.

(cherry picked from commit 600e749d9b)
2023-09-01 17:07:03 -05:00
Adam Scott
c7afd0f89a Fix forgotten not operator
(cherry picked from commit f5c8e5190f)
2023-09-01 17:06:51 -05:00
Adam Scott
6789b29b72 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.

(cherry picked from commit 5c262844ad)
2023-09-01 17:06:39 -05:00
David Snopek
960c906da1 Add automated tests to verify some previous fixes
(cherry picked from commit d5fab0b9f8)
2023-09-01 17:06:20 -05:00
Marc Gilleron
0f2d3652e5 Added generated version header
(cherry picked from commit c6b2c82570)
2023-09-01 17:06:03 -05:00
David Snopek
28494f0bd5 Merge pull request #1205 from dsnopek/4.1-cherrypicks-1
Cherry-picks for the godot-cpp 4.1 branch - 1st batch
2023-08-11 10:35:12 -05:00
Feiyun Wang
4fb9af7fb2 Statically link mingw/msvc runtime libraries on Windows
Co-authored-by: David Snopek <dsnopek@gmail.com>
(cherry picked from commit a745c2ac47)
2023-08-10 09:10:04 -05:00
Fabio Alessandrelli
6fa6b8b178 [SCons] Merge OSXCross tools into platofrm ones
(cherry picked from commit 6d195137fe)
2023-08-10 09:09:49 -05:00
Fabio Alessandrelli
784c3dc012 [SCons] Add option to generate a compilation database.
(cherry picked from commit 2586ad016e)
2023-08-10 09:09:30 -05:00
Adam Scott
7a9b323931 Add platform macros
(cherry picked from commit 9d9f4279ed)
2023-08-10 09:09:14 -05:00
Marc Gilleron
e75ec636db Don't cache null forever if a singleton isn't available yet
# Conflicts:
#	binding_generator.py

(cherry picked from commit 548c758677)
2023-08-10 09:08:56 -05:00
David Snopek
5dda0212f6 In generated methods, only construct the method StringName the first time
(cherry picked from commit efc16b49d9)
2023-08-10 09:06:33 -05:00
David Snopek
011965d864 Attempt to fully implement CharString
(cherry picked from commit 4df112cd95)
2023-08-10 09:06:09 -05:00
183 changed files with 8858 additions and 83911 deletions

View File

@@ -1,105 +1,80 @@
# 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 17.0.6).
BasedOnStyle: LLVM
# 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
# AlignArrayOfStructures: None
# AlignConsecutiveAssignments:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: true
# AlignConsecutiveBitFields:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveDeclarations:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveMacros:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCompound: false
# PadOperators: false
# AlignConsecutiveShortCaseStatements:
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
# AlignCaseColons: false
# AlignConsecutiveMacros: None
# AlignConsecutiveAssignments: None
# AlignConsecutiveBitFields: None
# AlignConsecutiveDeclarations: None
# AlignEscapedNewlines: Right
AlignOperands: DontAlign
AlignTrailingComments:
Kind: Never
OverEmptyLines: 0
AlignOperands: DontAlign
AlignTrailingComments: false
# AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortEnumsOnASingleLine: true
# AllowShortBlocksOnASingleLine: Never
# AllowShortCaseLabelsOnASingleLine: false
# AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
# AllowShortIfStatementsOnASingleLine: Never
# AllowShortFunctionsOnASingleLine: All
# AllowShortLambdasOnASingleLine: All
# AllowShortIfStatementsOnASingleLine: Never
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- _ALWAYS_INLINE_
- _FORCE_INLINE_
- _NO_INLINE_
# AttributeMacros:
# - __capability
# BinPackArguments: true
# BinPackParameters: true
# BitFieldColonSpacing: Both
# BraceWrapping:
# AfterCaseLabel: false
# AfterClass: false
# AfterCaseLabel: false
# AfterClass: false
# AfterControlStatement: Never
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# BeforeCatch: false
# BeforeElse: false
# BeforeLambdaBody: false
# BeforeWhile: false
# IndentBraces: false
# BeforeWhile: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
# BreakAfterAttributes: Never
# BreakAfterJavaFieldAnnotations: false
# BreakArrays: true
# BreakBeforeBinaryOperators: None
# BreakBeforeConceptDeclarations: true
# BreakBeforeBraces: Attach
# BreakBeforeConceptDeclarations: Always
# BreakBeforeInlineASMColon: OnlyMultiline
# BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
# BreakBeforeInheritanceComma: false
# BreakInheritanceList: BeforeColon
# BreakBeforeTernaryOperators: true
# BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: "^ IWYU pragma:"
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
# QualifierAlignment: Leave
# CompactNamespaces: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
# DeriveLineEnding: true
# DerivePointerAlignment: false
# DisableFormat: false
# DisableFormat: false
# EmptyLineAfterAccessModifier: Never
# EmptyLineBeforeAccessModifier: LogicalBlock
# ExperimentalAutoDetectBinPacking: false
# PackConstructorInitializers: BinPack
ConstructorInitializerAllOnOneLineOrOnePerLine: true
# AllowAllConstructorInitializersOnNextLine: true
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
@@ -107,61 +82,34 @@ Cpp11BracedListStyle: false
# - BOOST_FOREACH
# IfMacros:
# - KJ_IF_MAYBE
# IncludeBlocks: Preserve
# IncludeBlocks: Preserve
IncludeCategories:
- Regex: ^".*"$
Priority: 1
- Regex: ^<.*\.h>$
Priority: 2
- Regex: ^<.*>$
Priority: 3
# IncludeIsMainRegex: (Test)?$
# IncludeIsMainSourceRegex: ""
- Regex: '".*"'
Priority: 1
- Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
# IncludeIsMainRegex: '(Test)?$'
# IncludeIsMainSourceRegex: ''
# IndentAccessModifiers: false
# IndentCaseBlocks: false
IndentCaseLabels: true
# IndentExternBlock: AfterExternBlock
# IndentCaseBlocks: false
# IndentGotoLabels: true
# IndentPPDirectives: None
# IndentRequiresClause: true
IndentWidth: 4
# IndentExternBlock: AfterExternBlock
# IndentRequires: false
IndentWidth: 4
# IndentWrappedFunctionNames: false
InsertBraces: true
# InsertNewlineAtEOF: false
# InsertTrailingCommas: None
# IntegerLiteralSeparator:
# Binary: 0
# BinaryMinDigits: 0
# Decimal: 0
# DecimalMinDigits: 0
# Hex: 0
# HexMinDigits: 0
JavaImportGroups:
- org.godotengine
- android
- androidx
- com.android
- com.google
- java
- javax
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
# KeepEmptyLinesAtEOF: false
KeepEmptyLinesAtTheStartOfBlocks: false
# LambdaBodyIndentation: Signature
# Language: Cpp
# LineEnding: DeriveLF
# MacroBlockBegin: ""
# MacroBlockEnd: ""
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# MaxEmptyLinesToKeep: 1
# NamespaceIndentation: None
# ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
# ObjCBreakBeforeNestedBlockParam: true
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
# PPIndentWidth: -1
PackConstructorInitializers: NextLine
# PenaltyBreakAssignment: 2
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
@@ -170,71 +118,82 @@ PackConstructorInitializers: NextLine
# PenaltyBreakString: 1000
# PenaltyBreakTemplateDeclaration: 10
# PenaltyExcessCharacter: 1000000
# PenaltyIndentedWhitespace: 0
# PenaltyReturnTypeOnItsOwnLine: 60
# PenaltyIndentedWhitespace: 0
# PointerAlignment: Right
# QualifierAlignment: Leave
# PPIndentWidth: -1
# ReferenceAlignment: Pointer
# ReflowComments: true
# ReflowComments: true
# RemoveBracesLLVM: false
# RemoveParentheses: Leave
RemoveSemicolon: true
# RequiresClausePosition: OwnLine
# RequiresExpressionIndentation: OuterScope
# SeparateDefinitionBlocks: Leave
# ShortNamespaceLines: 1
# SortIncludes: CaseSensitive
# SortIncludes: CaseSensitive
# SortJavaStaticImport: Before
# SortUsingDeclarations: LexicographicNumeric
# SortUsingDeclarations: true
# SpaceAfterCStyleCast: false
# SpaceAfterLogicalNot: false
# SpaceAfterTemplateKeyword: true
# SpaceAroundPointerQualifiers: Default
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeCaseColon: false
# SpaceBeforeCpp11BracedList: false
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# SpaceBeforeJsonColon: false
# SpaceBeforeParens: ControlStatements
# SpaceBeforeParensOptions:
# AfterControlStatements: true
# AfterForeachMacros: true
# AfterFunctionDeclarationName: false
# AfterFunctionDefinitionName: false
# AfterIfMacros: true
# AfterFunctionDeclarationName: false
# AfterIfMacros: true
# AfterOverloadedOperator: false
# AfterRequiresInClause: false
# AfterRequiresInExpression: false
# BeforeNonEmptyParentheses: false
# SpaceAroundPointerQualifiers: Default
# SpaceBeforeRangeBasedForLoopColon: true
# SpaceBeforeSquareBrackets: false
# SpaceInEmptyBlock: false
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: Never
# 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 # We want a minimum of 1 for comments, but allow 0 for disabled code.
Maximum: -1
# SpacesInParens: Never
# SpacesInParensOptions:
# InConditionalStatements: false
# InCStyleCasts: false
# InEmptyParentheses: false
# Other: false
Minimum: 0
Maximum: -1
# SpacesInParentheses: false
# SpacesInSquareBrackets: false
Standard: c++20
# SpaceBeforeSquareBrackets: false
# BitFieldColonSpacing: Both
# StatementAttributeLikeMacros:
# - Q_EMIT
# StatementMacros:
# - Q_UNUSED
# - QT_REQUIRE_VERSION
TabWidth: 4
UseTab: Always
# VerilogBreakBetweenInstancePorts: true
TabWidth: 4
# UseCRLF: false
UseTab: Always
# WhitespaceSensitiveMacros:
# - BOOST_PP_STRINGIZE
# - CF_SWIFT_NAME
# - NS_SWIFT_NAME
# - PP_STRINGIZE
# - STRINGIZE
# - PP_STRINGIZE
# - BOOST_PP_STRINGIZE
# - NS_SWIFT_NAME
# - CF_SWIFT_NAME
---
### C++ specific config ###
Language: Cpp
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']
...

View File

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

View File

@@ -1,11 +0,0 @@
# This file contains a list of Git commit hashes that should be hidden from the
# regular Git history. Typically, this includes commits involving mass auto-formatting
# or other normalizations. Commit hashes *must* use the full 40-character notation.
# To apply the ignore list in your local Git client, you must run:
#
# git config blame.ignoreRevsFile .git-blame-ignore-revs
#
# This file is automatically used by GitHub.com's blame view.
# Style: Replace header guards with `#pragma once`
7056c996dd43ae1aa466c94d95cc2fe63853d8a9

8
.gitattributes vendored
View File

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

View File

@@ -9,7 +9,7 @@ body:
- Write a descriptive issue title above.
- The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them.
- Search [open](https://github.com/godotengine/godot-cpp/issues) and [closed](https://github.com/godotengine/godot-cpp/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate.
- Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/latest/about/release_policy.html).
- Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/stable/about/release_policy.html).
- type: input
attributes:

View File

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

View File

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

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

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

View File

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

View File

@@ -1,186 +0,0 @@
name: Continuous integration
on:
workflow_call:
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
# Used to select the version of Godot to run the tests with.
GODOT_TEST_VERSION: master
# Use UTF-8 on Linux.
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
concurrency:
group: ci-cmake-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-cmake:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
env:
EM_VERSION: 4.0.11
config-flags:
-DCMAKE_C_COMPILER_LAUNCHER=sccache
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
-DGODOTCPP_ENABLE_TESTING=ON
-DGODOTCPP_BUILD_PROFILE="test/build_profile.json"
SCCACHE_GHA_ENABLED: "true"
strategy:
fail-fast: false
matrix:
include:
- name: 🐧 Linux (GCC, Makefiles)
os: ubuntu-22.04
platform: linux
config-flags: -DCMAKE_BUILD_TYPE=Release
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.linux.template_release.x86_64.a
run-tests: true
- name: 🏁 Windows (x86_64, MSVC)
os: windows-2022
platform: windows
compiler: msvc
build-flags: --config Release
artifact-name: godot-cpp-windows-msvc2019-x86_64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.windows.template_release.x86_64.lib
run-tests: false
- name: 🏁 Windows (x86_64, MinGW, Ninja)
os: windows-2022
platform: windows
compiler: mingw
config-flags:
-GNinja -DCMAKE_BUILD_TYPE=Release
-DCMAKE_CXX_COMPILER=cc -DCMAKE_CXX_COMPILER=c++
artifact-name: godot-cpp-linux-mingw-x86_64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.windows.template_release.x86_64.a
run-tests: false
- name: 🍎 macOS (universal, Makefiles)
os: macos-latest
platform: macos
config-flags: -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
artifact-name: godot-cpp-macos-universal-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.macos.template_release.universal.a
run-tests: false
- name: 🤖 Android (arm64, Ninja)
os: ubuntu-22.04
platform: android
config-flags:
-G Ninja -DCMAKE_BUILD_TYPE=Release
--toolchain ${ANDROID_HOME}/ndk/28.1.13356709/build/cmake/android.toolchain.cmake
-DANDROID_PLATFORM=24 -DANDROID_ABI=arm64-v8a
artifact-name: godot-cpp-android-arm64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.android.template_release.arm64.a
flags: arch=arm64
run-tests: false
- name: 🍏 iOS (arm64, XCode)
os: macos-latest
platform: ios
config-flags:
-G Xcode
--toolchain cmake/ios.toolchain.cmake
-DPLATFORM=OS64
build-flags: --config Release
artifact-name: godot-cpp-ios-arm64-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.ios.template_release.arm64.a
flags: arch=arm64
run-tests: false
- name: 🌐 Web (wasm32, Ninja)
os: ubuntu-22.04
platform: web
config-flags:
-G Ninja -DCMAKE_BUILD_TYPE=Release
--toolchain ${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
artifact-name: godot-cpp-web-wasm32-release.cmake
artifact-path: cmake-build/bin/libgodot-cpp.web.template_release.wasm32.a
run-tests: false
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Setup godot-cpp
uses: ./.github/actions/setup-godot-cpp
with:
platform: ${{ matrix.platform }}
windows-compiler: ${{ matrix.compiler }}
buildtool: cmake
- name: Configure godot-cpp-test with template_debug
run: >
cmake --log-level=VERBOSE -S . -B cmake-build ${{ env.config-flags }} ${{ matrix.config-flags }}
- name: Build godot-cpp-test (template_debug)
run: >
cmake --build cmake-build --verbose --target godot-cpp-test ${{ matrix.build-flags }}
- name: Configure godot-cpp-test with template_release
run: >
cmake --fresh --log-level=VERBOSE -S . -B cmake-build
-DGODOTCPP_TARGET=template_release ${{ env.config-flags }} ${{ matrix.config-flags }}
- name: Build godot-cpp-test (template_release)
run: >
cmake --build cmake-build --verbose --target godot-cpp-test ${{ matrix.build-flags }}
- name: Run sccache stat for check
shell: bash
run: ${SCCACHE_PATH} --show-stats
- name: Download latest Godot artifacts
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
with:
repo: godotengine/godot
branch: master
event: push
workflow: linux_builds.yml
workflow_conclusion: success
name: linux-editor-mono
search_artifacts: true
check_artifacts: true
ensure_latest: true
path: godot-artifacts
- name: Prepare Godot artifacts for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
run: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
- name: Download requested Godot version for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION != 'master'
run: |
wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
unzip -a Godot.zip
chmod +x "Godot_v${GODOT_TEST_VERSION}_linux.x86_64"
echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
- name: Run tests
if: matrix.run-tests
run: |
$GODOT --headless --version
cd test
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
(cd project && (timeout 30 $GODOT --import --headless >/dev/null 2>&1 || true))
./run-tests.sh
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact-name }}
path: ${{ matrix.artifact-path }}
if-no-files-found: error

View File

@@ -1,24 +1,16 @@
name: Continuous integration
on:
workflow_call:
on: [push, pull_request]
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
# Used to select the version of Godot to run the tests with.
GODOT_TEST_VERSION: master
# Use UTF-8 on Linux.
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
# Use UTF-8 on Windows.
PYTHONIOENCODING: utf8
concurrency:
group: ci-scons-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
cancel-in-progress: true
jobs:
build-scons:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
@@ -26,15 +18,24 @@ jobs:
matrix:
include:
- name: 🐧 Linux (GCC)
os: ubuntu-22.04
os: ubuntu-20.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
run-tests: true
cache-name: linux-x86_64
- name: 🐧 Linux (GCC, Double Precision)
os: ubuntu-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-2022
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
@@ -42,7 +43,7 @@ jobs:
cache-name: windows-x86_64-msvc
- name: 🏁 Windows (x86_64, MinGW)
os: windows-2022
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
@@ -51,7 +52,7 @@ jobs:
cache-name: windows-x86_64-mingw
- name: 🍎 macOS (universal)
os: macos-latest
os: macos-11
platform: macos
artifact-name: godot-cpp-macos-universal-release
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
@@ -60,7 +61,7 @@ jobs:
cache-name: macos-universal
- name: 🤖 Android (arm64)
os: ubuntu-22.04
os: ubuntu-20.04
platform: android
artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
@@ -69,7 +70,7 @@ jobs:
cache-name: android-arm64
- name: 🍏 iOS (arm64)
os: macos-latest
os: macos-11
platform: ios
artifact-name: godot-cpp-ios-arm64-release
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
@@ -78,7 +79,7 @@ jobs:
cache-name: ios-arm64
- name: 🌐 Web (wasm32)
os: ubuntu-22.04
os: ubuntu-20.04
platform: web
artifact-name: godot-cpp-web-wasm32-release
artifact-path: bin/libgodot-cpp.web.template_release.wasm32.a
@@ -87,7 +88,8 @@ jobs:
env:
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
EM_VERSION: 4.0.11
EM_VERSION: 3.1.39
EM_CACHE_FOLDER: "emsdk-cache"
steps:
- name: Checkout
@@ -95,18 +97,40 @@ jobs:
with:
submodules: recursive
- name: Restore Godot build cache
uses: ./.github/actions/godot-cache-restore
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Setup godot-cpp
uses: ./.github/actions/setup-godot-cpp
- name: Set up Python (for SCons)
uses: actions/setup-python@v5
with:
platform: ${{ matrix.platform }}
windows-compiler: ${{ contains(matrix.flags, 'use_mingw=yes') && 'mingw' || 'msvc' }}
buildtool: scons
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@v14
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
- name: Setup MinGW for Windows/MinGW build
if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }}
uses: egor-tensin/setup-mingw@v2
with:
version: 12.2.0
- name: Install scons
run: |
python -m pip install scons==4.0.0
- name: Generate godot-cpp sources only
run: |
@@ -127,15 +151,9 @@ jobs:
cd test
scons platform=${{ matrix.platform }} verbose=yes target=template_release ${{ matrix.flags }}
- name: Save Godot build cache
uses: ./.github/actions/godot-cache-save
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Download latest Godot artifacts
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
if: ${{ matrix.run-tests }}
with:
repo: godotengine/godot
branch: master
@@ -148,32 +166,86 @@ jobs:
ensure_latest: true
path: godot-artifacts
- name: Prepare Godot artifacts for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
- name: Run tests
if: ${{ matrix.run-tests }}
run: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
- name: Download requested Godot version for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION != 'master'
run: |
wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
unzip -a Godot.zip
chmod +x "Godot_v${GODOT_TEST_VERSION}_linux.x86_64"
echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
- name: Run tests
if: matrix.run-tests
run: |
$GODOT --headless --version
./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 30 $GODOT --import --headless >/dev/null 2>&1 || true))
./run-tests.sh
(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@v4
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 cmake
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release .
make -j $(nproc) VERBOSE=1
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." .
make -j $(nproc) VERBOSE=1
linux-cmake-ninja:
name: 🐧 Build (Linux, GCC, CMake Ninja)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config cmake ninja-build
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release -GNinja .
cmake --build . -j $(nproc) --verbose
- 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@v4
with:
submodules: recursive
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 16 2019" .
cmake --build . --verbose
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -G"Visual Studio 16 2019" .
cmake --build . --verbose

View File

@@ -1,66 +0,0 @@
name: 🔗 GHA
on: [push, pull_request, merge_group]
concurrency:
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
cancel-in-progress: true
jobs:
# First stage: Only static checks, fast and prevent expensive builds from running.
static-checks:
name: 📊 Static Checks
if: '!vars.DISABLE_GODOT_CI'
uses: ./.github/workflows/static_checks.yml
# Second stage: Review code changes
changes:
name: Analyze Changes
needs: static-checks
runs-on: ubuntu-latest
outputs:
sources: ${{ steps.filter.outputs.sources_any_changed }}
scons: ${{ steps.filter.outputs.scons_any_changed }}
cmake: ${{ steps.filter.outputs.cmake_any_changed }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: tj-actions/changed-files@v45
id: filter
with:
files_yaml: |
sources:
- '.github/workflows/*.yml'
- '**/*.py'
- '**/*.cpp'
- '**/*.hpp'
- '**/*.h'
- '**/*.inc'
- 'test/build_profile.json'
- 'gdextension/extension_api.json'
scons:
- '**/SConstruct'
- '**/SCsub'
cmake:
- '**/CMakeLists.txt'
- '**/*.cmake'
- name: echo sources changed
run: |
echo sources ${{ steps.filter.outputs.sources_any_modified }}
echo scons ${{ steps.filter.outputs.scons_any_modified }}
echo cmake ${{ steps.filter.outputs.cmake_any_modified }}
# Third stage: Run all the builds and some of the tests.
ci-scons:
name: 🛠️ SCons CI
needs: changes
if: ${{ needs.changes.outputs.scons == 'true' || needs.changes.outputs.sources == 'true' }}
uses: ./.github/workflows/ci-scons.yml
ci-cmake:
name: 🛠️ CMake CI
needs: changes
if: ${{ needs.changes.outputs.cmake == 'true' || needs.changes.outputs.sources == 'true' }}
uses: ./.github/workflows/ci-cmake.yml

View File

@@ -1,30 +1,54 @@
name: 📊 Static Checks
on:
workflow_call:
on: [push, pull_request]
concurrency:
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
cancel-in-progress: true
jobs:
static-checks:
name: Format (clang-format, ruff format, file format)
runs-on: ubuntu-22.04
name: Format (clang-format, black format, file format)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v45
# 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: Style checks via pre-commit
uses: pre-commit/action@v3.0.1
with:
extra_args: --verbose --hook-stage manual --files ${{ steps.changed-files.outputs.all_changed_files }}
- name: Install dependencies
run: |
sudo apt-get install -qq dos2unix recode clang-format-15 libxml2-utils python3-pip moreutils
sudo update-alternatives --remove-all clang-format || true
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100
sudo pip3 install black==22.3.0 pygments pytest==7.1.2 mypy==0.971
- name: Check generated files consistency
run:
python misc/scripts/check_get_file_list.py
- name: File formatting checks (file_format.sh)
run: |
bash ./misc/scripts/file_format.sh
- name: Header guards formatting checks (header_guards.sh)
run: |
bash ./misc/scripts/header_guards.sh
- name: Python style checks via black (black_format.sh)
run: |
bash ./misc/scripts/black_format.sh
- name: Python scripts static analysis (mypy_check.sh)
run: |
bash ./misc/scripts/mypy_check.sh
- name: Bindings generation checks (ensures get_file_list returns all generated files)
run: |
python ./misc/scripts/check_get_file_list.py
- name: Style checks via clang-format (clang_format.sh)
run: |
bash ./misc/scripts/clang_format.sh

9
.gitignore vendored
View File

@@ -8,7 +8,7 @@
include/gen
src/gen
# Build configuration.
# Build configuarion.
/custom.py
# Misc
@@ -195,10 +195,3 @@ compile_commands.json
# Python development
.venv
venv
# Clion Configuration
.idea/
cmake-build*/
# CMake related
CMakeUserPresets.json

View File

@@ -1,74 +0,0 @@
default_language_version:
python: python3
exclude: |
(?x)^(
gdextension/extension_api\.json|
gdextension/gdextension_interface\.h
)$
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v20.1.0
hooks:
- id: clang-format
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.4
hooks:
- id: ruff
args: [--fix]
files: (\.py|SConstruct)$
types_or: [text]
- id: ruff-format
files: (\.py|SConstruct)$
types_or: [text]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1 # Latest version that supports Python 3.8
hooks:
- id: mypy
files: \.py$
types_or: [text]
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
additional_dependencies: [tomli]
- repo: https://github.com/BlankSpruce/gersemi
rev: 0.19.2
hooks:
- id: gersemi
args: ["-i", "--no-warn-about-unknown-commands", "-l", "120"]
- repo: local
hooks:
- id: copyright-headers
name: copyright-headers
language: python
entry: python misc/scripts/copyright_headers.py
files: \.(c|h)pp$
exclude: ^test/
- id: header-guards
name: header-guards
language: python
entry: python misc/scripts/header_guards.py
files: \.hpp$
exclude: ^test/
- id: file-format
name: file-format
language: python
entry: python misc/scripts/file_format.py
types_or: [text]
- id: check-get-file-list
name: check-get-file-list
language: python
entry: python misc/scripts/check_get_file_list.py
pass_filenames: false
always_run: true
stages: [manual]

View File

@@ -1,75 +1,216 @@
cmake_minimum_required(VERSION 3.10...3.17)
# cmake arguments
# CMAKE_BUILD_TYPE: Compilation target (Debug or Release defaults to Debug)
#
# godot-cpp cmake arguments
# GODOT_GDEXTENSION_DIR: Path to the directory containing GDExtension interface header and API JSON file
# GODOT_CPP_SYSTEM_HEADERS Mark the header files as SYSTEM. This may be useful to supress warnings in projects including this one.
# GODOT_CPP_WARNING_AS_ERROR Treat any warnings as errors
# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)
# FLOAT_PRECISION: Floating-point precision level ("single", "double")
#
# Android cmake arguments
# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake)
# ANDROID_NDK: The path to the android ndk root folder
# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9)
# ANDROID_PLATFORM: The android platform version (android-23)
# More info here: https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html
#
# Examples
#
# Builds a debug version:
# cmake .
# cmake --build .
#
# Builds a release version with clang
# CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .
# cmake --build .
#
# Builds an android armeabi-v7a debug version:
# cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \
# -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug .
# cmake --build .
#
# Protip
# Generate the buildfiles in a sub directory to not clutter the root directory with build files:
# mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
#
# Todo
# Test build for Windows, Mac and mingw.
#[=======================================================================[.rst:
cmake_minimum_required(VERSION 3.13)
project(godot-cpp LANGUAGES CXX)
CMake Version requirements
--------------------------
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
option(GODOT_CPP_SYSTEM_HEADERS "Expose headers as SYSTEM." ON)
option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
To enable use of the emscripten emsdk hack for pseudo shared library support
without polluting options for consumers we need to use the
CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE which was introduced in version 3.17
# Add path to modules
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
For more information check cmake/emsdkHack.cmake
# 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>" )
SCons Compatibility
-------------------
There is an understandable conflict between build systems as they define
similar concepts in different ways. When there isn't a 1:1 relationship,
compromises need to be made to resolve those differences.
As we are attempting to maintain feature parity, and ease of maintenance, these
CMake scripts are built to resemble the SCons build system wherever possible.
Where they are not, we will attempt to document common difference in
the docs (https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
and platform specific differences in their respective
cmake/<platform>.cmake file.
The file structure and file content are made to match, if not in content then
in spirit. The closer the two build systems look the easier they will be to
maintain.
Where the SCons additional scripts in the tools directory, The CMake scripts
are in the cmake directory.
For example; the tools/godotcpp.py is matched by the cmake/godotcpp.cmake file
.. highlight:: python
cpp_tool = Tool("godotcpp", toolpath=["tools"])
cpp_tool.options(opts, env)
The CMake equivalent is below.
]=======================================================================]
include(cmake/godotcpp.cmake)
godotcpp_options()
#[[ People are compiling godot by itself and expecting template_debug
Replace this with PROJECT_IS_TOP_LEVEL, <PROJECT-NAME>_IS_TOP_LEVEL when minimum reaches 3.21
]]
if(NOT PROJECT_NAME)
set(GODOTCPP_IS_TOP_LEVEL ON)
# Default build type is Debug in the SConstruct
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE Debug)
endif()
# Define our project.
project(
godot-cpp
VERSION 4.4
DESCRIPTION "C++ bindings for the Godot Engine's GDExtensions API."
HOMEPAGE_URL "https://github.com/godotengine/godot-cpp"
LANGUAGES CXX
if(NOT DEFINED BITS)
set(BITS 32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(BITS 64)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
endif()
# Input from user for GDExtension interface header and the API JSON file
set(GODOT_GDEXTENSION_DIR "gdextension" CACHE STRING "")
set(GODOT_CUSTOM_API_FILE "" CACHE STRING "")
set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json")
if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override.
set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}")
endif()
set(FLOAT_PRECISION "single" CACHE STRING "")
if ("${FLOAT_PRECISION}" STREQUAL "double")
add_definitions(-DREAL_T_IS_DOUBLE)
endif()
set(GODOT_COMPILE_FLAGS )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy
STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
endif(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-DNOMINMAX)
else() # GCC/Clang
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
endif(CMAKE_BUILD_TYPE MATCHES Debug)
endif()
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time (GH-80513).
option(GODOT_DISABLE_EXCEPTIONS OFF "Force disabling exception handling code")
if (GODOT_DISABLE_EXCEPTIONS)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions")
endif()
else()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc")
endif()
endif()
# Generate source from the bindings file
find_package(Python3 3.4 REQUIRED) # pathlib should be present
if(GENERATE_TEMPLATE_GET_NODE)
set(GENERATE_BINDING_PARAMETERS "True")
else()
set(GENERATE_BINDING_PARAMETERS "False")
endif()
execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
)
compiler_detection()
godotcpp_generate()
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"
)
# Conditionally enable the godot-cpp.test.<target> integration testing targets
if(GODOTCPP_ENABLE_TESTING)
add_subdirectory(test)
# 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)
target_compile_features(${PROJECT_NAME}
PRIVATE
cxx_std_17
)
target_compile_definitions(${PROJECT_NAME} PUBLIC
$<$<CONFIG:Debug>:
DEBUG_ENABLED
DEBUG_METHODS_ENABLED
>
$<${compiler_is_msvc}:
TYPED_METHOD_BIND
>
)
target_link_options(${PROJECT_NAME} PRIVATE
$<$<NOT:${compiler_is_msvc}>:
-static-libgcc
-static-libstdc++
-Wl,-R,'$$ORIGIN'
>
)
# Optionally mark headers as SYSTEM
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE "")
if (GODOT_CPP_SYSTEM_HEADERS)
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif ()
target_include_directories(${PROJECT_NAME} ${GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
include
${CMAKE_CURRENT_BINARY_DIR}/gen/include
${GODOT_GDEXTENSION_DIR}
)
# Add the compile flags
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
# Create the correct name (godot.os.build_type.system_bits)
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
if(ANDROID)
# Added the android abi after system name
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
# Android does not have the bits at the end if you look at the main godot repo build
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
else()
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
endif()
#[[ If this is the top level CMakeLists.txt, Generators which honor the
USE_FOLDERS flag will organize godot-cpp targets under a subfolder named
'godot-cpp'. This is enable by default from CMake version 3.26 ]]
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
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,18 +1,14 @@
# godot-cpp
> [!WARNING]
> **Warning**
>
> This repository's `master` branch is only usable with
> [GDExtension](https://godotengine.org/article/introducing-gd-extensions)
> from Godot's `master` branch.
>
> For users of stable branches, switch to the branch matching your target Godot version:
> - [`4.5`](https://github.com/godotengine/godot-cpp/tree/4.5)
> - [`4.4`](https://github.com/godotengine/godot-cpp/tree/4.4)
> - [`4.3`](https://github.com/godotengine/godot-cpp/tree/4.3)
> - [`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)
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
>
> Or check out the Git tag matching your Godot version (e.g. `godot-4.1.1-stable`).
>
@@ -25,7 +21,7 @@ This repository contains the *C++ bindings* for the [**Godot Engine**](https://
- [**Compatibility**](#compatibility)
- [**Contributing**](#contributing)
- [**Getting started**](#getting-started)
- [**Examples and templates**](#examples-and-templates)
- [**Included example**](#included-example)
## Versioning
@@ -52,22 +48,32 @@ Godot version.**
## Compatibility
GDExtensions targeting an earlier version of Godot should work in later minor versions,
but not vice-versa. For example, a GDExtension targeting Godot 4.2 should work just fine
in Godot 4.3, but one targeting Godot 4.3 won't work in Godot 4.2.
**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.
There is one exception to this: extensions targeting Godot 4.0 will _not_ work with
Godot 4.1 and later.
See [Updating your GDExtension for 4.1](https://docs.godotengine.org/en/latest/tutorials/migrating/upgrading_to_godot_4.1.html#updating-your-gdextension-for-godot-4-1).
This applies to both the GDExtension interface header, the API JSON, and this
first-party `godot-cpp` extension.
Some compatibility breakage is to be expected as GDExtension and `godot-cpp`
get more used, documented, and critical issues get resolved. See the
[Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension)
and the [godot-cpp issue tracker](https://github.com/godotengine/godot-cpp/issues)
for a list of known issues, and be sure to provide feedback on issues and PRs
which affect your use of this extension.
## Contributing
We greatly appreciate help in maintaining and extending this project. If you
wish to help out, please visit the [godot-cpp section of the Contributing docs](https://contributing.godotengine.org/en/latest/other/godot-cpp.html).
wish to help out, ensure you have an account on GitHub and create a "fork" of
this repository. See [Pull request workflow](https://docs.godotengine.org/en/stable/community/contributing/pr_workflow.html)
for instructions.
Please install clang-format and copy the files in `misc/hooks` into `.git/hooks`
so formatting is done before your changes are submitted.
## Getting started
You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/engine_details/development/compiling/index.html).
You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/index.html#building-for-target-platforms).
Getting started with GDExtensions is a bit similar to what it was for 3.x but also a bit different.
@@ -137,4 +143,4 @@ See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template)
generic reusable template.
Or checkout the code for the [Summator example](https://github.com/paddy-exe/GDExtensionSummator)
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/gdextension_cpp_example.html).
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/gdextension/gdextension_cpp_example.html).

View File

@@ -1,18 +1,18 @@
#!/usr/bin/env python
import os
import platform
import sys
# Add godot-cpp folder to sys.path, so that we can import local modules.
sys.path.append(Dir(".").srcnode().abspath)
import subprocess
from binding_generator import scons_generate_bindings, scons_emit_files
EnsureSConsVersion(4, 0)
EnsurePythonVersion(3, 8)
try:
Import("env")
except Exception:
except:
# Default tools with no platform defaults to gnu toolchain.
# We apply platform specific toolchains via our custom tools.
env = Environment(tools=["default"], PLATFORM="")
@@ -23,7 +23,7 @@ env.PrependENVPath("PATH", os.getenv("PATH"))
customs = ["custom.py"]
try:
customs += Import("customs")
except Exception:
except:
pass
profile = ARGUMENTS.get("profile", "")
if profile:
@@ -32,7 +32,7 @@ if profile:
elif os.path.isfile(profile + ".py"):
customs.append(profile + ".py")
opts = Variables(customs, ARGUMENTS)
cpp_tool = Tool("godotcpp", toolpath=[Dir("tools").srcnode().abspath])
cpp_tool = Tool("godotcpp", toolpath=["tools"])
cpp_tool.options(opts, env)
opts.Update(env)

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,176 +0,0 @@
#[=======================================================================[.rst:
GodotCPPModule.cmake
---------------------
This file contains functions and tests which may be needed by consumers.
* Generate Trimmed API
* Generate File List
* Generate Bindings
If you want to use these functions in your project extend the CMAKE_MODULE_PATH
by adding these two lines into your CMakeLists.txt after the inclusion
godot-cpp
.. highlight:: cmake
list(APPEND CMAKE_MODULE_PATH "${godot-cpp_SOURCE_DIR}/cmake")
include( GodotCPPModule )
]=======================================================================]
find_package(Python3 3.4 REQUIRED) # pathlib should be present
#[[ Generate Trimmed API
The build_profile.py has a __main__ and is used as a tool
Its usage is listed as:
$ python build_profile.py BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]
]]
function(build_profile_generate_trimmed_api BUILD_PROFILE INPUT_JSON OUTPUT_JSON)
execute_process(
COMMAND
"${Python3_EXECUTABLE}" "${godot-cpp_SOURCE_DIR}/build_profile.py" "${BUILD_PROFILE}" "${INPUT_JSON}"
"${OUTPUT_JSON}"
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
)
endfunction()
#[[ Generate File List
Use the binding_generator.py Python script to determine the list of files that
will be passed to the code generator using extension_api.json.
NOTE: This happens for every configure.]]
function(binding_generator_get_file_list OUT_VAR_NAME API_FILEPATH OUTPUT_DIR)
# This code snippet will be squashed into a single line
# The two strings make this a list, in CMake lists are semicolon delimited strings.
set(PYTHON_SCRIPT
"from binding_generator import print_file_list"
"print_file_list( api_filepath='${API_FILEPATH}',
output_dir='${OUTPUT_DIR}',
headers=True,
sources=True)"
)
message(DEBUG "Python:\n${PYTHON_SCRIPT}")
# Strip newlines and whitespace to make it a one-liner.
string(REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}")
execute_process(
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Debug output
message(DEBUG "FileList-Begin")
foreach(PATH ${GENERATED_FILES_LIST})
message(DEBUG ${PATH})
endforeach()
# Error out if the file list generator returned no files.
list(LENGTH GENERATED_FILES_LIST LIST_LENGTH)
if(NOT LIST_LENGTH GREATER 0)
message(FATAL_ERROR "File List Generation Failed")
endif()
message(STATUS "There are ${LIST_LENGTH} Files to generate")
set(${OUT_VAR_NAME} ${GENERATED_FILES_LIST} PARENT_SCOPE)
endfunction()
#[[ Generate Bindings
Using the generated file list, use the binding_generator.py to generate the
godot-cpp bindings. This will run at build time only if there are files
missing. ]]
function(
binding_generator_generate_bindings
API_FILE
USE_TEMPLATE_GET_NODE
BITS
PRECISION
OUTPUT_DIR
)
# This code snippet will be squashed into a single line
set(PYTHON_SCRIPT
"from binding_generator import generate_bindings"
"generate_bindings(
api_filepath='${API_FILE}',
use_template_get_node='${USE_TEMPLATE_GET_NODE}',
bits='${BITS}',
precision='${PRECISION}',
output_dir='${OUTPUT_DIR}')"
)
message(DEBUG "Python:\n${PYTHON_SCRIPT}")
# Strip newlines and whitespace to make it a one-liner.
string(REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}")
add_custom_command(
OUTPUT ${GENERATED_FILES_LIST}
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
VERBATIM
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
MAIN_DEPENDENCY ${GODOTCPP_GDEXTENSION_API_FILE}
DEPENDS ${godot-cpp_SOURCE_DIR}/binding_generator.py
COMMENT "Generating bindings"
)
add_custom_target(generate_bindings DEPENDS ${GENERATED_FILES_LIST})
set_target_properties(generate_bindings PROPERTIES FOLDER "godot-cpp")
endfunction()
#[[ Generate doc_data.cpp
The documentation displayed in the Godot editor is compiled into the extension.
It takes a list of XML source files, and transforms them into a cpp file that
is added to the sources list.]]
function(generate_doc_source OUTPUT_PATH SOURCES)
# Transform SOURCES CMake LIST
# quote each path with ''
# join with , to transform into a python list minus the surrounding []
set(PYTHON_LIST "${SOURCES}")
list(TRANSFORM PYTHON_LIST REPLACE "(.*\.xml)" "'\\1'")
list(JOIN PYTHON_LIST "," PYTHON_LIST)
get_filename_component(OUTPUT_DIR "${OUTPUT_PATH}" DIRECTORY)
file(MAKE_DIRECTORY ${OUTPUT_DIR})
# Python one-liner to run our command
# lists in CMake are just strings delimited by ';', so this works.
set(PYTHON_SCRIPT
"from doc_source_generator import generate_doc_source"
"generate_doc_source( '${OUTPUT_PATH}', [${PYTHON_LIST}] )"
)
add_custom_command(
OUTPUT "${OUTPUT_PATH}"
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
VERBATIM
WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
DEPENDS #
"${godot-cpp_SOURCE_DIR}/doc_source_generator.py"
"${SOURCES}"
COMMENT "Generating: ${OUTPUT_PATH}"
)
add_custom_target(generate_doc_source DEPENDS "${OUTPUT_PATH}")
set_target_properties(generate_doc_source PROPERTIES FOLDER "godot-cpp")
endfunction()
#[[ target_doc_sources
A simpler interface to add xml files as doc source to a output target.
TARGET: The gdexension library target
SOURCES: a list of xml files to use for source generation and inclusion.]]
function(target_doc_sources TARGET SOURCES)
# set the generated file name
set(DOC_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen/doc_source.cpp")
# Create the file generation target, this won't be triggered unless a target
# that depends on DOC_SOURCE_FILE is built
generate_doc_source( "${DOC_SOURCE_FILE}" ${SOURCES} )
# Add DOC_SOURCE_FILE as a dependency to TARGET
target_sources(${TARGET} PRIVATE "${DOC_SOURCE_FILE}")
# Without adding this dependency to the doc_source_generator, XCode will complain.
add_dependencies(${TARGET} generate_doc_source)
endfunction()

View File

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

View File

@@ -1,49 +0,0 @@
#[=======================================================================[.rst:
Android
-------
This file contains functions for options and configuration for targeting the
Android platform
Configuration of the Android toolchain is done using toolchain files,
CMakePresets, or variables on the command line.
The `Android SDK`_ provides toolchain files to help with configuration.
CMake has its own `built-in support`_ for cross compiling to the
Android platforms.
.. warning::
Android does not support or test the CMake built-in workflow, recommend
using their toolchain file.
.. _Android SDK:https://developer.android.com/ndk/guides/cmake
.. _built-in support:https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android
There is further information and examples in the docs: https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html
]=======================================================================]
#[============================[ Android Options ]============================]
function(android_options)
#[[ Options from SCons
The options below are managed by CMake toolchain files, the docs have more information:
https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html
android_api_level : Target Android API level.
Default = 24
ANDROID_HOME : Path to your Android SDK installation.
Default = os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT")
]]
endfunction()
#[===========================[ Target Generation ]===========================]
function(android_generate)
target_compile_definitions(godot-cpp PUBLIC ANDROID_ENABLED UNIX_ENABLED)
common_compiler_flags()
endfunction()

View File

@@ -1,192 +0,0 @@
#[=======================================================================[.rst:
Common Compiler Flags
---------------------
This file contains host platform toolchain and target platform agnostic
configuration. It includes flags like optimization levels, warnings, and
features. For target platform specific flags look to each of the
``cmake/<platform>.cmake`` files.
The default compile and link options CMake adds can be found in the
platform modules_. When a project is created it initializes its variables from
the ``CMAKE_*`` values. The cleanest way I have found to alter these defaults
is the use of the ``CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`` as demonstrated by
the emsdkHack.cmake to overcome the limitation on shared library creation.
So far the emsdkHack is the only modification to the defaults we have made.
.. _modules: https://github.com/Kitware/CMake/blob/master/Modules/Platform/
]=======================================================================]
#[[ Compiler Configuration, not to be confused with build targets ]]
set(DEBUG_SYMBOLS "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>")
#[[ Compiler Identification ]]
set(IS_CLANG "$<CXX_COMPILER_ID:Clang>")
set(IS_APPLECLANG "$<CXX_COMPILER_ID:AppleClang>")
set(IS_GNU "$<CXX_COMPILER_ID:GNU>")
set(IS_MSVC "$<CXX_COMPILER_ID:MSVC>")
set(NOT_MSVC "$<NOT:$<CXX_COMPILER_ID:MSVC>>")
set(LT_V8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>")
set(GE_V9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>")
set(GT_V11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>")
set(LT_V11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>")
set(GE_V12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>")
#[===========================[ compiler_detection ]===========================]
#[[ Check for clang-cl with MSVC frontend
The compiler is tested and set when the project command is called.
The variable CXX_COMPILER_FRONTEND_VARIANT was introduced in 3.14
The generator expression $<CXX_COMPILER_FRONTEND_VARIANT> wasn't introduced
until CMake 3.30 so we can't use it yet.
So to support clang downloaded from llvm.org which uses the MSVC frontend
by default, we need to test for it. ]]
function(compiler_detection)
if(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)
if(${CMAKE_CXX_COMPILER_FRONTEND_VARIANT} STREQUAL MSVC)
message(STATUS "Using clang-cl")
set(IS_CLANG "0" PARENT_SCOPE)
set(IS_MSVC "1" PARENT_SCOPE)
set(NOT_MSVC "0" PARENT_SCOPE)
endif()
endif()
endfunction()
#[=========================[ common_compiler_flags ]=========================]
#[[ This function assumes it is being called from within one of the platform
generate functions, with all the variables from lower scopes defined. ]]
function(common_compiler_flags)
# gersemi: off
# These compiler options reflect what is in godot/SConstruct.
target_compile_options(
godot-cpp
# The public flag tells CMake that the following options are transient,
# and will propagate to consumers.
PUBLIC
# Enabling Debug Symbols
$<${DEBUG_SYMBOLS}:
# Adding dwarf-4 explicitly makes stacktraces work with clang builds,
# otherwise addr2line doesn't understand them.
$<${NOT_MSVC}:
-gdwarf-4
$<IF:${IS_DEV_BUILD},-g3,-g2>
>
>
$<${IS_DEV_BUILD}:$<${NOT_MSVC}:-fno-omit-frame-pointer -O0>>
$<${HOT_RELOAD}:$<${IS_GNU}:-fno-gnu-unique>>
# MSVC only
$<${IS_MSVC}:
# /MP isn't valid for clang-cl with msvc frontend
$<$<CXX_COMPILER_ID:MSVC>:/MP${PROC_N}>
# Interpret source files as utf-8
/utf-8
>
# Warnings below, these do not need to propagate to consumers.
PRIVATE
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time.
$<${DISABLE_EXCEPTIONS}:$<${NOT_MSVC}:-fno-exceptions>>
$<${IS_MSVC}:
/W4 # Warning level 4 (informational) warnings that aren't off by default.
# Disable warnings which we don't plan to fix.
/wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
/wd4127 # C4127 (conditional expression is constant)
/wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89.
/wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
/wd4245
/wd4267
/wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid.
/wd4514 # C4514 (unreferenced inline function has been removed)
/wd4714 # C4714 (function marked as __forceinline not inlined)
/wd4820 # C4820 (padding added after construct)
>
# Clang and GNU common options
$<$<OR:${IS_CLANG},${IS_GNU}>:
-Wall
-Wctor-dtor-privacy
-Wextra
-Wno-unused-parameter
-Wnon-virtual-dtor
-Wwrite-strings
>
# Clang only
$<${IS_CLANG}:
-Wimplicit-fallthrough
-Wno-ordered-compare-function-pointers
>
# GNU only
$<${IS_GNU}:
-Walloc-zero
-Wduplicated-branches
-Wduplicated-cond
-Wno-misleading-indentation
-Wplacement-new=1
-Wshadow-local
-Wstringop-overflow=4
# Bogus warning fixed in 8+.
$<${LT_V8}:-Wno-strict-overflow>
$<${GE_V9}:-Wattribute-alias=2>
# Broke on MethodBind templates before GCC 11.
$<${GT_V11}:-Wlogical-op>
# Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it.
$<${LT_V11}:-Wno-type-limits>
# False positives in our error macros, see GH-58747.
$<${GE_V12}:-Wno-return-type>
>
)
target_compile_definitions(
godot-cpp
PUBLIC
GDEXTENSION
# features
$<${DEBUG_FEATURES}:DEBUG_ENABLED>
$<${IS_DEV_BUILD}:DEV_ENABLED>
$<${HOT_RELOAD}:HOT_RELOAD_ENABLED>
$<$<STREQUAL:${GODOTCPP_PRECISION},double>:REAL_T_IS_DOUBLE>
$<${IS_MSVC}:$<${DISABLE_EXCEPTIONS}:_HAS_EXCEPTIONS=0>>
$<${THREADS_ENABLED}:THREADS_ENABLED>
)
target_link_options(
godot-cpp
PUBLIC
$<${DEBUG_SYMBOLS}:$<${IS_MSVC}:/DEBUG:FULL>>
$<$<NOT:${DEBUG_SYMBOLS}>:
$<${IS_GNU}:-s>
$<${IS_CLANG}:-s>
$<${IS_APPLECLANG}:-Wl,-S -Wl,-x -Wl,-dead_strip>
>
PRIVATE
$<${IS_MSVC}:
/WX # treat link warnings as errors.
/MANIFEST:NO # We dont need a manifest
>
)
# gersemi: on
endfunction()

View File

@@ -1,40 +0,0 @@
#[=======================================================================[.rst:
emsdkHack
---------
The Emscripten platform doesn't support the use of shared libraries as known by cmake.
* https://github.com/emscripten-core/emscripten/issues/15276
* https://github.com/emscripten-core/emscripten/issues/17804
This workaround only works due to the way the cmake scripts are loaded.
Prior to the use of ``project( ... )`` directive we need to set
``CMAKE_PROJECT_INCLUDE=cmake/emscripten.cmake``.
This file will be loaded after the toolchain overriding the settings that
prevent shared library building.
CMAKE_PROJECT_INCLUDE was Added in version 3.15.
``CMAKE_PROJECT_<projectName>_INCLUDE`` was Added in version 3.17:
More information on cmake's `code injection`_
.. _code injection:https://cmake.org/cmake/help/latest/command/project.html#code-injection
Overwrite Shared Library Properties to allow shared libs to be generated.
]=======================================================================]
if(EMSCRIPTEN)
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-sSIDE_MODULE=1")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-sSIDE_MODULE=1")
set(CMAKE_SHARED_LIBRARY_SUFFIX) # remove the suffix from the shared lib
set(CMAKE_STRIP FALSE) # used by default in pybind11 on .so modules
# The Emscripten toolchain sets the default value for EMSCRIPTEN_SYSTEM_PROCESSOR to x86
# and copies that to CMAKE_SYSTEM_PROCESSOR. We don't want that.
set(CMAKE_SYSTEM_PROCESSOR "wasm32")
# the above prevents the need for logic like:
#if( ${CMAKE_SYSTEM_NAME} STREQUAL Emscripten )
# set( SYSTEM_ARCH wasm32 )
#endif ()
endif()

View File

@@ -1,399 +0,0 @@
#[=======================================================================[.rst:
godotcpp.cmake
--------------
As godot-cpp is a C++ project, there are no C files, and detection of a C
compiler is unnecessary. When CMake performs the configure process, if a
C compiler is specified, like in a toolchain, or from an IDE, then it will
print a warning stating that the CMAKE_C_COMPILER compiler is unused.
This if statement simply silences that warning.
]=======================================================================]
if(CMAKE_C_COMPILER)
endif()
#[[ Include Platform Files
Because these files are included into the top level CMakeLists.txt before the
project directive, it means that
CMAKE_CURRENT_SOURCE_DIR is the location of godot-cpp's CMakeLists.txt
CMAKE_SOURCE_DIR is the location where any prior project() directive was ]]
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GodotCPPModule.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/common_compiler_flags.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/android.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ios.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/web.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows.cmake)
# Detect number of processors
include(ProcessorCount)
ProcessorCount(PROC_MAX)
message(STATUS "Auto-detected ${PROC_MAX} CPU cores available for build parallelism.")
# List of known platforms
set(PLATFORM_LIST
linux
macos
windows
android
ios
web
)
# List of known architectures
set(ARCH_LIST
x86_32
x86_64
arm32
arm64
rv64
ppc32
ppc64
wasm32
)
#[=============================[ godot_arch_name ]=============================]
#[[ Function to map CMAKE_SYSTEM_PROCESSOR names to godot arch equivalents ]]
function(godot_arch_name OUTVAR)
# Special case for macos universal builds that target both x86_64 and arm64
if(DEFINED CMAKE_OSX_ARCHITECTURES)
if("x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES AND "arm64" IN_LIST CMAKE_OSX_ARCHITECTURES)
set(${OUTVAR} "universal" PARENT_SCOPE)
return()
endif()
endif()
# Direct match early out.
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ARCH)
if(ARCH IN_LIST ARCH_LIST)
set(${OUTVAR} "${ARCH}" PARENT_SCOPE)
return()
endif()
# Known aliases
set(x86_64 "w64;amd64;x86-64")
set(arm32 "armv7;armv7-a")
set(arm64 "armv8;arm64v8;aarch64;armv8-a")
set(rv64 "rv;riscv;riscv64")
set(ppc32 "ppcle;ppc")
set(ppc64 "ppc64le")
if(ARCH IN_LIST x86_64)
set(${OUTVAR} "x86_64" PARENT_SCOPE)
elseif(ARCH IN_LIST arm32)
set(${OUTVAR} "arm32" PARENT_SCOPE)
elseif(ARCH IN_LIST arm64)
set(${OUTVAR} "arm64" PARENT_SCOPE)
elseif(ARCH IN_LIST rv64)
set(${OUTVAR} "rv64" PARENT_SCOPE)
elseif(ARCH IN_LIST ppc32)
set(${OUTVAR} "ppc32" PARENT_SCOPE)
elseif(ARCH IN_LIST ppc64)
set(${OUTVAR} "ppc64" PARENT_SCOPE)
elseif(ARCH MATCHES "86")
# Catches x86, i386, i486, i586, i686, etc.
set(${OUTVAR} "x86_32" PARENT_SCOPE)
else()
# Default value is whatever the processor is.
set(${OUTVAR} ${CMAKE_SYSTEM_PROCESSOR} PARENT_SCOPE)
endif()
endfunction()
# Function to define all the options.
function(godotcpp_options)
#NOTE: platform is managed using toolchain files.
#NOTE: arch is managed by using toolchain files.
# To create a universal build for macos, set CMAKE_OSX_ARCHITECTURES
set(GODOTCPP_TARGET
"template_debug"
CACHE STRING
"Which target to generate. valid values are: template_debug, template_release, and editor"
)
set_property(CACHE GODOTCPP_TARGET PROPERTY STRINGS "template_debug;template_release;editor")
# Input from user for GDExtension interface header and the API JSON file
set(GODOTCPP_GDEXTENSION_DIR
"gdextension"
CACHE PATH
"Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )"
)
set(GODOTCPP_CUSTOM_API_FILE
""
CACHE FILEPATH
"Path to a custom GDExtension API JSON file (takes precedence over `GODOTCPP_GDEXTENSION_DIR`) ( /path/to/custom_api_file )"
)
#TODO generate_bindings
option(GODOTCPP_GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node. (ON|OFF)" ON)
#TODO build_library
set(GODOTCPP_PRECISION "single" CACHE STRING "Set the floating-point precision level (single|double)")
set(GODOTCPP_THREADS ON CACHE BOOL "Enable threading support")
#TODO compiledb
#TODO compiledb_file
set(GODOTCPP_BUILD_PROFILE "" CACHE PATH "Path to a file containing a feature build profile")
set(GODOTCPP_USE_HOT_RELOAD "" CACHE BOOL "Enable the extra accounting required to support hot reload. (ON|OFF)")
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time (GH-80513).
option(GODOTCPP_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON)
set(GODOTCPP_SYMBOL_VISIBILITY
"hidden"
CACHE STRING
"Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)"
)
set_property(CACHE GODOTCPP_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden")
#TODO optimize
option(GODOTCPP_DEV_BUILD "Developer build with dev-only debugging code (DEV_ENABLED)" OFF)
#[[ debug_symbols
Debug symbols are enabled by using the Debug or RelWithDebInfo build configurations.
Single Config Generator is set at configure time
cmake ../ -DCMAKE_BUILD_TYPE=Debug
Multi-Config Generator is set at build time
cmake --build . --config Debug
]]
# FIXME These options are not present in SCons, and perhaps should be added there.
option(GODOTCPP_SYSTEM_HEADERS "Expose headers as SYSTEM." OFF)
option(GODOTCPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
# Enable Testing
option(GODOTCPP_ENABLE_TESTING "Enable the godot-cpp.test.<target> integration testing targets" OFF)
#[[ Target Platform Options ]]
android_options()
ios_options()
linux_options()
macos_options()
web_options()
windows_options()
endfunction()
#[===========================[ Target Generation ]===========================]
function(godotcpp_generate)
#[[ Multi-Threaded MSVC Compilation
When using the MSVC compiler the build command -j <n> only specifies
parallel jobs or targets, and not multi-threaded compilation To speed up
compile times on msvc, the /MP <n> flag can be set. But we need to set it
at configure time.
MSVC is true when the compiler is some version of Microsoft Visual C++ or
another compiler simulating the Visual C++ cl command-line syntax. ]]
if(MSVC)
math(EXPR PROC_N "(${PROC_MAX}-1) | (${X}-2)>>31 & 1")
message(STATUS "Using ${PROC_N} cores for multi-threaded compilation.")
# TODO You can override it at configure time with ...." )
else()
if(CMAKE_BUILD_PARALLEL_LEVEL)
set(_cores "${CMAKE_BUILD_PARALLEL_LEVEL}")
else()
set(_cores "all")
endif()
message(
STATUS
"Using ${_cores} cores. You can override"
" this at configure time by using -j <n> or --parallel <n> in the build"
" command."
)
message(STATUS " eg. cmake --build . -j 7 ...")
endif()
#[[ GODOTCPP_SYMBOL_VISIBLITY
To match the SCons options, the allowed values are "auto", "visible", and "hidden"
This effects the compiler flag_ -fvisibility=[default|internal|hidden|protected]
The corresponding target option CXX_VISIBILITY_PRESET accepts the compiler values.
TODO: It is probably worth a pull request which changes both to use the compiler values
.. _flag:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fvisibility
]]
if(${GODOTCPP_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOTCPP_SYMBOL_VISIBILITY} STREQUAL "visible")
set(GODOTCPP_SYMBOL_VISIBILITY "default")
endif()
# Setup variable to optionally mark headers as SYSTEM
set(GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE "")
if(GODOTCPP_SYSTEM_HEADERS)
set(GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif()
#[[ Configure Binding Variables ]]
# Generate Binding Parameters (True|False)
set(USE_TEMPLATE_GET_NODE "False")
if(GODOTCPP_GENERATE_TEMPLATE_GET_NODE)
set(USE_TEMPLATE_GET_NODE "True")
endif()
# Bits (32|64)
math(EXPR BITS "${CMAKE_SIZEOF_VOID_P} * 8") # CMAKE_SIZEOF_VOID_P refers to target architecture.
# API json File
set(GODOTCPP_GDEXTENSION_API_FILE "${GODOTCPP_GDEXTENSION_DIR}/extension_api.json")
if(GODOTCPP_CUSTOM_API_FILE) # User-defined override.
set(GODOTCPP_GDEXTENSION_API_FILE "${GODOTCPP_CUSTOM_API_FILE}")
endif()
# Build Profile
if(GODOTCPP_BUILD_PROFILE)
message(STATUS "Using build profile to trim api file")
message(STATUS "\tBUILD_PROFILE = '${GODOTCPP_BUILD_PROFILE}'")
message(STATUS "\tAPI_SOURCE = '${GODOTCPP_GDEXTENSION_API_FILE}'")
build_profile_generate_trimmed_api(
"${GODOTCPP_BUILD_PROFILE}"
"${GODOTCPP_GDEXTENSION_API_FILE}"
"${CMAKE_CURRENT_BINARY_DIR}/extension_api.json"
)
set(GODOTCPP_GDEXTENSION_API_FILE "${CMAKE_CURRENT_BINARY_DIR}/extension_api.json")
endif()
message(STATUS "GODOTCPP_GDEXTENSION_API_FILE = '${GODOTCPP_GDEXTENSION_API_FILE}'")
# generate the file list to use
binding_generator_get_file_list( GENERATED_FILES_LIST
"${GODOTCPP_GDEXTENSION_API_FILE}"
"${CMAKE_CURRENT_BINARY_DIR}"
)
binding_generator_generate_bindings(
"${GODOTCPP_GDEXTENSION_API_FILE}"
"${USE_TEMPLATE_GET_NODE}"
"${BITS}"
"${GODOTCPP_PRECISION}"
"${CMAKE_CURRENT_BINARY_DIR}"
)
### Platform is derived from the toolchain target
# See GeneratorExpressions PLATFORM_ID and CMAKE_SYSTEM_NAME
string(
CONCAT
SYSTEM_NAME
"$<$<PLATFORM_ID:Android>:android>"
"$<$<PLATFORM_ID:iOS>:ios>"
"$<$<PLATFORM_ID:Linux>:linux>"
"$<$<PLATFORM_ID:Darwin>:macos>"
"$<$<PLATFORM_ID:Emscripten>:web>"
"$<$<PLATFORM_ID:Windows>:windows>"
"$<$<PLATFORM_ID:Msys>:windows>"
)
# Process CPU architecture argument.
godot_arch_name( ARCH_NAME )
# Transform options into generator expressions
set(HOT_RELOAD-UNSET "$<STREQUAL:${GODOTCPP_USE_HOT_RELOAD},>")
set(DISABLE_EXCEPTIONS "$<BOOL:${GODOTCPP_DISABLE_EXCEPTIONS}>")
set(THREADS_ENABLED "$<BOOL:${GODOTCPP_THREADS}>")
# GODOTCPP_DEV_BUILD
set(RELEASE_TYPES "Release;MinSizeRel")
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTI_CONFIG)
message(NOTICE "=> Default build type is Debug. For other build types add --config <type> to build command")
elseif(GODOTCPP_DEV_BUILD AND CMAKE_BUILD_TYPE IN_LIST RELEASE_TYPES)
message(
WARNING
"=> GODOTCPP_DEV_BUILD implies a Debug-like build but CMAKE_BUILD_TYPE is '${CMAKE_BUILD_TYPE}'"
)
endif()
set(IS_DEV_BUILD "$<BOOL:${GODOTCPP_DEV_BUILD}>")
### Define our godot-cpp library targets
# Generator Expressions that rely on the target
set(DEBUG_FEATURES "$<NOT:$<STREQUAL:${GODOTCPP_TARGET},template_release>>")
set(HOT_RELOAD "$<IF:${HOT_RELOAD-UNSET},${DEBUG_FEATURES},$<BOOL:${GODOTCPP_USE_HOT_RELOAD}>>")
# Suffix Generator Expression
string(
CONCAT
GODOTCPP_SUFFIX_GENEX
"$<1:${SYSTEM_NAME}>"
"$<1:.${GODOTCPP_TARGET}>"
"$<${IS_DEV_BUILD}:.dev>"
"$<$<STREQUAL:${GODOTCPP_PRECISION},double>:.double>"
"$<1:.${ARCH_NAME}>"
# TODO IOS_SIMULATOR
"$<$<NOT:${THREADS_ENABLED}>:.nothreads>"
)
# The same as above, but with a leading '.' to maintain backwards compatibility.
set(GODOTCPP_SUFFIX ".${GODOTCPP_SUFFIX_GENEX}")
# the godot-cpp.* library targets
add_library(godot-cpp STATIC)
# Without adding this dependency to the binding generator, XCode will complain.
add_dependencies(godot-cpp generate_bindings)
# Added for backwards compatibility with prior cmake solution so that builds dont immediately break
# from a missing target.
add_library(godot::cpp ALIAS godot-cpp)
file(GLOB_RECURSE GODOTCPP_SOURCES LIST_DIRECTORIES NO CONFIGURE_DEPENDS src/*.cpp)
target_sources(godot-cpp PRIVATE ${GODOTCPP_SOURCES} ${GENERATED_FILES_LIST})
target_include_directories(
godot-cpp
${GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE}
PUBLIC include ${CMAKE_CURRENT_BINARY_DIR}/gen/include ${GODOTCPP_GDEXTENSION_DIR}
)
# gersemi: off
set_target_properties(
godot-cpp
PROPERTIES
CXX_STANDARD 17
CXX_EXTENSIONS OFF
CXX_VISIBILITY_PRESET ${GODOTCPP_SYMBOL_VISIBILITY}
COMPILE_WARNING_AS_ERROR ${GODOTCPP_WARNING_AS_ERROR}
POSITION_INDEPENDENT_CODE ON
BUILD_RPATH_USE_ORIGIN ON
PREFIX "lib"
OUTPUT_NAME "${PROJECT_NAME}${GODOTCPP_SUFFIX}"
ARCHIVE_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/bin>"
# Things that are handy to know for dependent targets
GODOTCPP_PLATFORM "${SYSTEM_NAME}"
GODOTCPP_TARGET "${GODOTCPP_TARGET}"
GODOTCPP_ARCH "${ARCH_NAME}"
GODOTCPP_PRECISION "${GODOTCPP_PRECISION}"
GODOTCPP_SUFFIX "${GODOTCPP_SUFFIX}"
GODOTCPP_SUFFIX_GENEX "${GODOTCPP_SUFFIX_GENEX}"
# Some IDE's respect this property to logically group targets
FOLDER "godot-cpp"
)
# gersemi: on
if(CMAKE_SYSTEM_NAME STREQUAL Android)
android_generate()
elseif(CMAKE_SYSTEM_NAME STREQUAL iOS)
ios_generate()
elseif(CMAKE_SYSTEM_NAME STREQUAL Linux)
linux_generate()
elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
macos_generate()
elseif(CMAKE_SYSTEM_NAME STREQUAL Emscripten)
web_generate()
elseif(CMAKE_SYSTEM_NAME STREQUAL Windows)
windows_generate()
endif()
endfunction()

View File

@@ -1,36 +0,0 @@
#[=======================================================================[.rst:
iOS
---
This file contains functions for options and configuration for targeting the
iOS platform
]=======================================================================]
#[==============================[ iOS Options ]==============================]
function(ios_options)
#[[ Options from SCons
TODO ios_simulator: Target iOS Simulator
Default: False
TODO ios_min_version: Target minimum iphoneos/iphonesimulator version
Default: 12.0
TODO IOS_TOOLCHAIN_PATH: Path to iOS toolchain
Default: "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain",
TODO IOS_SDK_PATH: Path to the iOS SDK
Default: ''
TODO ios_triple: Triple for ios toolchain
Default: if has_ios_osxcross(): 'ios_triple' else ''
]]
endfunction()
#[===========================[ Target Generation ]===========================]
function(ios_generate)
target_compile_definitions(godot-cpp PUBLIC IOS_ENABLED UNIX_ENABLED)
common_compiler_flags()
endfunction()

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +0,0 @@
#[=======================================================================[.rst:
Linux
-----
This file contains functions for options and configuration for targeting the
Linux platform
]=======================================================================]
#[=============================[ Linux Options ]=============================]
function(linux_options)
#[[ Options from SCons
use_llvm : Use the LLVM compiler
Not implemented as compiler selection is managed by CMake. Look to
the docs (https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
for examples.
]]
option(GODOTCPP_USE_STATIC_CPP "Link libgcc and libstdc++ statically for better portability" OFF)
endfunction()
#[===========================[ Target Generation ]===========================]
function(linux_generate)
set(STATIC_CPP "$<BOOL:${GODOTCPP_USE_STATIC_CPP}>")
target_compile_definitions(godot-cpp PUBLIC LINUX_ENABLED UNIX_ENABLED)
# gersemi: off
target_link_options(
godot-cpp
PUBLIC
$<${STATIC_CPP}:
-static-libgcc
-static-libstdc++
>
)
# gersemi: on
common_compiler_flags()
endfunction()

View File

@@ -1,41 +0,0 @@
#[=======================================================================[.rst:
MacOS
-----
This file contains functions for options and configuration for targeting the
MacOS platform
Universal Builds
----------------
To build universal binaries, ie targeting both x86_64 and arm64, use
the CMAKE_OSX_ARCHITECTURES variable prior to any project calls.
https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_ARCHITECTURES.html
]=======================================================================]
# Find Requirements
if(APPLE)
set(CMAKE_OSX_SYSROOT $ENV{SDKROOT})
endif(APPLE)
#[=============================[ MacOS Options ]=============================]
function(macos_options)
#[[ Options from SCons
TODO macos_deployment_target: macOS deployment target
Default: 'default'
TODO macos_sdk_path: macOS SDK path
Default: ''
TODO osxcross_sdk: OSXCross SDK version
Default: if has_osxcross(): "darwin16" else None
]]
endfunction()
#[===========================[ Target Generation ]===========================]
function(macos_generate)
target_compile_definitions(godot-cpp PUBLIC MACOS_ENABLED UNIX_ENABLED)
common_compiler_flags()
endfunction()

View File

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

View File

@@ -1,118 +0,0 @@
#[=======================================================================[.rst:
Windows
-------
This file contains functions for options and configuration for targeting the
Windows platform
Because this file is included into the top level CMakelists.txt before the
project directive, it means that
* ``CMAKE_CURRENT_SOURCE_DIR`` is the location of godot-cpp's CMakeLists.txt
* ``CMAKE_SOURCE_DIR`` is the location where any prior ``project(...)``
directive was
MSVC Runtime Selection
----------------------
There are two main ways to set the msvc runtime library;
Using ``target_compile_options()`` to add the flags
or using the ``CMAKE_MSVC_RUNTIME_LIBRARY`` property_ abstraction, introduced
in CMake version 3.15 with the policy CMP0091_ to remove the flags from
``CMAKE_<LANG>_FLAGS_<CONFIG>``.
Default: ``CMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"``
This initializes each target's ``MSVC_RUNTIME_LIBRARY`` property at the time of
target creation.
it is stated in the msvc_ documentation that: "All modules passed to a given
invocation of the linker must have been compiled with the same runtime library
compiler option (/MD, /MT, /LD)."
This creates a conundrum for us, the ``CMAKE_MSVC_RUNTIME_LIBRARY`` needs to be
correct at the time the target is created, but we have no control over the
consumers CMake scripts, and the per-target ``MSVC_RUNTIME_LIBRARY`` property
is not transient.
It has been raised that not using ``CMAKE_MSVC_RUNTIME_LIBRARY`` can also cause
issues_ when a dependency( independent to godot-cpp ) that doesn't set any
runtime flags, which relies purely on the ``CMAKE_MSVC_RUNTIME_LIBRARY``
variable will very likely not have the correct msvc runtime flags set.
So we'll set ``CMAKE_MSVC_RUNTIME_LIBRARY`` as CACHE STRING so that it will be
available for consumer target definitions, but also be able to be overridden if
needed.
Additionally we message consumers notifying them and pointing to this
documentation.
.. _CMP0091:https://cmake.org/cmake/help/latest/policy/CMP0091.html
.. _property:https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html
.. https://discourse.cmake.org/t/mt-staticrelease-doesnt-match-value-md-dynamicrelease/5428/4
.. _msvc: https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library
.. _issues: https://github.com/godotengine/godot-cpp/issues/1699
]=======================================================================]
#[============================[ Windows Options ]============================]
function(windows_options)
#[[ Options from SCons
TODO silence_msvc: Silence MSVC's cl/link stdout bloat, redirecting errors to stderr
Default: True
These three options will not implemented as compiler selection is managed
by CMake toolchain files. Look to the docs
(https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/build_system/cmake.html)
for examples.
use_mingw: Use the MinGW compiler instead of MSVC - only effective on Windows
use_llvm: Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag
mingw_prefix: MinGW prefix
]]
option(GODOTCPP_USE_STATIC_CPP "Link MinGW/MSVC C++ runtime libraries statically" ON)
option(GODOTCPP_DEBUG_CRT "Compile with MSVC's debug CRT (/MDd)" OFF)
message(
STATUS
"If not already cached, setting CMAKE_MSVC_RUNTIME_LIBRARY.\n"
"\tFor more information please read godot-cpp/cmake/windows.cmake"
)
set(CMAKE_MSVC_RUNTIME_LIBRARY
"MultiThreaded$<IF:$<BOOL:${GODOTCPP_DEBUG_CRT}>,DebugDLL,$<$<NOT:$<BOOL:${GODOTCPP_USE_STATIC_CPP}>>:DLL>>"
CACHE STRING
"Select the MSVC runtime library for use by compilers targeting the MSVC ABI."
)
endfunction()
#[===========================[ Target Generation ]===========================]
function(windows_generate)
set(STATIC_CPP "$<BOOL:${GODOTCPP_USE_STATIC_CPP}>")
set_target_properties(godot-cpp PROPERTIES PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>")
target_compile_definitions(
godot-cpp
PUBLIC WINDOWS_ENABLED $<${IS_MSVC}: TYPED_METHOD_BIND NOMINMAX >
)
# gersemi: off
target_link_options(
godot-cpp
PUBLIC
$<${NOT_MSVC}:
-Wl,--no-undefined
$<${STATIC_CPP}:
-static
-static-libgcc
-static-libstdc++
>
>
$<${IS_CLANG}:-lstdc++>
)
# gersemi: on
common_compiler_flags()
endfunction()

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
#define GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
#include <godot_cpp/templates/vector.hpp>
@@ -57,3 +58,5 @@ public:
};
} // namespace godot
#endif // GODOT_EDITOR_PLUGIN_REGISTRATION_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_REF_HPP
#define GODOT_REF_HPP
#include <godot_cpp/core/defs.hpp>
@@ -70,10 +71,6 @@ class Ref {
}
public:
static _FORCE_INLINE_ String get_class_static() {
return T::get_class_static();
}
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
return reference == p_ptr;
}
@@ -233,9 +230,7 @@ template <typename T>
struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
if (unlikely(!p_ptr)) {
return Ref<T>();
}
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))));
}
@@ -259,17 +254,15 @@ struct PtrToArg<const Ref<T> &> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
GDExtensionRefPtr ref = const_cast<GDExtensionRefPtr>(p_ptr);
if (unlikely(!p_ptr)) {
return Ref<T>();
}
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 <typename T>
struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
@@ -278,8 +271,8 @@ struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>
template <typename T>
struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
@@ -287,3 +280,5 @@ struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>
};
} // namespace godot
#endif // GODOT_REF_HPP

View File

@@ -28,63 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#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/templates/vector.hpp>
#include <godot_cpp/godot.hpp>
#if defined(MACOS_ENABLED) && defined(HOT_RELOAD_ENABLED)
#include <mutex>
#define _GODOT_CPP_AVOID_THREAD_LOCAL
#define _GODOT_CPP_THREAD_LOCAL
#else
#define _GODOT_CPP_THREAD_LOCAL thread_local
#endif
namespace godot {
class ClassDB;
typedef void GodotObject;
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
_ALWAYS_INLINE_ void _pre_initialize();
// Base for all engine classes, to contain the pointer to the engine instance.
class Wrapped {
friend class GDExtensionBinding;
friend class ClassDB;
friend void postinitialize_handler(Wrapped *);
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
friend _ALWAYS_INLINE_ void _pre_initialize();
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
static std::recursive_mutex _constructing_mutex;
#endif
_GODOT_CPP_THREAD_LOCAL static const StringName *_constructing_extension_class_name;
_GODOT_CPP_THREAD_LOCAL static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
#ifdef HOT_RELOAD_ENABLED
_GODOT_CPP_THREAD_LOCAL static GDExtensionObjectPtr _constructing_recreate_owner;
#endif
template <typename T>
_ALWAYS_INLINE_ static void _set_construct_info() {
_constructing_extension_class_name = T::_get_extension_class_name();
_constructing_class_binding_callbacks = &T::_gde_binding_callbacks;
}
protected:
virtual bool _is_extension_class() const { return false; }
static const StringName *_get_extension_class_name(); // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
virtual const StringName *_get_extension_class_name() const; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const = 0;
void _notification(int p_what) {}
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
@@ -92,72 +60,43 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const {}
bool _property_can_revert(const StringName &p_name) const { return false; }
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }
void _validate_property(PropertyInfo &p_property) const {}
String _to_string() const { return "<Wrapped#0>"; }
String _to_string() const { return "[" + String(get_class_static()) + ":" + itos(get_instance_id()) + "]"; }
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) {}
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) {}
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { return false; }
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { return nullptr; }
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) {}
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) {}
static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { return false; }
static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { return false; }
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) {}
// The only reason this has to be held here, is when we return results of `_get_property_list` to Godot, we pass
// pointers to strings in this list. They have to remain valid to pass the bridge, until the list is freed by Godot...
::godot::List<::godot::PropertyInfo> plist_owned;
GDExtensionPropertyInfo *plist = nullptr;
uint32_t plist_size = 0;
void _postinitialize();
Wrapped(const StringName &p_godot_class);
Wrapped(const StringName p_godot_class);
Wrapped(GodotObject *p_godot_object);
virtual ~Wrapped() {}
public:
static const StringName &get_class_static() {
static const StringName string_name = StringName("Wrapped");
static StringName &get_class_static() {
static StringName string_name = StringName("Wrapped");
return string_name;
}
uint64_t get_instance_id() const {
return 0;
}
// Must be public but you should not touch this.
GodotObject *_owner = nullptr;
};
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
_ALWAYS_INLINE_ void _pre_initialize() {
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
Wrapped::_constructing_mutex.lock();
#endif
Wrapped::_set_construct_info<T>();
}
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
}
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str) {
arr.push_back(p_str);
}
template <typename... P>
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str, P... p_args) {
arr.push_back(p_str);
snarray_add_str(arr, p_args...);
}
template <typename... P>
_FORCE_INLINE_ Vector<StringName> snarray(P... p_args) {
Vector<StringName> arr;
snarray_add_str(arr, p_args...);
return arr;
}
namespace internal {
GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size);
void free_c_property_list(GDExtensionPropertyInfo *plist);
typedef void (*EngineClassRegistrationCallback)();
void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback);
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks);
@@ -178,23 +117,19 @@ struct EngineClassRegistration {
} // namespace godot
// Use this on top of your own classes.
// Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes
// every line of the macro different
#define GDCLASS(m_class, m_inherits) /***********************************************************************************************************************************************/ \
#define GDCLASS(m_class, m_inherits) \
private: \
void operator=(const m_class & /*p_rval*/) {} \
void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
friend class ::godot::Wrapped; \
\
protected: \
virtual bool _is_extension_class() const override { \
return true; \
virtual const ::godot::StringName *_get_extension_class_name() const override { \
static ::godot::StringName string_name = get_class_static(); \
return &string_name; \
} \
\
static const ::godot::StringName *_get_extension_class_name() { \
const ::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())() { \
@@ -202,35 +137,31 @@ protected:
} \
\
static void (::godot::Wrapped::*_get_notification())(int) { \
return (void (::godot::Wrapped::*)(int)) & m_class::_notification; \
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; \
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; \
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; \
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; \
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; \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &) const) & m_class::_property_get_revert; \
} \
\
static ::godot::String (::godot::Wrapped::*_get_to_string())() const { \
return (::godot::String (::godot::Wrapped::*)() const) & m_class::_to_string; \
return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \
} \
\
template <typename T, typename B> \
@@ -240,7 +171,6 @@ protected:
\
public: \
typedef m_class self_type; \
typedef m_inherits parent_type; \
\
static void initialize_class() { \
static bool initialized = false; \
@@ -255,78 +185,86 @@ public:
initialized = true; \
} \
\
static const ::godot::StringName &get_class_static() { \
static const ::godot::StringName string_name = ::godot::StringName(U## #m_class); \
static ::godot::StringName &get_class_static() { \
static ::godot::StringName string_name = ::godot::StringName(#m_class); \
return string_name; \
} \
\
static const ::godot::StringName &get_parent_class_static() { \
static ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
\
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \
static GDExtensionObjectPtr create(void *data) { \
m_class *new_object = memnew(m_class); \
return new_object->_owner; \
} \
\
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \
if (p_instance && m_class::_get_notification()) { \
if (!p_reversed) { \
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
} \
m_inherits::notification_bind(p_instance, p_what); \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
cls->_notification(p_what); \
} \
if (p_reversed) { \
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) { \
if (m_inherits::set_bind(p_instance, p_name, p_value)) { \
return true; \
} \
if (p_instance && m_class::_get_set()) { \
if (m_class::_get_set() != m_inherits::_get_set()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_set(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<const ::godot::Variant *>(p_value)); \
} \
return m_inherits::set_bind(p_instance, p_name, p_value); \
} \
return false; \
} \
\
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
if (p_instance) { \
if (m_inherits::get_bind(p_instance, p_name, r_ret)) { \
return true; \
} \
if (p_instance && m_class::_get_get()) { \
if (m_class::_get_get() != m_inherits::_get_get()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_get(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \
} \
return m_inherits::get_bind(p_instance, p_name, r_ret); \
} \
return false; \
} \
\
static inline bool has_get_property_list() { \
return m_class::_get_get_property_list() && m_class::_get_get_property_list() != m_inherits::_get_get_property_list(); \
} \
\
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \
if (!p_instance) { \
if (r_count) \
*r_count = 0; \
return nullptr; \
if (p_instance && m_class::_get_get_property_list()) { \
if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
ERR_FAIL_COND_V_MSG(!cls->plist_owned.is_empty() || cls->plist != nullptr || cls->plist_size != 0, nullptr, "Internal error, property list was not freed by engine!"); \
cls->_get_property_list(&cls->plist_owned); \
cls->plist = reinterpret_cast<GDExtensionPropertyInfo *>(memalloc(sizeof(GDExtensionPropertyInfo) * cls->plist_owned.size())); \
cls->plist_size = 0; \
for (const ::godot::PropertyInfo &E : cls->plist_owned) { \
cls->plist[cls->plist_size].type = static_cast<GDExtensionVariantType>(E.type); \
cls->plist[cls->plist_size].name = E.name._native_ptr(); \
cls->plist[cls->plist_size].hint = E.hint; \
cls->plist[cls->plist_size].hint_string = E.hint_string._native_ptr(); \
cls->plist[cls->plist_size].class_name = E.class_name._native_ptr(); \
cls->plist[cls->plist_size].usage = E.usage; \
cls->plist_size++; \
} \
if (r_count) \
*r_count = cls->plist_size; \
return cls->plist; \
} \
return m_inherits::get_property_list_bind(p_instance, r_count); \
} \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
::godot::List<::godot::PropertyInfo> &plist_cpp = cls->plist_owned; \
ERR_FAIL_COND_V_MSG(!plist_cpp.is_empty(), nullptr, "Internal error, property list was not freed by engine!"); \
cls->_get_property_list(&plist_cpp); \
return ::godot::internal::create_c_property_list(plist_cpp, r_count); \
return nullptr; \
} \
\
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t /*p_count*/) { \
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) { \
if (p_instance) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
ERR_FAIL_COND_MSG(cls->plist == nullptr, "Internal error, property list double free!"); \
memfree(cls->plist); \
cls->plist = nullptr; \
cls->plist_size = 0; \
cls->plist_owned.clear(); \
::godot::internal::free_c_property_list(const_cast<GDExtensionPropertyInfo *>(p_list)); \
} \
} \
\
@@ -352,21 +290,6 @@ public:
return false; \
} \
\
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { \
bool ret = false; \
if (p_instance && m_class::_get_validate_property()) { \
ret = m_inherits::validate_property_bind(p_instance, p_property); \
if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
::godot::PropertyInfo info(p_property); \
cls->_validate_property(info); \
info._update(p_property); \
return true; \
} \
} \
return ret; \
} \
\
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) { \
if (p_instance && m_class::_get_to_string()) { \
if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \
@@ -379,7 +302,7 @@ public:
} \
} \
\
static void free(void * /*data*/, GDExtensionClassInstancePtr ptr) { \
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
if (ptr) { \
m_class *cls = reinterpret_cast<m_class *>(ptr); \
cls->~m_class(); \
@@ -387,14 +310,14 @@ public:
} \
} \
\
static void *_gde_binding_create_callback(void * /*p_token*/, void * /*p_instance*/) { \
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 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*/) { \
static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
return true; \
} \
\
@@ -411,15 +334,15 @@ private:
private: \
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
friend class ::godot::Wrapped; \
\
protected: \
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 _bind_methods() {} \
\
static void (*_get_bind_methods())() { \
return nullptr; \
} \
@@ -462,25 +385,28 @@ protected:
\
public: \
typedef m_class self_type; \
typedef m_inherits parent_type; \
\
static void initialize_class() {} \
\
static const ::godot::StringName &get_class_static() { \
static const ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
static ::godot::StringName &get_class_static() { \
static ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
return string_name; \
} \
\
static const ::godot::StringName &get_parent_class_static() { \
static ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
\
static GDExtensionObjectPtr create(void *data) { \
return nullptr; \
} \
\
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
} \
\
static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
/* Do not call memnew here, we don't want the post-initializer to be called */ \
return new ("", "") m_class((GodotObject *)p_instance); \
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 */ \
@@ -502,9 +428,4 @@ private:
// Don't use this for your classes, use GDCLASS() instead.
#define GDEXTENSION_CLASS(m_class, m_inherits) GDEXTENSION_CLASS_ALIAS(m_class, m_class, m_inherits)
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__)
#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call(__VA_ARGS__)
#define GDVIRTUAL_BIND(m_name, ...) ::godot::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), ::godot::snarray(__VA_ARGS__));
#define GDVIRTUAL_IS_OVERRIDDEN(m_name) _gdvirtual_##m_name##_overridden()
#define GDVIRTUAL_IS_OVERRIDDEN_PTR(m_obj, m_name) m_obj->_gdvirtual_##m_name##_overridden()
#endif // GODOT_WRAPPED_HPP

View File

@@ -28,15 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_BINDER_COMMON_HPP
#define GODOT_BINDER_COMMON_HPP
#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/method_ptrcall.hpp>
#include <godot_cpp/core/type_info.hpp>
#include <array>
#include <vector>
namespace godot {
@@ -261,7 +262,6 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#else
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)p_args; // Avoid warning.
}
template <typename T, typename R, typename... P, size_t... Is>
@@ -273,69 +273,15 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
#else
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)p_args; // Avoid warning.
(void)p_args;
}
template <typename T, typename... P>
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, GDExtensionCallError &r_error) {
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename... P>
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 LocalVector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -346,7 +292,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -366,11 +312,11 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G
}
template <typename T, typename... P>
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -381,7 +327,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -401,11 +347,11 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
}
template <typename T, typename R, typename... P>
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -416,7 +362,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -436,11 +382,11 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
}
template <typename T, typename R, typename... P>
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -451,7 +397,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -548,11 +494,11 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg
}
template <typename... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = sizeof...(P);
r_error.argument = sizeof...(P);
return;
}
#endif
@@ -563,7 +509,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionC
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = sizeof...(P);
r_error.argument = sizeof...(P);
return;
}
#endif
@@ -592,42 +538,6 @@ void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionC
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <typename R, typename... P>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename... P>
void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename R, typename... P, size_t... Is>
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;
@@ -640,11 +550,11 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
}
template <typename R, typename... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const LocalVector<Variant> &default_values) {
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = sizeof...(P);
r_error.argument = sizeof...(P);
return;
}
#endif
@@ -655,7 +565,7 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtension
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = sizeof...(P);
r_error.argument = sizeof...(P);
return;
}
#endif
@@ -692,3 +602,5 @@ void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtension
#include <godot_cpp/classes/global_constants_binds.hpp>
#include <godot_cpp/variant/builtin_binds.hpp>
#endif // GODOT_BINDER_COMMON_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_BUILTIN_PTRCALL_HPP
#define GODOT_BUILTIN_PTRCALL_HPP
#include <gdextension_interface.h>
#include <godot_cpp/core/object.hpp>
@@ -87,3 +88,5 @@ T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTy
} // namespace internal
} // namespace godot
#endif // GODOT_BUILTIN_PTRCALL_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_CLASS_DB_HPP
#define GODOT_CLASS_DB_HPP
#include <gdextension_interface.h>
@@ -36,18 +37,22 @@
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/method_bind.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/core/print_string.hpp>
#include <godot_cpp/classes/class_db_singleton.hpp>
// Makes callable_mp readily available in all classes connecting signals.
// Needs to come after method_bind and object have been included.
#include <godot_cpp/variant/callable_method_pointer.hpp>
#include <godot_cpp/templates/a_hash_map.hpp>
#include <list>
#include <mutex>
#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 {
@@ -76,18 +81,22 @@ class ClassDB {
friend class godot::GDExtensionBinding;
public:
struct ClassInfo {
struct VirtualMethod {
GDExtensionClassCallVirtual func;
uint32_t hash;
};
struct PropertySetGet {
int index;
StringName setter;
StringName getter;
MethodBind *_setptr;
MethodBind *_getptr;
Variant::Type type;
};
struct ClassInfo {
StringName name;
StringName parent_name;
GDExtensionInitializationLevel level = GDEXTENSION_INITIALIZATION_SCENE;
AHashMap<StringName, MethodBind *> method_map;
std::unordered_map<StringName, MethodBind *> method_map;
std::set<StringName> signal_names;
AHashMap<StringName, VirtualMethod> virtual_methods;
std::unordered_map<StringName, GDExtensionClassCallVirtual> virtual_methods;
std::set<StringName> property_names;
std::set<StringName> constant_names;
// Pointer to the parent custom class, if any. Will be null if the parent class is a Godot class.
@@ -96,84 +105,28 @@ public:
private:
// This may only contain custom classes, not Godot classes
static HashMap<StringName, ClassInfo> classes;
static AHashMap<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks;
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 LocalVector<StringName> class_register_order;
static AHashMap<StringName, Object *> engine_singletons;
static std::mutex engine_singletons_mutex;
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 <typename T, bool is_abstract>
static void _register_class(bool p_virtual = false, bool p_exposed = true, bool p_runtime = false);
template <typename T>
static GDExtensionObjectPtr _create_instance_func(void *data, GDExtensionBool p_notify_postinitialize) {
if constexpr (!std::is_abstract_v<T>) {
Wrapped::_set_construct_info<T>();
T *new_object = new ("", "") T;
if (p_notify_postinitialize) {
new_object->_postinitialize();
}
return new_object->_owner;
} else {
return nullptr;
}
}
template <typename T>
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
if constexpr (!std::is_abstract_v<T>) {
#ifdef HOT_RELOAD_ENABLED
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
std::lock_guard<std::recursive_mutex> lk(Wrapped::_constructing_mutex);
#endif
Wrapped::_constructing_recreate_owner = obj;
T *new_instance = (T *)memalloc(sizeof(T));
memnew_placement(new_instance, T);
return new_instance;
#else
return nullptr;
#endif
} else {
return nullptr;
}
}
static void _register_class(bool p_virtual = false);
public:
template <typename T>
static void register_class(bool p_virtual = false);
template <typename T>
static void register_abstract_class();
template <typename T>
static void register_internal_class();
template <typename T>
static void register_runtime_class();
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
instance_binding_callbacks[p_name] = p_callbacks;
}
static void _editor_get_classes_used_callback(GDExtensionTypePtr p_packed_string_array);
static void _register_engine_singleton(const StringName &p_class_name, Object *p_singleton) {
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
AHashMap<StringName, Object *>::ConstIterator i = engine_singletons.find(p_class_name);
if (i != engine_singletons.end()) {
ERR_FAIL_COND((*i).value != p_singleton);
return;
}
engine_singletons[p_class_name] = p_singleton;
}
static void _unregister_engine_singleton(const StringName &p_class_name) {
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
engine_singletons.erase(p_class_name);
}
template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
@@ -181,21 +134,18 @@ public:
static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
template <typename M>
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const LocalVector<Variant> &p_default_args = LocalVector<Variant>{}, bool p_return_nil_is_variant = true);
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);
// Binds an implementation of a virtual method defined in Godot.
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call, uint32_t p_hash);
// Add a new virtual method that can be implemented by scripts.
static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, const Vector<StringName> &p_arg_names = Vector<StringName>());
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call);
static MethodBind *get_method(const StringName &p_class, const StringName &p_method);
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
static 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);
@@ -213,19 +163,17 @@ public:
#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, m_hash) \
#define BIND_VIRTUAL_METHOD(m_class, m_method) \
{ \
auto _call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \
call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
}; \
::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method, m_hash); \
::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method); \
}
template <typename T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
void ClassDB::_register_class(bool p_virtual) {
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
static_assert(!FunctionsAreSame<T::self_type::_bind_methods, T::parent_type::_bind_methods>::value, "Class must declare 'static void _bind_methods'.");
static_assert(!std::is_abstract_v<T> || is_abstract, "Class is abstract, please use GDREGISTER_ABSTRACT_CLASS.");
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
// Register this class within our plugin
@@ -233,42 +181,36 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
cl.name = T::get_class_static();
cl.parent_name = T::get_parent_class_static();
cl.level = current_level;
HashMap<StringName, ClassInfo>::Iterator parent_it = classes.find(cl.parent_name);
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->value;
cl.parent_ptr = &parent_it->second;
}
classes[cl.name] = cl;
class_register_order.push_back(cl.name);
// Register this class with Godot
GDExtensionClassCreationInfo5 class_info = {
GDExtensionClassCreationInfo class_info = {
p_virtual, // GDExtensionBool is_virtual;
is_abstract, // GDExtensionBool is_abstract;
p_exposed, // GDExtensionBool is_exposed;
p_runtime, // GDExtensionBool is_runtime;
nullptr, // GDExtensionConstStringPtr icon_path;
T::set_bind, // GDExtensionClassSet set_func;
T::get_bind, // GDExtensionClassGet get_func;
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
T::free_property_list_bind, // GDExtensionClassFreePropertyList2 free_property_list_func;
T::get_property_list_bind, // GDExtensionClassGetPropertyList get_property_list_func;
T::free_property_list_bind, // GDExtensionClassFreePropertyList free_property_list_func;
T::property_can_revert_bind, // GDExtensionClassPropertyCanRevert property_can_revert_func;
T::property_get_revert_bind, // GDExtensionClassPropertyGetRevert property_get_revert_func;
T::validate_property_bind, // GDExtensionClassValidateProperty validate_property_func;
T::notification_bind, // GDExtensionClassNotification2 notification_func;
T::notification_bind, // GDExtensionClassNotification notification_func;
T::to_string_bind, // GDExtensionClassToString to_string_func;
nullptr, // GDExtensionClassReference reference_func;
nullptr, // GDExtensionClassUnreference unreference_func;
&_create_instance_func<T>, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
&_recreate_instance_func<T>, // GDExtensionClassRecreateInstance recreate_instance_func;
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
nullptr, // GDExtensionClassGetRID get_rid;
(void *)&T::get_class_static(), // void *class_userdata;
};
internal::gdextension_interface_classdb_register_extension_class5(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
internal::gdextension_interface_classdb_register_extension_class(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
// call bind_methods etc. to register all members of the class
T::initialize_class();
@@ -287,16 +229,6 @@ void ClassDB::register_abstract_class() {
ClassDB::_register_class<T, true>();
}
template <typename T>
void ClassDB::register_internal_class() {
ClassDB::_register_class<T, false>(false, false);
}
template <typename T>
void ClassDB::register_runtime_class() {
ClassDB::_register_class<T, false>(false, true, true);
}
template <typename N, typename M, typename... VarArgs>
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.
@@ -321,7 +253,7 @@ MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p
}
template <typename M>
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const LocalVector<Variant> &p_default_args, bool p_return_nil_is_variant) {
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);
@@ -330,13 +262,13 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
StringName instance_type = bind->get_instance_class();
HashMap<StringName, ClassInfo>::Iterator type_it = classes.find(instance_type);
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->value;
ClassInfo &type = type_it->second;
if (type.method_map.find(p_name) != type.method_map.end()) {
memdelete(bind);
@@ -352,12 +284,10 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
return bind;
}
#define GDREGISTER_CLASS(m_class) ::godot::ClassDB::register_class<m_class>();
#define GDREGISTER_VIRTUAL_CLASS(m_class) ::godot::ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ::godot::ClassDB::register_abstract_class<m_class>();
#define GDREGISTER_INTERNAL_CLASS(m_class) ::godot::ClassDB::register_internal_class<m_class>();
#define GDREGISTER_RUNTIME_CLASS(m_class) ::godot::ClassDB::register_runtime_class<m_class>();
#define GDREGISTER_CLASS(m_class) ClassDB::register_class<m_class>();
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
} // namespace godot
CLASSDB_SINGLETON_VARIANT_CAST;
#endif // GODOT_CLASS_DB_HPP

View File

@@ -28,14 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_DEFS_HPP
#define GODOT_DEFS_HPP
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <utility>
namespace godot {
#include <cstring>
#if !defined(GDE_EXPORT)
#if defined(_WIN32)
@@ -65,31 +63,17 @@ namespace godot {
#endif
#endif
// Should always inline, except in dev builds because it makes debugging harder,
// or `size_enabled` builds where inlining is actively avoided.
// Should always inline, except in debug builds because it makes debugging harder.
#ifndef _FORCE_INLINE_
#if defined(DEV_ENABLED) || defined(SIZE_EXTRA)
#ifdef DISABLE_FORCED_INLINE
#define _FORCE_INLINE_ inline
#else
#define _FORCE_INLINE_ _ALWAYS_INLINE_
#endif
#endif
// Should never inline.
#ifndef _NO_INLINE_
#if defined(__GNUC__)
#define _NO_INLINE_ __attribute__((noinline))
#elif defined(_MSC_VER)
#define _NO_INLINE_ __declspec(noinline)
#else
#define _NO_INLINE_
#endif
#endif
// In some cases [[nodiscard]] will get false positives,
// we can prevent the warning in specific cases by preceding the call with a cast.
#ifndef _ALLOW_DISCARD_
#define _ALLOW_DISCARD_ (void)
#ifndef _NO_DISCARD_
#define _NO_DISCARD_ [[nodiscard]]
#endif
// Windows badly defines a lot of stuff we'll never use. Undefine it.
@@ -99,182 +83,14 @@ namespace godot {
#undef ERROR // override (really stupid) wingdi.h standard definition
#undef DELETE // override (another really stupid) winnt.h standard definition
#undef MessageBox // override winuser.h standard definition
#undef MIN // override standard definition
#undef MAX // override standard definition
#undef CLAMP // override standard definition
#undef Error
#undef OK
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#undef MemoryBarrier
#undef MONO_FONT
#endif
// Make room for our constexpr's below by overriding potential system-specific macros.
#undef SIGN
#undef MIN
#undef MAX
#undef CLAMP
template <typename T>
constexpr const T SIGN(const T m_v) {
return m_v > 0 ? +1.0f : (m_v < 0 ? -1.0f : 0.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) std::swap((m_x), (m_y))
#endif // SWAP
/* Functions to handle powers of 2 and shifting. */
// Returns `true` if a positive integer is a power of 2, `false` otherwise.
template <typename T>
inline bool is_power_of_2(const T x) {
return x && ((x & (x - 1)) == 0);
}
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
// Function to find the previous power of 2 to an integer.
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x - (x >> 1);
}
// Function to find the closest power of 2 to an integer.
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
unsigned int nx = next_power_of_2(x);
unsigned int px = previous_power_of_2(x);
return (nx - x) > (x - px) ? px : nx;
}
// Get a shift value from a power of 2.
static inline int get_shift_from_power_of_2(unsigned int p_bits) {
for (unsigned int i = 0; i < 32; i++) {
if (p_bits == (unsigned int)(1 << i)) {
return i;
}
}
return -1;
}
template <typename 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)
#elif defined(_MSC_VER)
#define BSWAP16(x) _byteswap_ushort(x)
#define BSWAP32(x) _byteswap_ulong(x)
#define BSWAP64(x) _byteswap_uint64(x)
#else
static inline uint16_t BSWAP16(uint16_t x) {
return (x >> 8) | (x << 8);
}
static inline uint32_t BSWAP32(uint32_t x) {
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
}
static inline uint64_t BSWAP64(uint64_t x) {
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
#endif
// Generic comparator used in Map, List, etc.
template <typename T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
// Global lock macro, relies on the static Mutex::_global_mutex.
void _global_lock();
void _global_unlock();
struct _GlobalLock {
_GlobalLock() { _global_lock(); }
~_GlobalLock() { _global_unlock(); }
};
#define GLOBAL_LOCK_FUNCTION _GlobalLock _global_lock_;
#if defined(__GNUC__)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
@@ -283,17 +99,22 @@ struct _GlobalLock {
#define unlikely(x) x
#endif
#if defined(__GNUC__)
#define _PRINTF_FORMAT_ATTRIBUTE_2_0 __attribute__((format(printf, 2, 0)))
#define _PRINTF_FORMAT_ATTRIBUTE_2_3 __attribute__((format(printf, 2, 3)))
#ifdef REAL_T_IS_DOUBLE
typedef double real_t;
#else
#define _PRINTF_FORMAT_ATTRIBUTE_2_0
#define _PRINTF_FORMAT_ATTRIBUTE_2_3
typedef float real_t;
#endif
// This is needed due to a strange OpenGL API that expects a pointer
// type for an argument that is actually an offset.
#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr))
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <typename 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
@@ -306,79 +127,4 @@ struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {};
template <size_t... Is>
struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
// Limit the depth of recursive algorithms when dealing with Array/Dictionary
#define MAX_RECURSION 100
#ifdef DEBUG_ENABLED
#define DEBUG_METHODS_ENABLED
#endif
// Macro GD_IS_DEFINED() allows to check if a macro is defined. It needs to be defined to anything (say 1) to work.
#define __GDARG_PLACEHOLDER_1 false,
#define __gd_take_second_arg(__ignored, val, ...) val
#define ____gd_is_defined(arg1_or_junk) __gd_take_second_arg(arg1_or_junk true, false)
#define ___gd_is_defined(val) ____gd_is_defined(__GDARG_PLACEHOLDER_##val)
#define GD_IS_DEFINED(x) ___gd_is_defined(x)
// Whether the default value of a type is just all-0 bytes.
// This can most commonly be exploited by using memset for these types instead of loop-construct.
// Trivially constructible types are also zero-constructible.
template <typename T>
struct is_zero_constructible : std::is_trivially_constructible<T> {};
template <typename T>
struct is_zero_constructible<const T> : is_zero_constructible<T> {};
template <typename T>
struct is_zero_constructible<volatile T> : is_zero_constructible<T> {};
template <typename T>
struct is_zero_constructible<const volatile T> : is_zero_constructible<T> {};
template <typename T>
inline constexpr bool is_zero_constructible_v = is_zero_constructible<T>::value;
// Warning suppression helper macros.
#if defined(__clang__)
#define GODOT_CLANG_PRAGMA(m_content) _Pragma(#m_content)
#define GODOT_CLANG_WARNING_PUSH GODOT_CLANG_PRAGMA(clang diagnostic push)
#define GODOT_CLANG_WARNING_IGNORE(m_warning) GODOT_CLANG_PRAGMA(clang diagnostic ignored m_warning)
#define GODOT_CLANG_WARNING_POP GODOT_CLANG_PRAGMA(clang diagnostic pop)
#define GODOT_CLANG_WARNING_PUSH_AND_IGNORE(m_warning) GODOT_CLANG_WARNING_PUSH GODOT_CLANG_WARNING_IGNORE(m_warning)
#else
#define GODOT_CLANG_PRAGMA(m_content)
#define GODOT_CLANG_WARNING_PUSH
#define GODOT_CLANG_WARNING_IGNORE(m_warning)
#define GODOT_CLANG_WARNING_POP
#define GODOT_CLANG_WARNING_PUSH_AND_IGNORE(m_warning)
#endif
#if defined(__GNUC__) && !defined(__clang__)
#define GODOT_GCC_PRAGMA(m_content) _Pragma(#m_content)
#define GODOT_GCC_WARNING_PUSH GODOT_GCC_PRAGMA(GCC diagnostic push)
#define GODOT_GCC_WARNING_IGNORE(m_warning) GODOT_GCC_PRAGMA(GCC diagnostic ignored m_warning)
#define GODOT_GCC_WARNING_POP GODOT_GCC_PRAGMA(GCC diagnostic pop)
#define GODOT_GCC_WARNING_PUSH_AND_IGNORE(m_warning) GODOT_GCC_WARNING_PUSH GODOT_GCC_WARNING_IGNORE(m_warning)
#else
#define GODOT_GCC_PRAGMA(m_content)
#define GODOT_GCC_WARNING_PUSH
#define GODOT_GCC_WARNING_IGNORE(m_warning)
#define GODOT_GCC_WARNING_POP
#define GODOT_GCC_WARNING_PUSH_AND_IGNORE(m_warning)
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#define GODOT_MSVC_PRAGMA(m_content) __pragma(m_content)
#define GODOT_MSVC_WARNING_PUSH GODOT_MSVC_PRAGMA(warning(push))
#define GODOT_MSVC_WARNING_IGNORE(m_warning) GODOT_MSVC_PRAGMA(warning(disable : m_warning))
#define GODOT_MSVC_WARNING_POP GODOT_MSVC_PRAGMA(warning(pop))
#define GODOT_MSVC_WARNING_PUSH_AND_IGNORE(m_warning) GODOT_MSVC_WARNING_PUSH GODOT_MSVC_WARNING_IGNORE(m_warning)
#else
#define GODOT_MSVC_PRAGMA(m_content)
#define GODOT_MSVC_WARNING_PUSH
#define GODOT_MSVC_WARNING_IGNORE(m_warning)
#define GODOT_MSVC_WARNING_POP
#define GODOT_MSVC_WARNING_PUSH_AND_IGNORE(m_warning)
#endif
} //namespace godot
#endif // GODOT_DEFS_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_ENGINE_PTRCALL_HPP
#define GODOT_ENGINE_PTRCALL_HPP
#include <gdextension_interface.h>
@@ -55,10 +56,10 @@ O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, co
template <typename R, typename... Args>
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
typename PtrToArg<R>::EncodeT ret;
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 static_cast<R>(ret);
return ret;
}
template <typename... Args>
@@ -69,10 +70,10 @@ void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, c
template <typename R, typename... Args>
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
typename PtrToArg<R>::EncodeT ret;
R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(&ret, mb_args.data(), mb_args.size());
return static_cast<R>(ret);
return ret;
}
template <typename... Args>
@@ -92,3 +93,5 @@ void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &
} // namespace internal
} // namespace godot
#endif // GODOT_ENGINE_PTRCALL_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_ERROR_MACROS_HPP
#define GODOT_ERROR_MACROS_HPP
#include <godot_cpp/core/defs.hpp>
@@ -801,3 +802,5 @@ void _err_flush_stdout();
#define CHECK_METHOD_BIND_RET(m_mb, m_ret)
#define CHECK_METHOD_BIND(m_mb)
#endif
#endif // GODOT_ERROR_MACROS_HPP

View File

@@ -1,51 +0,0 @@
/**************************************************************************/
/* math.compat.inc */
/**************************************************************************/
/* 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 DISABLE_DEPRECATED
namespace godot {
#undef ABS
// Generic ABS function, for math uses please use Math::abs.
template <typename T>
[[deprecated("Use Math::abs instead")]]
constexpr T ABS(T m_v) {
return m_v < 0 ? -m_v : m_v;
}
}
// To maintain compatibility an alias is defined outside the namespace.
// Consider it deprecated.
using real_t = godot::real_t;
#endif

View File

@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_MATH_HPP
#define GODOT_MATH_HPP
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/math_defs.hpp>
#include <gdextension_interface.h>
@@ -39,8 +39,185 @@
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 <typename 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 <typename 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.
@@ -361,26 +538,6 @@ inline float bezier_interpolate(float p_start, float p_control_1, float p_contro
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3;
}
inline double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
/* Formula from Wikipedia article on Bezier curves. */
double omt = (1.0 - p_t);
double omt2 = omt * omt;
double t2 = p_t * p_t;
double d = (p_control_1 - p_start) * 3.0 * omt2 + (p_control_2 - p_control_1) * 6.0 * omt * p_t + (p_end - p_control_2) * 3.0 * t2;
return d;
}
inline float bezier_derivative(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
/* Formula from Wikipedia article on Bezier curves. */
float omt = (1.0f - p_t);
float omt2 = omt * omt;
float t2 = p_t * p_t;
float d = (p_control_1 - p_start) * 3.0f * omt2 + (p_control_2 - p_control_1) * 6.0f * omt * p_t + (p_end - p_control_2) * 3.0f * t2;
return d;
}
template <typename T>
inline T clamp(T x, T minv, T maxv) {
if (x < minv) {
@@ -456,14 +613,6 @@ inline bool is_inf(double p_val) {
return std::isinf(p_val);
}
inline bool is_finite(float p_val) {
return std::isfinite(p_val);
}
inline bool is_finite(double p_val) {
return std::isfinite(p_val);
}
inline bool is_equal_approx(float a, float b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
@@ -659,4 +808,4 @@ inline float snap_scalar_separation(float p_offset, float p_step, float p_target
} // namespace Math
} // namespace godot
#include "math.compat.inc"
#endif // GODOT_MATH_HPP

View File

@@ -1,74 +0,0 @@
/**************************************************************************/
/* math_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. */
/**************************************************************************/
#pragma once
namespace godot {
#define CMP_EPSILON 0.00001
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
#define CMP_NORMALIZE_TOLERANCE 0.000001
#define CMP_POINT_IN_PLANE_EPSILON 0.00001
#define Math_SQRT12 0.7071067811865475244008443621048490
#define Math_SQRT2 1.4142135623730950488016887242
#define Math_LN2 0.6931471805599453094172321215
#define Math_TAU 6.2831853071795864769252867666
#define Math_PI 3.1415926535897932384626433833
#define Math_E 2.7182818284590452353602874714
#define Math_INF INFINITY
#define Math_NAN NAN
#ifdef DEBUG_ENABLED
#define MATH_CHECKS
#endif
//this epsilon is for values related to a unit size (scalar or vector len)
#ifdef PRECISE_MATH_CHECKS
#define UNIT_EPSILON 0.00001
#else
//tolerate some more floating point error normally
#define UNIT_EPSILON 0.001
#endif
#define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0)
/**
* The "Real" type is an abstract type used for real numbers, such as 1.5,
* in contrast to integer numbers. Precision can be controlled with the
* presence or absence of the REAL_T_IS_DOUBLE define.
*/
#ifdef REAL_T_IS_DOUBLE
typedef double real_t;
#else
typedef float real_t;
#endif
} // namespace godot

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_MEMORY_HPP
#define GODOT_MEMORY_HPP
#include <cstddef>
#include <cstdint>
@@ -39,21 +40,20 @@
#include <type_traits>
// p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS.
void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
_ALWAYS_INLINE_ void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) {
_ALWAYS_INLINE_ void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description) {
return p_pointer;
}
#ifdef _MSC_VER
// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291).
// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete.
void operator delete(void *p_mem, const char *p_dummy, const char *p_description);
void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size));
void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description);
void operator delete(void *p_mem, const char *p_description);
void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size));
void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description);
#endif
namespace godot {
@@ -81,9 +81,6 @@ public:
static void free_static(void *p_ptr, bool p_pad_align = false);
};
template <typename T, std::enable_if_t<!std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
_ALWAYS_INLINE_ void _pre_initialize() {}
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
template <typename T>
@@ -96,10 +93,16 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
#define memnew(m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", "") m_class))
#define memnew(m_class) ::godot::_post_initialize(new ("") m_class)
#define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class))
#define memnew_placement(m_placement, m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class))
#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new (m_allocator::alloc) m_class)
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new (m_placement, sizeof(m_class), "") m_class)
// Generic comparator used in Map, List, etc.
template <typename T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
template <typename T>
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) {
@@ -165,7 +168,7 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
/* call operator new */
for (size_t i = 0; i < p_elements; i++) {
new ("", &elems[i], sizeof(T), p_descr) T;
new (&elems[i], sizeof(T), p_descr) T;
}
}
@@ -209,3 +212,5 @@ struct _GlobalNilClass {
};
} // namespace godot
#endif // GODOT_MEMORY_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_METHOD_BIND_HPP
#define GODOT_METHOD_BIND_HPP
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/type_info.hpp>
@@ -38,40 +39,44 @@
#include <gdextension_interface.h>
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/templates/local_vector.hpp>
#include <string>
#include <vector>
#include <iostream>
namespace godot {
class MethodBind {
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
StringName name;
StringName instance_class;
int argument_count = 0;
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
bool _static = false;
bool _const = false;
bool _returns = false;
bool _is_const = false;
bool _has_return = false;
bool _vararg = false;
LocalVector<StringName> argument_names;
std::vector<StringName> argument_names;
GDExtensionVariantType *argument_types = nullptr;
LocalVector<Variant> default_arguments;
std::vector<Variant> default_arguments;
protected:
void _set_const(bool p_const);
void _set_static(bool p_static);
void _set_returns(bool p_returns);
void _set_vararg(bool p_vararg);
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_argument_count(int p_count) { argument_count = p_count; }
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:
_FORCE_INLINE_ const LocalVector<Variant> &get_default_arguments() const { return default_arguments; }
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);
@@ -92,6 +97,19 @@ public:
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);
@@ -99,9 +117,10 @@ public:
}
PropertyInfo get_argument_info(int p_argument) const;
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
LocalVector<PropertyInfo> get_arguments_info_list() const {
LocalVector<PropertyInfo> vec;
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++) {
@@ -109,41 +128,19 @@ public:
}
return vec;
}
void set_argument_names(const LocalVector<StringName> &p_names);
LocalVector<StringName> get_argument_names() const;
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
_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_ 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; }
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;
StringName get_name() const;
void set_name(const StringName &p_name);
_FORCE_INLINE_ bool is_const() const { return _const; }
_FORCE_INLINE_ bool is_static() const { return _static; }
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
_FORCE_INLINE_ bool has_return() const { return _returns; }
void set_default_arguments(const LocalVector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
LocalVector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
LocalVector<GDExtensionClassMethodArgumentMetadata> 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 + 1; i++) {
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);
@@ -153,8 +150,9 @@ public:
template <typename Derived, typename T, typename R, bool should_returns>
class MethodBindVarArgBase : public MethodBind {
protected:
R (T::*method)(const Variant **, GDExtensionInt, GDExtensionCallError &);
LocalVector<PropertyInfo> arguments;
R(T::*method)
(const Variant **, GDExtensionInt, GDExtensionCallError &);
std::vector<PropertyInfo> arguments;
public:
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
@@ -184,13 +182,13 @@ public:
const MethodInfo &p_method_info,
bool p_return_nil_is_variant) :
method(p_method) {
_set_vararg(true);
_set_const(true);
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;
LocalVector<StringName> names;
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);
@@ -198,8 +196,8 @@ public:
set_argument_names(names);
}
_generate_argument_types((int)p_method_info.arguments.size());
_set_returns(should_returns);
generate_argument_types((int)p_method_info.arguments.size());
set_return(should_returns);
}
~MethodBindVarArgBase() {}
@@ -336,7 +334,7 @@ public:
MethodBindT(void (MB_T::*p_method)(P...)) {
method = p_method;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
}
};
@@ -412,9 +410,8 @@ public:
MethodBindTC(void (MB_T::*p_method)(P...) const) {
method = p_method;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_const(true);
}
};
@@ -437,7 +434,8 @@ template <typename T, typename R, typename... P>
template <typename R, typename... P>
#endif // TYPED_METHOD_BIND
class MethodBindTR : public MethodBind {
R (MB_T::*method)(P...);
R(MB_T::*method)
(P...);
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
@@ -494,9 +492,9 @@ public:
MethodBindTR(R (MB_T::*p_method)(P...)) {
method = p_method;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_returns(true);
set_return(true);
}
};
@@ -519,7 +517,8 @@ template <typename T, typename R, typename... P>
template <typename R, typename... P>
#endif // TYPED_METHOD_BIND
class MethodBindTRC : public MethodBind {
R (MB_T::*method)(P...) const;
R(MB_T::*method)
(P...) const;
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
@@ -576,10 +575,9 @@ public:
MethodBindTRC(R (MB_T::*p_method)(P...) const) {
method = p_method;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_returns(true);
_set_const(true);
set_return(true);
}
};
@@ -648,9 +646,9 @@ public:
MethodBindTS(void (*p_function)(P...)) {
function = p_function;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_static(true);
set_static(true);
}
};
@@ -664,7 +662,8 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) {
template <typename R, typename... P>
class MethodBindTRS : public MethodBind {
R (*function)(P...);
R(*function)
(P...);
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
@@ -716,10 +715,10 @@ public:
MethodBindTRS(R (*p_function)(P...)) {
function = p_function;
_generate_argument_types(sizeof...(P));
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
_set_static(true);
_set_returns(true);
set_static(true);
set_return(true);
}
};
@@ -730,3 +729,5 @@ MethodBind *create_static_method_bind(R (*p_method)(P...)) {
}
} // namespace godot
#endif // GODOT_METHOD_BIND_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_METHOD_PTRCALL_HPP
#define GODOT_METHOD_PTRCALL_HPP
#include <godot_cpp/core/defs.hpp>
@@ -121,9 +122,6 @@ MAKE_PTRARGCONV(uint16_t, int64_t);
MAKE_PTRARGCONV(int16_t, int64_t);
MAKE_PTRARGCONV(uint32_t, int64_t);
MAKE_PTRARGCONV(int32_t, int64_t);
MAKE_PTRARGCONV(char16_t, int64_t);
MAKE_PTRARGCONV(char32_t, int64_t);
MAKE_PTRARGCONV(wchar_t, int64_t);
MAKE_PTRARG(int64_t);
MAKE_PTRARG(uint64_t);
// Float types
@@ -163,7 +161,6 @@ MAKE_PTRARG(PackedFloat64Array);
MAKE_PTRARG(PackedStringArray);
MAKE_PTRARG(PackedVector2Array);
MAKE_PTRARG(PackedVector3Array);
MAKE_PTRARG(PackedVector4Array);
MAKE_PTRARG(PackedColorArray);
MAKE_PTRARG_BY_REFERENCE(Variant);
@@ -173,11 +170,11 @@ template <typename T>
struct PtrToArg<T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
return likely(p_ptr) ? reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))) : nullptr;
return reinterpret_cast<T *>(godot::internal::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) = likely(p_var) ? p_var->_owner : nullptr;
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
}
};
@@ -185,11 +182,11 @@ template <typename T>
struct PtrToArg<const T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
return likely(p_ptr) ? reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))) : nullptr;
return reinterpret_cast<const T *>(godot::internal::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) = likely(p_var) ? p_var->_owner : nullptr;
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
}
};
@@ -236,3 +233,5 @@ GDVIRTUAL_NATIVE_PTR(float);
GDVIRTUAL_NATIVE_PTR(double);
} // namespace godot
#endif // GODOT_METHOD_PTRCALL_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_MUTEX_LOCK_HPP
#define GODOT_MUTEX_LOCK_HPP
#include <godot_cpp/classes/mutex.hpp>
@@ -54,3 +55,5 @@ public:
#define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock();
} // namespace godot
#endif // GODOT_MUTEX_LOCK_HPP

View File

@@ -28,29 +28,27 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#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/templates/local_vector.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 {
@@ -65,10 +63,8 @@ struct MethodInfo {
PropertyInfo return_val;
uint32_t flags;
int id = 0;
LocalVector<PropertyInfo> arguments;
LocalVector<Variant> default_arguments;
GDExtensionClassMethodArgumentMetadata return_val_metadata;
LocalVector<GDExtensionClassMethodArgumentMetadata> arguments_metadata;
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); }
@@ -92,19 +88,45 @@ struct MethodInfo {
template <typename... Args>
MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {}
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
template <typename... Args>
MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
return_val.type = ret;
arguments = { args... };
}
template <typename... Args>
MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) :
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL), arguments({ args... }) {
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
class ObjectID {
uint64_t id = 0;
public:
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
_FORCE_INLINE_ bool is_null() const { return id == 0; }
_FORCE_INLINE_ operator uint64_t() const { return id; }
_FORCE_INLINE_ operator int64_t() const { return id; }
_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
_FORCE_INLINE_ ObjectID() {}
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};
class ObjectDB {
public:
static Object *get_instance(uint64_t p_object_id) {
@@ -143,3 +165,5 @@ const T *Object::cast_to(const Object *p_object) {
}
} // namespace godot
#endif // GODOT_OBJECT_HPP

View File

@@ -1,59 +0,0 @@
/**************************************************************************/
/* object_id.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#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

View File

@@ -1,70 +0,0 @@
/**************************************************************************/
/* print_string.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include <godot_cpp/variant/utility_functions.hpp>
namespace godot {
inline void print_error(const Variant &p_variant) {
UtilityFunctions::printerr(p_variant);
}
inline void print_line(const Variant &p_variant) {
UtilityFunctions::print(p_variant);
}
inline void print_line_rich(const Variant &p_variant) {
UtilityFunctions::print_rich(p_variant);
}
template <typename... Args>
void print_error(const Variant &p_variant, Args... p_args) {
UtilityFunctions::printerr(p_variant, p_args...);
}
template <typename... Args>
void print_line(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print(p_variant, p_args...);
}
template <typename... Args>
void print_line_rich(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print_rich(p_variant, p_args...);
}
template <typename... Args>
void print_verbose(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print_verbose(p_variant, p_args...);
}
bool is_print_verbose_enabled();
} // namespace godot

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_PROPERTY_INFO_HPP
#define GODOT_PROPERTY_INFO_HPP
#include <godot_cpp/core/defs.hpp>
@@ -67,63 +68,8 @@ struct PropertyInfo {
PropertyInfo(GDExtensionVariantType p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {}
PropertyInfo(const GDExtensionPropertyInfo *p_info) :
PropertyInfo(p_info->type, *reinterpret_cast<StringName *>(p_info->name), (PropertyHint)p_info->hint, *reinterpret_cast<String *>(p_info->hint_string), p_info->usage, *reinterpret_cast<StringName *>(p_info->class_name)) {}
operator Dictionary() const {
Dictionary dict;
dict["name"] = name;
dict["class_name"] = class_name;
dict["type"] = type;
dict["hint"] = hint;
dict["hint_string"] = hint_string;
dict["usage"] = usage;
return dict;
}
static PropertyInfo from_dict(const Dictionary &p_dict) {
PropertyInfo pi;
if (p_dict.has("type")) {
pi.type = Variant::Type(int(p_dict["type"]));
}
if (p_dict.has("name")) {
pi.name = p_dict["name"];
}
if (p_dict.has("class_name")) {
pi.class_name = p_dict["class_name"];
}
if (p_dict.has("hint")) {
pi.hint = PropertyHint(int(p_dict["hint"]));
}
if (p_dict.has("hint_string")) {
pi.hint_string = p_dict["hint_string"];
}
if (p_dict.has("usage")) {
pi.usage = p_dict["usage"];
}
return pi;
}
void _update(GDExtensionPropertyInfo *p_info) {
p_info->type = (GDExtensionVariantType)type;
*(reinterpret_cast<StringName *>(p_info->name)) = name;
p_info->hint = hint;
*(reinterpret_cast<String *>(p_info->hint_string)) = hint_string;
p_info->usage = usage;
*(reinterpret_cast<StringName *>(p_info->class_name)) = class_name;
}
GDExtensionPropertyInfo _to_gdextension() const {
return {
(GDExtensionVariantType)type,
name._native_ptr(),
class_name._native_ptr(),
hint,
hint_string._native_ptr(),
usage,
};
}
};
} // namespace godot
#endif // GODOT_PROPERTY_INFO_HPP

View File

@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_TYPE_INFO_HPP
#define GODOT_TYPE_INFO_HPP
#include <godot_cpp/core/method_ptrcall.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/variant/typed_array.hpp>
#include <godot_cpp/variant/variant.hpp>
@@ -58,16 +58,6 @@ struct TypesAreSame<A, A> {
static bool const value = true;
};
template <auto A, auto B>
struct FunctionsAreSame {
static bool const value = false;
};
template <auto A>
struct FunctionsAreSame<A, A> {
static bool const value = true;
};
template <typename B, typename D>
struct TypeInherits {
static D *get_d();
@@ -148,8 +138,8 @@ MAKE_TYPE_INFO_WITH_META(uint32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_MET
MAKE_TYPE_INFO_WITH_META(int32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32)
MAKE_TYPE_INFO_WITH_META(uint64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64)
MAKE_TYPE_INFO_WITH_META(int64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64)
MAKE_TYPE_INFO_WITH_META(char16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR16)
MAKE_TYPE_INFO_WITH_META(char32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32)
MAKE_TYPE_INFO(char16_t, GDEXTENSION_VARIANT_TYPE_INT)
MAKE_TYPE_INFO(char32_t, GDEXTENSION_VARIANT_TYPE_INT)
MAKE_TYPE_INFO_WITH_META(float, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT)
MAKE_TYPE_INFO_WITH_META(double, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE)
@@ -185,7 +175,6 @@ MAKE_TYPE_INFO(PackedFloat64Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY
MAKE_TYPE_INFO(PackedStringArray, GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY)
MAKE_TYPE_INFO(PackedVector2Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY)
MAKE_TYPE_INFO(PackedVector3Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY)
MAKE_TYPE_INFO(PackedVector4Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR4_ARRAY)
MAKE_TYPE_INFO(PackedColorArray, GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY)
// For variant.
@@ -209,8 +198,8 @@ struct GetTypeInfo<const Variant &> {
template <typename T>
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
@@ -218,8 +207,8 @@ struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type>
template <typename T>
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
@@ -237,8 +226,8 @@ inline String enum_qualified_name_to_class_info_name(const String &p_qualified_n
#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -275,8 +264,8 @@ public:
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -284,8 +273,8 @@ public:
}; \
template <> \
struct GetTypeInfo<BitField<m_impl>> { \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -381,14 +370,11 @@ MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY_INFO(Vector4, Variant::VECTOR4)
MAKE_TYPED_ARRAY_INFO(Vector4i, Variant::VECTOR4I)
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY_INFO(Projection, Variant::PROJECTION)
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
@@ -397,22 +383,20 @@ MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
/*
MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
MAKE_TYPED_ARRAY_INFO(Vector<uint8_t>, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<int32_t>, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<int64_t>, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<float>, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<double>, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<String>, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
*/
#undef MAKE_TYPED_ARRAY_INFO
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
} // namespace godot
#endif // GODOT_TYPE_INFO_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_GODOT_HPP
#define GODOT_GODOT_HPP
#include <gdextension_interface.h>
@@ -40,10 +41,10 @@ extern "C" GDExtensionInterfaceGetProcAddress gdextension_interface_get_proc_add
extern "C" GDExtensionClassLibraryPtr library;
extern "C" void *token;
extern "C" GDExtensionGodotVersion2 godot_version;
extern "C" GDExtensionGodotVersion godot_version;
// All of the GDExtension interface functions.
extern "C" GDExtensionInterfaceGetGodotVersion2 gdextension_interface_get_godot_version2;
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;
@@ -81,13 +82,11 @@ extern "C" GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_
extern "C" GDExtensionInterfaceVariantHasMethod gdextension_interface_variant_has_method;
extern "C" GDExtensionInterfaceVariantHasMember gdextension_interface_variant_has_member;
extern "C" GDExtensionInterfaceVariantHasKey gdextension_interface_variant_has_key;
extern "C" GDExtensionInterfaceVariantGetObjectInstanceId gdextension_interface_variant_get_object_instance_id;
extern "C" GDExtensionInterfaceVariantGetTypeName gdextension_interface_variant_get_type_name;
extern "C" GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert;
extern "C" GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict;
extern "C" GDExtensionInterfaceGetVariantFromTypeConstructor gdextension_interface_get_variant_from_type_constructor;
extern "C" GDExtensionInterfaceGetVariantToTypeConstructor gdextension_interface_get_variant_to_type_constructor;
extern "C" GDExtensionInterfaceGetVariantGetInternalPtrFunc gdextension_interface_variant_get_ptr_internal_getter;
extern "C" GDExtensionInterfaceVariantGetPtrOperatorEvaluator gdextension_interface_variant_get_ptr_operator_evaluator;
extern "C" GDExtensionInterfaceVariantGetPtrBuiltinMethod gdextension_interface_variant_get_ptr_builtin_method;
extern "C" GDExtensionInterfaceVariantGetPtrConstructor gdextension_interface_variant_get_ptr_constructor;
@@ -109,9 +108,7 @@ extern "C" GDExtensionInterfaceStringNewWithUtf32Chars gdextension_interface_str
extern "C" GDExtensionInterfaceStringNewWithWideChars gdextension_interface_string_new_with_wide_chars;
extern "C" GDExtensionInterfaceStringNewWithLatin1CharsAndLen gdextension_interface_string_new_with_latin1_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen gdextension_interface_string_new_with_utf8_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen2 gdextension_interface_string_new_with_utf8_chars_and_len2;
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen gdextension_interface_string_new_with_utf16_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen2 gdextension_interface_string_new_with_utf16_chars_and_len2;
extern "C" GDExtensionInterfaceStringNewWithUtf32CharsAndLen gdextension_interface_string_new_with_utf32_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithWideCharsAndLen gdextension_interface_string_new_with_wide_chars_and_len;
extern "C" GDExtensionInterfaceStringToLatin1Chars gdextension_interface_string_to_latin1_chars;
@@ -126,8 +123,6 @@ extern "C" GDExtensionInterfaceStringOperatorPlusEqChar gdextension_interface_st
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;
@@ -151,46 +146,33 @@ extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndex gdextension_inter
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndexConst gdextension_interface_packed_vector2_array_operator_index_const;
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndex gdextension_interface_packed_vector3_array_operator_index;
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndexConst gdextension_interface_packed_vector3_array_operator_index_const;
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndex gdextension_interface_packed_vector4_array_operator_index;
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndexConst gdextension_interface_packed_vector4_array_operator_index_const;
extern "C" GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index;
extern "C" GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const;
extern "C" GDExtensionInterfaceArrayRef gdextension_interface_array_ref;
extern "C" GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed;
extern "C" GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index;
extern "C" GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const;
extern "C" GDExtensionInterfaceDictionarySetTyped gdextension_interface_dictionary_set_typed;
extern "C" GDExtensionInterfaceObjectMethodBindCall gdextension_interface_object_method_bind_call;
extern "C" GDExtensionInterfaceObjectMethodBindPtrcall gdextension_interface_object_method_bind_ptrcall;
extern "C" GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy;
extern "C" GDExtensionInterfaceGlobalGetSingleton gdextension_interface_global_get_singleton;
extern "C" GDExtensionInterfaceObjectGetInstanceBinding gdextension_interface_object_get_instance_binding;
extern "C" GDExtensionInterfaceObjectSetInstanceBinding gdextension_interface_object_set_instance_binding;
extern "C" GDExtensionInterfaceObjectFreeInstanceBinding gdextension_interface_object_free_instance_binding;
extern "C" GDExtensionInterfaceObjectSetInstance gdextension_interface_object_set_instance;
extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_name;
extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to;
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
extern "C" GDExtensionInterfaceObjectHasScriptMethod gdextension_interface_object_has_script_method;
extern "C" GDExtensionInterfaceObjectCallScriptMethod gdextension_interface_object_call_script_method;
extern "C" GDExtensionInterfaceCallableCustomCreate2 gdextension_interface_callable_custom_create2;
extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata;
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object;
extern "C" GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update;
extern "C" GDExtensionInterfaceObjectGetScriptInstance gdextension_interface_object_get_script_instance;
extern "C" GDExtensionInterfaceObjectSetScriptInstance gdextension_interface_object_set_script_instance;
extern "C" GDExtensionInterfaceClassdbConstructObject2 gdextension_interface_classdb_construct_object2;
extern "C" GDExtensionInterfaceScriptInstanceCreate gdextension_interface_script_instance_create;
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" GDExtensionInterfaceClassdbRegisterExtensionClass5 gdextension_interface_classdb_register_extension_class5;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass gdextension_interface_classdb_register_extension_class;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup gdextension_interface_classdb_register_extension_class_property_group;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup gdextension_interface_classdb_register_extension_class_property_subgroup;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassSignal gdextension_interface_classdb_register_extension_class_signal;
@@ -198,17 +180,6 @@ extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_inter
extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path;
extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin;
extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin;
extern "C" GDExtensionInterfaceEditorRegisterGetClassesUsedCallback gdextension_interface_editor_register_get_classes_used_callback;
extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars;
extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len;
extern "C" GDExtensionInterfaceImagePtrw gdextension_interface_image_ptrw;
extern "C" GDExtensionInterfaceImagePtr gdextension_interface_image_ptr;
extern "C" GDExtensionInterfaceRegisterMainLoopCallbacks gdextension_interface_register_main_loop_callbacks;
class DocDataRegistration {
public:
DocDataRegistration(const char *p_hash, int p_uncompressed_size, int p_compressed_size, const unsigned char *p_data);
};
} // namespace internal
@@ -228,11 +199,6 @@ public:
GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
Callback init_callback = nullptr;
Callback terminate_callback = nullptr;
GDExtensionMainLoopCallbacks main_loop_callbacks = {};
inline bool has_main_loop_callbacks() const {
return main_loop_callbacks.frame_func || main_loop_callbacks.startup_func || main_loop_callbacks.shutdown_func;
}
};
class InitDataList {
@@ -267,15 +233,10 @@ public:
void register_terminator(Callback p_init) const;
void set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const;
// Register a callback that is called after all initialization levels when Godot is fully initialized.
void register_startup_callback(GDExtensionMainLoopStartupCallback p_callback) const;
// Register a callback that is called for every process frame. This will run after all `_process()` methods on Node, and before `ScriptServer::frame()`.
void register_frame_callback(GDExtensionMainLoopFrameCallback p_callback) const;
// Register a callback that is called before Godot is shutdown when it is still fully initialized.
void register_shutdown_callback(GDExtensionMainLoopShutdownCallback p_callback) const;
GDExtensionBool init() const;
};
};
} // namespace godot
#endif // GODOT_GODOT_HPP

View File

@@ -1,734 +0,0 @@
/**************************************************************************/
/* a_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. */
/**************************************************************************/
#pragma once
#include <godot_cpp/templates/hash_map.hpp>
namespace godot {
struct HashMapData {
union {
uint64_t data;
struct
{
uint32_t hash;
uint32_t hash_to_key;
};
};
};
static_assert(sizeof(HashMapData) == 8);
/**
* An array-based implementation of a hash map. It is very efficient in terms of performance and
* memory usage. Works like a dynamic array, adding elements to the end of the array, and
* allows you to access array elements by their index by using `get_by_index` method.
* Example:
* ```
* AHashMap<int, Object *> map;
*
* int get_object_id_by_number(int p_number) {
* int id = map.get_index(p_number);
* return id;
* }
*
* Object *get_object_by_id(int p_id) {
* map.get_by_index(p_id).value;
* }
* ```
* Still, don`t erase the elements because ID can break.
*
* When an element erase, its place is taken by the element from the end.
*
* <-------------
* | |
* 6 8 X 9 32 -1 5 -10 7 X X X
* 6 8 7 9 32 -1 5 -10 X X X X
*
*
* Use RBMap if you need to iterate over sorted elements.
*
* Use HashMap if:
* - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
* - You need to preserve the insertion order when using erase.
*
* It is recommended to use `HashMap` if `KeyValue` size is very large.
*/
template <typename TKey, typename TValue,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>>
class AHashMap {
public:
// Must be a power of two.
static constexpr uint32_t INITIAL_CAPACITY = 16;
static constexpr uint32_t EMPTY_HASH = 0;
static_assert(EMPTY_HASH == 0, "EMPTY_HASH must always be 0 for the memcpy() optimization.");
private:
typedef KeyValue<TKey, TValue> MapKeyValue;
MapKeyValue *elements = nullptr;
HashMapData *map_data = nullptr;
// Due to optimization, this is `capacity - 1`. Use + 1 to get normal capacity.
uint32_t capacity = 0;
uint32_t num_elements = 0;
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;
}
static _FORCE_INLINE_ uint32_t _get_resize_count(uint32_t p_capacity) {
return p_capacity ^ (p_capacity + 1) >> 2; // = get_capacity() * 0.75 - 1; Works only if p_capacity = 2^n - 1.
}
static _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_local_capacity) {
const uint32_t original_pos = p_hash & p_local_capacity;
return (p_pos - original_pos + p_local_capacity + 1) & p_local_capacity;
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos) const {
if (unlikely(elements == nullptr)) {
return false; // Failed lookups, no elements.
}
return _lookup_pos_with_hash(p_key, r_pos, r_hash_pos, _hash(p_key));
}
bool _lookup_pos_with_hash(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos, uint32_t p_hash) const {
if (unlikely(elements == nullptr)) {
return false; // Failed lookups, no elements.
}
uint32_t pos = p_hash & capacity;
HashMapData data = map_data[pos];
if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
r_pos = data.hash_to_key;
r_hash_pos = pos;
return true;
}
if (data.data == EMPTY_HASH) {
return false;
}
// A collision occurred.
pos = (pos + 1) & capacity;
uint32_t distance = 1;
while (true) {
data = map_data[pos];
if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
r_pos = data.hash_to_key;
r_hash_pos = pos;
return true;
}
if (data.data == EMPTY_HASH) {
return false;
}
if (distance > _get_probe_length(pos, data.hash, capacity)) {
return false;
}
pos = (pos + 1) & capacity;
distance++;
}
}
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
uint32_t pos = p_hash & capacity;
if (map_data[pos].data == EMPTY_HASH) {
uint64_t data = ((uint64_t)p_index << 32) | p_hash;
map_data[pos].data = data;
return pos;
}
uint32_t distance = 1;
pos = (pos + 1) & capacity;
HashMapData c_data;
c_data.hash = p_hash;
c_data.hash_to_key = p_index;
while (true) {
if (map_data[pos].data == EMPTY_HASH) {
#ifdef DEV_ENABLED
if (unlikely(distance > 12)) {
WARN_PRINT("Excessive collision count (" +
itos(distance) + "), is the right hash function being used?");
}
#endif
map_data[pos] = c_data;
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, map_data[pos].hash, capacity);
if (existing_probe_len < distance) {
SWAP(c_data, map_data[pos]);
distance = existing_probe_len;
}
pos = (pos + 1) & capacity;
distance++;
}
}
void _resize_and_rehash(uint32_t p_new_capacity) {
uint32_t real_old_capacity = capacity + 1;
// Capacity can't be 0 and must be 2^n - 1.
capacity = MAX(4u, p_new_capacity);
uint32_t real_capacity = next_power_of_2(capacity);
capacity = real_capacity - 1;
HashMapData *old_map_data = map_data;
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
memset(map_data, 0, sizeof(HashMapData) * real_capacity);
elements = reinterpret_cast<MapKeyValue *>(Memory::realloc_static(elements, sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
if (num_elements != 0) {
for (uint32_t i = 0; i < real_old_capacity; i++) {
HashMapData data = old_map_data[i];
if (data.data != EMPTY_HASH) {
_insert_with_hash(data.hash, data.hash_to_key);
}
}
}
Memory::free_static(old_map_data);
}
int32_t _insert_element(const TKey &p_key, const TValue &p_value, uint32_t p_hash) {
if (unlikely(elements == nullptr)) {
// Allocate on demand to save memory.
uint32_t real_capacity = capacity + 1;
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
memset(map_data, 0, sizeof(HashMapData) * real_capacity);
elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
}
if (unlikely(num_elements > _get_resize_count(capacity))) {
_resize_and_rehash(capacity * 2);
}
memnew_placement(&elements[num_elements], MapKeyValue(p_key, p_value));
_insert_with_hash(p_hash, num_elements);
num_elements++;
return num_elements - 1;
}
void _init_from(const AHashMap &p_other) {
capacity = p_other.capacity;
uint32_t real_capacity = capacity + 1;
num_elements = p_other.num_elements;
if (p_other.num_elements == 0) {
return;
}
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
if constexpr (std::is_trivially_copyable_v<TKey> && std::is_trivially_copyable_v<TValue>) {
void *destination = elements;
const void *source = p_other.elements;
memcpy(destination, source, sizeof(MapKeyValue) * num_elements);
} else {
for (uint32_t i = 0; i < num_elements; i++) {
memnew_placement(&elements[i], MapKeyValue(p_other.elements[i]));
}
}
memcpy(map_data, p_other.map_data, sizeof(HashMapData) * real_capacity);
}
public:
/* Standard Godot Container API */
_FORCE_INLINE_ uint32_t get_capacity() const { return capacity + 1; }
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
_FORCE_INLINE_ bool is_empty() const {
return num_elements == 0;
}
void clear() {
if (elements == nullptr || num_elements == 0) {
return;
}
memset(map_data, EMPTY_HASH, (capacity + 1) * sizeof(HashMapData));
if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
for (uint32_t i = 0; i < num_elements; i++) {
elements[i].key.~TKey();
elements[i].value.~TValue();
}
}
num_elements = 0;
}
TValue &get(const TKey &p_key) {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
CRASH_COND_MSG(!exists, "AHashMap key not found.");
return elements[pos].value;
}
const TValue &get(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
CRASH_COND_MSG(!exists, "AHashMap key not found.");
return elements[pos].value;
}
const TValue *getptr(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
if (exists) {
return &elements[pos].value;
}
return nullptr;
}
TValue *getptr(const TKey &p_key) {
uint32_t pos = 0;
uint32_t hash_pos = 0;
bool exists = _lookup_pos(p_key, pos, hash_pos);
if (exists) {
return &elements[pos].value;
}
return nullptr;
}
bool has(const TKey &p_key) const {
uint32_t _pos = 0;
uint32_t h_pos = 0;
return _lookup_pos(p_key, _pos, h_pos);
}
bool erase(const TKey &p_key) {
uint32_t pos = 0;
uint32_t element_pos = 0;
bool exists = _lookup_pos(p_key, element_pos, pos);
if (!exists) {
return false;
}
uint32_t next_pos = (pos + 1) & capacity;
while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
SWAP(map_data[next_pos], map_data[pos]);
pos = next_pos;
next_pos = (next_pos + 1) & capacity;
}
map_data[pos].data = EMPTY_HASH;
elements[element_pos].key.~TKey();
elements[element_pos].value.~TValue();
num_elements--;
if (element_pos < num_elements) {
void *destination = &elements[element_pos];
const void *source = &elements[num_elements];
memcpy(destination, source, sizeof(MapKeyValue));
uint32_t h_pos = 0;
_lookup_pos(elements[num_elements].key, pos, h_pos);
map_data[h_pos].hash_to_key = element_pos;
}
return true;
}
// Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
// p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
if (p_old_key == p_new_key) {
return true;
}
uint32_t pos = 0;
uint32_t element_pos = 0;
ERR_FAIL_COND_V(_lookup_pos(p_new_key, element_pos, pos), false);
ERR_FAIL_COND_V(!_lookup_pos(p_old_key, element_pos, pos), false);
MapKeyValue &element = elements[element_pos];
const_cast<TKey &>(element.key) = p_new_key;
uint32_t next_pos = (pos + 1) & capacity;
while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
SWAP(map_data[next_pos], map_data[pos]);
pos = next_pos;
next_pos = (next_pos + 1) & capacity;
}
map_data[pos].data = EMPTY_HASH;
uint32_t hash = _hash(p_new_key);
_insert_with_hash(hash, element_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) {
ERR_FAIL_COND_MSG(p_new_capacity < size(), "reserve() called with a capacity smaller than the current size. This is likely a mistake.");
if (elements == nullptr) {
capacity = MAX(4u, p_new_capacity);
capacity = next_power_of_2(capacity) - 1;
return; // Unallocated yet.
}
if (p_new_capacity <= get_capacity()) {
return;
}
_resize_and_rehash(p_new_capacity);
}
/** Iterator API **/
struct ConstIterator {
_FORCE_INLINE_ const MapKeyValue &operator*() const {
return *pair;
}
_FORCE_INLINE_ const MapKeyValue *operator->() const {
return pair;
}
_FORCE_INLINE_ ConstIterator &operator++() {
pair++;
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
pair--;
if (pair < begin) {
pair = end;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return pair == b.pair; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return pair != b.pair; }
_FORCE_INLINE_ explicit operator bool() const {
return pair != end;
}
_FORCE_INLINE_ ConstIterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
pair = p_key;
begin = p_begin;
end = p_end;
}
_FORCE_INLINE_ ConstIterator() {}
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
_FORCE_INLINE_ void operator=(const ConstIterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
private:
MapKeyValue *pair = nullptr;
MapKeyValue *begin = nullptr;
MapKeyValue *end = nullptr;
};
struct Iterator {
_FORCE_INLINE_ MapKeyValue &operator*() const {
return *pair;
}
_FORCE_INLINE_ MapKeyValue *operator->() const {
return pair;
}
_FORCE_INLINE_ Iterator &operator++() {
pair++;
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
pair--;
if (pair < begin) {
pair = end;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return pair == b.pair; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return pair != b.pair; }
_FORCE_INLINE_ explicit operator bool() const {
return pair != end;
}
_FORCE_INLINE_ Iterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
pair = p_key;
begin = p_begin;
end = p_end;
}
_FORCE_INLINE_ Iterator() {}
_FORCE_INLINE_ Iterator(const Iterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
pair = p_it.pair;
begin = p_it.begin;
end = p_it.end;
}
operator ConstIterator() const {
return ConstIterator(pair, begin, end);
}
private:
MapKeyValue *pair = nullptr;
MapKeyValue *begin = nullptr;
MapKeyValue *end = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(elements, elements, elements + num_elements);
}
_FORCE_INLINE_ Iterator end() {
return Iterator(elements + num_elements, elements, elements + num_elements);
}
_FORCE_INLINE_ Iterator last() {
if (unlikely(num_elements == 0)) {
return Iterator(nullptr, nullptr, nullptr);
}
return Iterator(elements + num_elements - 1, elements, elements + num_elements);
}
Iterator find(const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return end();
}
return Iterator(elements + pos, elements, elements + num_elements);
}
void remove(const Iterator &p_iter) {
if (p_iter) {
erase(p_iter->key);
}
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(elements, elements, elements + num_elements);
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(elements + num_elements, elements, elements + num_elements);
}
_FORCE_INLINE_ ConstIterator last() const {
if (unlikely(num_elements == 0)) {
return ConstIterator(nullptr, nullptr, nullptr);
}
return ConstIterator(elements + num_elements - 1, elements, elements + num_elements);
}
ConstIterator find(const TKey &p_key) const {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return end();
}
return ConstIterator(elements + pos, elements, elements + num_elements);
}
/* Indexing */
const TValue &operator[](const TKey &p_key) const {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
CRASH_COND(!exists);
return elements[pos].value;
}
TValue &operator[](const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
uint32_t hash = _hash(p_key);
bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
if (exists) {
return elements[pos].value;
} else {
pos = _insert_element(p_key, TValue(), hash);
return elements[pos].value;
}
}
/* Insert */
Iterator insert(const TKey &p_key, const TValue &p_value) {
uint32_t pos = 0;
uint32_t h_pos = 0;
uint32_t hash = _hash(p_key);
bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
if (!exists) {
pos = _insert_element(p_key, p_value, hash);
} else {
elements[pos].value = p_value;
}
return Iterator(elements + pos, elements, elements + num_elements);
}
// Inserts an element without checking if it already exists.
Iterator insert_new(const TKey &p_key, const TValue &p_value) {
DEV_ASSERT(!has(p_key));
uint32_t hash = _hash(p_key);
uint32_t pos = _insert_element(p_key, p_value, hash);
return Iterator(elements + pos, elements, elements + num_elements);
}
/* Array methods. */
// Unsafe. Changing keys and going outside the bounds of an array can lead to undefined behavior.
KeyValue<TKey, TValue> *get_elements_ptr() {
return elements;
}
// Returns the element index. If not found, returns -1.
int get_index(const TKey &p_key) {
uint32_t pos = 0;
uint32_t h_pos = 0;
bool exists = _lookup_pos(p_key, pos, h_pos);
if (!exists) {
return -1;
}
return pos;
}
KeyValue<TKey, TValue> &get_by_index(uint32_t p_index) {
CRASH_BAD_UNSIGNED_INDEX(p_index, num_elements);
return elements[p_index];
}
bool erase_by_index(uint32_t p_index) {
if (p_index >= size()) {
return false;
}
return erase(elements[p_index].key);
}
/* Constructors */
AHashMap(const AHashMap &p_other) {
_init_from(p_other);
}
AHashMap(const HashMap<TKey, TValue> &p_other) {
reserve(p_other.size());
for (const KeyValue<TKey, TValue> &E : p_other) {
uint32_t hash = _hash(E.key);
_insert_element(E.key, E.value, hash);
}
}
void operator=(const AHashMap &p_other) {
if (this == &p_other) {
return; // Ignore self assignment.
}
reset();
_init_from(p_other);
}
void operator=(const HashMap<TKey, TValue> &p_other) {
reset();
reserve(p_other.size());
for (const KeyValue<TKey, TValue> &E : p_other) {
uint32_t hash = _hash(E.key);
_insert_element(E.key, E.value, hash);
}
}
AHashMap(uint32_t p_initial_capacity) {
// Capacity can't be 0 and must be 2^n - 1.
capacity = MAX(4u, p_initial_capacity);
capacity = next_power_of_2(capacity) - 1;
}
AHashMap() :
capacity(INITIAL_CAPACITY - 1) {
}
AHashMap(std::initializer_list<KeyValue<TKey, TValue>> p_init) {
reserve(p_init.size());
for (const KeyValue<TKey, TValue> &E : p_init) {
insert(E.key, E.value);
}
}
void reset() {
if (elements != nullptr) {
if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
for (uint32_t i = 0; i < num_elements; i++) {
elements[i].key.~TKey();
elements[i].value.~TValue();
}
}
Memory::free_static(elements);
Memory::free_static(map_data);
elements = nullptr;
}
capacity = INITIAL_CAPACITY - 1;
num_elements = 0;
}
~AHashMap() {
reset();
}
};
} //namespace godot

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_COWDATA_HPP
#define GODOT_COWDATA_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/core/error_macros.hpp>
@@ -37,10 +38,8 @@
#include <godot_cpp/templates/safe_refcount.hpp>
#include <cstring>
#include <initializer_list>
#include <new>
#include <type_traits>
#include <utility>
namespace godot {
@@ -168,25 +167,13 @@ private:
return *out;
}
// Decrements the reference count. Deallocates the backing buffer if needed.
// After this function, _ptr is guaranteed to be NULL.
void _unref();
void _unref(void *p_data);
void _ref(const CowData *p_from);
void _ref(const CowData &p_from);
USize _copy_on_write();
Error _realloc(Size p_alloc_size);
public:
void operator=(const CowData<T> &p_from) { _ref(p_from); }
void operator=(CowData<T> &&p_from) {
if (_ptr == p_from._ptr) {
return;
}
_unref();
_ptr = p_from._ptr;
p_from._ptr = nullptr;
}
_FORCE_INLINE_ T *ptrw() {
_copy_on_write();
@@ -235,22 +222,19 @@ public:
T *p = ptrw();
Size len = size();
for (Size i = p_index; i < len - 1; i++) {
p[i] = std::move(p[i + 1]);
p[i] = p[i + 1];
}
resize(len - 1);
}
Error insert(Size p_pos, const T &p_val) {
Size new_size = size() + 1;
ERR_FAIL_INDEX_V(p_pos, new_size, ERR_INVALID_PARAMETER);
Error err = resize(new_size);
ERR_FAIL_COND_V(err, err);
T *p = ptrw();
for (Size i = new_size - 1; i > p_pos; i--) {
p[i] = std::move(p[i - 1]);
ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER);
resize(size() + 1);
for (Size i = (size() - 1); i > p_pos; i--) {
set(i, get(i - 1));
}
p[p_pos] = p_val;
set(p_pos, p_val);
return OK;
}
@@ -260,47 +244,35 @@ public:
Size count(const T &p_val) const;
_FORCE_INLINE_ CowData() {}
_FORCE_INLINE_ ~CowData() { _unref(); }
_FORCE_INLINE_ CowData(std::initializer_list<T> p_init);
_FORCE_INLINE_ CowData(const CowData<T> &p_from) { _ref(p_from); }
_FORCE_INLINE_ CowData(CowData<T> &&p_from) {
_ptr = p_from._ptr;
p_from._ptr = nullptr;
}
_FORCE_INLINE_ ~CowData();
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); };
};
template <typename T>
void CowData<T>::_unref() {
if (!_ptr) {
void CowData<T>::_unref(void *p_data) {
if (!p_data) {
return;
}
SafeNumeric<USize> *refc = _get_refcount();
if (refc->decrement() > 0) {
// Data is still in use elsewhere.
_ptr = nullptr;
return;
return; // still in use
}
// Clean up.
// First, invalidate our own reference.
// NOTE: It is required to do so immediately because it must not be observable outside of this
// function after refcount has already been reduced to 0.
// WARNING: It must be done before calling the destructors, because one of them may otherwise
// observe it through a reference to us. In this case, it may try to access the buffer,
// which is illegal after some of the elements in it have already been destructed, and
// may lead to a segmentation fault.
USize current_size = *_get_size();
T *prev_ptr = _ptr;
_ptr = nullptr;
// clean up
if constexpr (!std::is_trivially_destructible_v<T>) {
for (USize i = 0; i < current_size; ++i) {
prev_ptr[i].~T();
USize *count = _get_size();
T *data = (T *)(count + 1);
for (USize i = 0; i < *count; ++i) {
// call destructors
data[i].~T();
}
}
// free mem
Memory::free_static((uint8_t *)prev_ptr - DATA_OFFSET, false);
Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false);
}
template <typename T>
@@ -335,7 +307,7 @@ typename CowData<T>::USize CowData<T>::_copy_on_write() {
}
}
_unref();
_unref(_ptr);
_ptr = _data_ptr;
rc = 1;
@@ -355,13 +327,14 @@ Error CowData<T>::resize(Size p_size) {
}
if (p_size == 0) {
// Wants to clean up.
_unref(); // Resets _ptr to nullptr.
// wants to clean up
_unref(_ptr);
_ptr = nullptr;
return OK;
}
// possibly changing size, copy on write
_copy_on_write();
USize rc = _copy_on_write();
USize current_alloc_size = _get_alloc_size(current_size);
USize alloc_size;
@@ -382,12 +355,16 @@ Error CowData<T>::resize(Size p_size) {
*(_size_ptr) = 0; //size, currently none
_ptr = _data_ptr;
} else {
const Error error = _realloc(alloc_size);
if (error) {
return error;
}
uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
_ptr = _data_ptr;
}
}
@@ -413,10 +390,15 @@ Error CowData<T>::resize(Size p_size) {
}
if (alloc_size != current_alloc_size) {
const Error error = _realloc(alloc_size);
if (error) {
return error;
}
uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
_ptr = _data_ptr;
}
*_get_size() = p_size;
@@ -425,21 +407,6 @@ Error CowData<T>::resize(Size p_size) {
return OK;
}
template <typename T>
Error CowData<T>::_realloc(Size p_alloc_size) {
uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, p_alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
// If we realloc, we're guaranteed to be the only reference.
new (_refc_ptr) SafeNumeric<USize>(1);
_ptr = _data_ptr;
return OK;
}
template <typename T>
typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
Size ret = -1;
@@ -499,10 +466,11 @@ void CowData<T>::_ref(const CowData &p_from) {
return; // self assign, do nothing.
}
_unref(); // Resets _ptr to nullptr.
_unref(_ptr);
_ptr = nullptr;
if (!p_from._ptr) {
return; //nothing to do
return; // nothing to do
}
if (p_from._get_refcount()->conditional_increment() > 0) { // could reference
@@ -511,16 +479,8 @@ void CowData<T>::_ref(const CowData &p_from) {
}
template <typename T>
CowData<T>::CowData(std::initializer_list<T> p_init) {
Error err = resize(p_init.size());
if (err != OK) {
return;
}
Size i = 0;
for (const T &element : p_init) {
set(i++, element);
}
CowData<T>::~CowData() {
_unref(_ptr);
}
#if defined(__GNUC__) && !defined(__clang__)
@@ -528,3 +488,5 @@ CowData<T>::CowData(std::initializer_list<T> p_init) {
#endif
} // namespace godot
#endif // GODOT_COWDATA_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_HASH_MAP_HPP
#define GODOT_HASH_MAP_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
@@ -61,17 +62,15 @@ struct HashMapElement {
data(p_key, p_value) {}
};
bool _hashmap_variant_less_than(const Variant &p_left, const Variant &p_right);
template <typename TKey, typename TValue,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>,
typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
class HashMap {
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;
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;
@@ -93,20 +92,19 @@ private:
return hash;
}
static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) {
const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity);
return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity);
_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 || num_elements == 0) {
if (elements == nullptr) {
return false; // Failed lookups, no elements
}
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t hash = _hash(p_key);
uint32_t pos = fastmod(hash, capacity_inv, capacity);
uint32_t pos = hash % capacity;
uint32_t distance = 0;
while (true) {
@@ -114,7 +112,7 @@ private:
return false;
}
if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) {
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
return false;
}
@@ -123,18 +121,17 @@ private:
return true;
}
pos = fastmod((pos + 1), capacity_inv, capacity);
pos = (pos + 1) % capacity;
distance++;
}
}
void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) {
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
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 = fastmod(hash, capacity_inv, capacity);
uint32_t pos = hash % capacity;
while (true) {
if (hashes[pos] == EMPTY_HASH) {
@@ -147,14 +144,14 @@ private:
}
// 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, capacity_inv);
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 = fastmod((pos + 1), capacity_inv, capacity);
pos = (pos + 1) % capacity;
distance++;
}
}
@@ -254,7 +251,7 @@ public:
}
void clear() {
if (elements == nullptr || num_elements == 0) {
if (elements == nullptr) {
return;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
@@ -273,47 +270,6 @@ public:
num_elements = 0;
}
void sort() {
if (elements == nullptr || num_elements < 2) {
return; // An empty or single element HashMap is already sorted.
}
// Use insertion sort because we want this operation to be fast for the
// common case where the input is already sorted or nearly sorted.
HashMapElement<TKey, TValue> *inserting = head_element->next;
while (inserting != nullptr) {
HashMapElement<TKey, TValue> *after = nullptr;
for (HashMapElement<TKey, TValue> *current = inserting->prev; current != nullptr; current = current->prev) {
if (_hashmap_variant_less_than(inserting->data.key, current->data.key)) {
after = current;
} else {
break;
}
}
HashMapElement<TKey, TValue> *next = inserting->next;
if (after != nullptr) {
// Modify the elements around `inserting` to remove it from its current position.
inserting->prev->next = next;
if (next == nullptr) {
tail_element = inserting->prev;
} else {
next->prev = inserting->prev;
}
// Modify `before` and `after` to insert `inserting` between them.
HashMapElement<TKey, TValue> *before = after->prev;
if (before == nullptr) {
head_element = inserting;
} else {
before->next = inserting;
}
after->prev = inserting;
// Point `inserting` to its new surroundings.
inserting->prev = before;
inserting->next = after;
}
inserting = next;
}
}
TValue &get(const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
@@ -361,14 +317,13 @@ public:
return false;
}
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity);
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) {
uint32_t 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 = fastmod((pos + 1), capacity_inv, capacity);
next_pos = (pos + 1) % capacity;
}
hashes[pos] = EMPTY_HASH;
@@ -396,40 +351,6 @@ public:
return true;
}
// Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
// p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
if (p_old_key == p_new_key) {
return true;
}
uint32_t pos = 0;
ERR_FAIL_COND_V(_lookup_pos(p_new_key, pos), false);
ERR_FAIL_COND_V(!_lookup_pos(p_old_key, pos), false);
HashMapElement<TKey, TValue> *element = elements[pos];
// Delete the old entries in hashes and elements.
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity);
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) {
SWAP(hashes[next_pos], hashes[pos]);
SWAP(elements[next_pos], elements[pos]);
pos = next_pos;
next_pos = fastmod((pos + 1), capacity_inv, capacity);
}
hashes[pos] = EMPTY_HASH;
elements[pos] = nullptr;
// _insert_with_hash will increment this again.
num_elements--;
// Update the HashMapElement with the new key and reinsert it.
const_cast<TKey &>(element->data.key) = p_new_key;
uint32_t hash = _hash(p_new_key);
_insert_with_hash(hash, element);
return true;
}
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
void reserve(uint32_t p_new_capacity) {
@@ -640,13 +561,6 @@ public:
capacity_index = MIN_CAPACITY_INDEX;
}
HashMap(std::initializer_list<KeyValue<TKey, TValue>> p_init) {
reserve(p_init.size());
for (const KeyValue<TKey, TValue> &E : p_init) {
insert(E.key, E.value);
}
}
uint32_t debug_get_hash(uint32_t p_index) {
if (num_elements == 0) {
return 0;
@@ -673,3 +587,5 @@ public:
};
} // namespace godot
#endif // GODOT_HASH_MAP_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_HASH_SET_HPP
#define GODOT_HASH_SET_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
@@ -75,20 +76,19 @@ private:
return hash;
}
static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) {
const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity);
return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity);
_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 || num_elements == 0) {
if (keys == nullptr) {
return false; // Failed lookups, no elements
}
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t hash = _hash(p_key);
uint32_t pos = fastmod(hash, capacity_inv, capacity);
uint32_t pos = hash % capacity;
uint32_t distance = 0;
while (true) {
@@ -96,7 +96,7 @@ private:
return false;
}
if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) {
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
return false;
}
@@ -105,18 +105,17 @@ private:
return true;
}
pos = fastmod(pos + 1, capacity_inv, capacity);
pos = (pos + 1) % capacity;
distance++;
}
}
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t hash = p_hash;
uint32_t index = p_index;
uint32_t distance = 0;
uint32_t pos = fastmod(hash, capacity_inv, capacity);
uint32_t pos = hash % capacity;
while (true) {
if (hashes[pos] == EMPTY_HASH) {
@@ -127,7 +126,7 @@ private:
}
// 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, capacity_inv);
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]);
@@ -135,7 +134,7 @@ private:
distance = existing_probe_len;
}
pos = fastmod(pos + 1, capacity_inv, capacity);
pos = (pos + 1) % capacity;
distance++;
}
}
@@ -238,7 +237,7 @@ public:
}
void clear() {
if (keys == nullptr || num_elements == 0) {
if (keys == nullptr) {
return;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
@@ -266,12 +265,11 @@ public:
}
uint32_t key_pos = pos;
pos = key_to_hash[pos]; //make hash pos
pos = key_to_hash[pos]; // make hash pos
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t next_pos = fastmod(pos + 1, capacity_inv, capacity);
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) {
uint32_t 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]);
@@ -279,7 +277,7 @@ public:
SWAP(hash_to_key[next_pos], hash_to_key[pos]);
pos = next_pos;
next_pos = fastmod(pos + 1, capacity_inv, capacity);
next_pos = (pos + 1) % capacity;
}
hashes[pos] = EMPTY_HASH;
@@ -446,13 +444,6 @@ public:
capacity_index = MIN_CAPACITY_INDEX;
}
HashSet(std::initializer_list<TKey> p_init) {
reserve(p_init.size());
for (const TKey &E : p_init) {
insert(E);
}
}
void reset() {
clear();
@@ -482,3 +473,5 @@ public:
};
} // namespace godot
#endif // GODOT_HASH_SET_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_HASHFUNCS_HPP
#define GODOT_HASHFUNCS_HPP
// Needed for fastmod.
#if defined(_MSC_VER)
@@ -37,7 +38,6 @@
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/templates/pair.hpp>
#include <godot_cpp/variant/aabb.hpp>
#include <godot_cpp/variant/node_path.hpp>
#include <godot_cpp/variant/rect2.hpp>
@@ -67,11 +67,10 @@ namespace godot {
static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
const unsigned char *chr = (const unsigned char *)p_cstr;
uint32_t hash = 5381;
uint32_t c = *chr++;
uint32_t c;
while (c) {
while ((c = *chr++)) {
hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */
c = *chr++;
}
return hash;
@@ -109,16 +108,6 @@ static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
return uint32_t(v);
}
static _FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) {
key ^= seed;
key ^= key >> 33;
key *= 0xff51afd7ed558ccd;
key ^= key >> 33;
key *= 0xc4ceb9fe1a85ec53;
key ^= key >> 33;
return key;
}
#define HASH_MURMUR3_SEED 0x7F07C65
// Murmurhash3 32-bit version.
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
@@ -239,7 +228,7 @@ static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length,
k1 = hash_rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
};
}
// Finalize with additional bit mixing.
h1 ^= length;
@@ -320,51 +309,42 @@ struct HashMapHasherDefault {
template <typename T>
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
template <typename F, typename S>
static _FORCE_INLINE_ uint32_t hash(const Pair<F, S> &p_pair) {
uint64_t h1 = hash(p_pair.first);
uint64_t h2 = hash(p_pair.second);
return hash_one_uint64((h1 << 32) | h2);
}
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(uint32_t(p_wchar)); }
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); }
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); }
static _FORCE_INLINE_ uint32_t hash(const 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 CharString &p_char_string) { return hash_djb2(p_char_string.get_data()); }
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
static _FORCE_INLINE_ uint32_t hash(const Callable &p_callable) { return p_callable.hash(); }
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(uint64_t(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(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(uint32_t(p_int)); }
static _FORCE_INLINE_ uint32_t hash(const 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(uint32_t(p_vec.x));
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
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(uint32_t(p_vec.x));
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
h = hash_murmur3_one_32(uint32_t(p_vec.z), h);
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(uint32_t(p_vec.x));
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
h = hash_murmur3_one_32(uint32_t(p_vec.z), h);
h = hash_murmur3_one_32(uint32_t(p_vec.w), h);
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) {
@@ -385,18 +365,11 @@ struct HashMapHasherDefault {
h = hash_murmur3_one_real(p_vec.w, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Color &p_vec) {
uint32_t h = hash_murmur3_one_float(p_vec.r);
h = hash_murmur3_one_float(p_vec.g, h);
h = hash_murmur3_one_float(p_vec.b, h);
h = hash_murmur3_one_float(p_vec.a, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
uint32_t h = hash_murmur3_one_32(uint32_t(p_rect.position.x));
h = hash_murmur3_one_32(uint32_t(p_rect.position.y), h);
h = hash_murmur3_one_32(uint32_t(p_rect.size.x), h);
h = hash_murmur3_one_32(uint32_t(p_rect.size.y), h);
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) {
@@ -417,19 +390,6 @@ struct HashMapHasherDefault {
}
};
struct HashHasher {
static _FORCE_INLINE_ uint32_t hash(const int32_t hash) { return hash; }
static _FORCE_INLINE_ uint32_t hash(const uint32_t hash) { return hash; }
static _FORCE_INLINE_ uint64_t hash(const int64_t hash) { return hash; }
static _FORCE_INLINE_ uint64_t hash(const uint64_t hash) { return hash; }
};
// TODO: Fold this into HashMapHasherDefault once C++20 concepts are allowed
template <typename T>
struct HashableHasher {
static _FORCE_INLINE_ uint32_t hash(const T &hashable) { return hashable.hash(); }
};
template <typename T>
struct HashMapComparatorDefault {
static bool compare(const T &p_lhs, const T &p_rhs) {
@@ -451,13 +411,6 @@ struct HashMapComparatorDefault<double> {
}
};
template <>
struct HashMapComparatorDefault<Color> {
static bool compare(const Color &p_lhs, const Color &p_rhs) {
return ((p_lhs.r == p_rhs.r) || (Math::is_nan(p_lhs.r) && Math::is_nan(p_rhs.r))) && ((p_lhs.g == p_rhs.g) || (Math::is_nan(p_lhs.g) && Math::is_nan(p_rhs.g))) && ((p_lhs.b == p_rhs.b) || (Math::is_nan(p_lhs.b) && Math::is_nan(p_rhs.b))) && ((p_lhs.a == p_rhs.a) || (Math::is_nan(p_lhs.a) && Math::is_nan(p_rhs.a)));
}
};
template <>
struct HashMapComparatorDefault<Vector2> {
static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) {
@@ -472,90 +425,9 @@ struct HashMapComparatorDefault<Vector3> {
}
};
template <>
struct HashMapComparatorDefault<Vector4> {
static bool compare(const Vector4 &p_lhs, const Vector4 &p_rhs) {
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))) && ((p_lhs.w == p_rhs.w) || (Math::is_nan(p_lhs.w) && Math::is_nan(p_rhs.w)));
}
};
template <>
struct HashMapComparatorDefault<Rect2> {
static bool compare(const Rect2 &p_lhs, const Rect2 &p_rhs) {
return HashMapComparatorDefault<Vector2>().compare(p_lhs.position, p_rhs.position) && HashMapComparatorDefault<Vector2>().compare(p_lhs.size, p_rhs.size);
}
};
template <>
struct HashMapComparatorDefault<AABB> {
static bool compare(const AABB &p_lhs, const AABB &p_rhs) {
return HashMapComparatorDefault<Vector3>().compare(p_lhs.position, p_rhs.position) && HashMapComparatorDefault<Vector3>().compare(p_lhs.size, p_rhs.size);
}
};
template <>
struct HashMapComparatorDefault<Plane> {
static bool compare(const Plane &p_lhs, const Plane &p_rhs) {
return HashMapComparatorDefault<Vector3>().compare(p_lhs.normal, p_rhs.normal) && ((p_lhs.d == p_rhs.d) || (Math::is_nan(p_lhs.d) && Math::is_nan(p_rhs.d)));
}
};
template <>
struct HashMapComparatorDefault<Transform2D> {
static bool compare(const Transform2D &p_lhs, const Transform2D &p_rhs) {
for (int i = 0; i < 3; ++i) {
if (!HashMapComparatorDefault<Vector2>().compare(p_lhs.columns[i], p_rhs.columns[i])) {
return false;
}
}
return true;
}
};
template <>
struct HashMapComparatorDefault<Basis> {
static bool compare(const Basis &p_lhs, const Basis &p_rhs) {
for (int i = 0; i < 3; ++i) {
if (!HashMapComparatorDefault<Vector3>().compare(p_lhs.rows[i], p_rhs.rows[i])) {
return false;
}
}
return true;
}
};
template <>
struct HashMapComparatorDefault<Transform3D> {
static bool compare(const Transform3D &p_lhs, const Transform3D &p_rhs) {
return HashMapComparatorDefault<Basis>().compare(p_lhs.basis, p_rhs.basis) && HashMapComparatorDefault<Vector3>().compare(p_lhs.origin, p_rhs.origin);
}
};
template <>
struct HashMapComparatorDefault<Projection> {
static bool compare(const Projection &p_lhs, const Projection &p_rhs) {
for (int i = 0; i < 4; ++i) {
if (!HashMapComparatorDefault<Vector4>().compare(p_lhs.columns[i], p_rhs.columns[i])) {
return false;
}
}
return true;
}
};
template <>
struct HashMapComparatorDefault<Quaternion> {
static bool compare(const Quaternion &p_lhs, const Quaternion &p_rhs) {
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))) && ((p_lhs.w == p_rhs.w) || (Math::is_nan(p_lhs.w) && Math::is_nan(p_rhs.w)));
}
};
constexpr uint32_t HASH_TABLE_SIZE_MAX = 29;
inline constexpr uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
5,
13,
23,
@@ -588,7 +460,7 @@ inline constexpr uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
};
// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array.
inline constexpr uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
const uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
3689348814741910324,
1418980313362273202,
802032351030850071,
@@ -650,3 +522,5 @@ static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const
}
} // namespace godot
#endif // GODOT_HASHFUNCS_HPP

View File

@@ -28,14 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#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>
#include <initializer_list>
/**
* Generic Templatized Linked List Implementation.
* The implementation differs from the STL one because
@@ -135,13 +134,36 @@ public:
data->erase(this);
}
void transfer_to_back(List<T, A> *p_dst_list);
_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();
@@ -167,35 +189,6 @@ public:
const Element *E = nullptr;
};
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return E->get();
}
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
operator ConstIterator() const {
return ConstIterator(E);
}
private:
Element *E = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(front());
}
@@ -227,7 +220,7 @@ private:
Element *last = nullptr;
int size_cache = 0;
bool erase(Element *p_I) {
bool erase(const Element *p_I) {
ERR_FAIL_NULL_V(p_I, false);
ERR_FAIL_COND_V(p_I->data != this, false);
@@ -247,7 +240,7 @@ private:
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
}
memdelete_allocator<Element, A>(p_I);
memdelete_allocator<Element, A>(const_cast<Element *>(p_I));
size_cache--;
return true;
@@ -433,7 +426,7 @@ public:
/**
* erase an element in the list, by iterator pointing to it. Return true if it was found/erased.
*/
bool erase(Element *p_I) {
bool erase(const Element *p_I) {
if (_data && p_I) {
bool ret = _data->erase(p_I);
@@ -525,19 +518,8 @@ public:
it = it->next();
}
}
void operator=(List &&p_list) {
if (unlikely(this == &p_list)) {
return;
}
clear();
_data = p_list._data;
p_list._data = nullptr;
}
// Random access to elements, use with care,
// do not use for iteration.
T &get(int p_index) {
T &operator[](int p_index) {
CRASH_BAD_INDEX(p_index, size());
Element *I = front();
@@ -550,9 +532,7 @@ public:
return I->get();
}
// Random access to elements, use with care,
// do not use for iteration.
const T &get(int p_index) const {
const T &operator[](int p_index) const {
CRASH_BAD_INDEX(p_index, size());
const Element *I = front();
@@ -723,8 +703,8 @@ public:
template <typename C>
void sort_custom() {
//this version uses auxiliary memory for speed.
//if you don't want to use auxiliary memory, use the in_place version
// this version uses auxiliary memory for speed.
// if you don't want to use auxiliary memory, use the in_place version
int s = size();
if (s < 2) {
@@ -772,19 +752,9 @@ public:
it = it->next();
}
}
List(List &&p_list) {
_data = p_list._data;
p_list._data = nullptr;
}
List() {}
List(std::initializer_list<T> p_init) {
for (const T &E : p_init) {
push_back(E);
}
}
~List() {
clear();
if (_data) {
@@ -794,41 +764,6 @@ public:
}
};
template <typename T, typename A>
void List<T, A>::Element::transfer_to_back(List<T, A> *p_dst_list) {
// Detach from current.
if (data->first == this) {
data->first = data->first->next_ptr;
}
if (data->last == this) {
data->last = data->last->prev_ptr;
}
if (prev_ptr) {
prev_ptr->next_ptr = next_ptr;
}
if (next_ptr) {
next_ptr->prev_ptr = prev_ptr;
}
data->size_cache--;
// Attach to the back of the new one.
if (!p_dst_list->_data) {
p_dst_list->_data = memnew_allocator(_Data, A);
p_dst_list->_data->first = this;
p_dst_list->_data->last = nullptr;
p_dst_list->_data->size_cache = 0;
prev_ptr = nullptr;
} else {
p_dst_list->_data->last->next_ptr = this;
prev_ptr = p_dst_list->_data->last;
}
p_dst_list->_data->last = this;
next_ptr = nullptr;
data = p_dst_list->_data;
p_dst_list->_data->size_cache++;
}
} // namespace godot
#endif // GODOT_LIST_HPP

View File

@@ -28,12 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_LOCAL_VECTOR_HPP
#define GODOT_LOCAL_VECTOR_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/sort_array.hpp>
#include <godot_cpp/templates/vector.hpp>
#include "godot_cpp/core/error_macros.hpp"
#include "godot_cpp/core/memory.hpp"
#include "godot_cpp/templates/sort_array.hpp"
#include "godot_cpp/templates/vector.hpp"
#include <initializer_list>
#include <type_traits>
@@ -58,18 +59,21 @@ public:
return data;
}
// Must take a copy instead of a reference (see GH-31736).
_FORCE_INLINE_ void push_back(T p_elem) {
if (unlikely(count == capacity)) {
capacity = tight ? (capacity + 1) : MAX((U)1, capacity << 1);
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_v<T> && !force_trivial) {
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
memnew_placement(&data[count++], T(p_elem));
} else {
data[count++] = std::move(p_elem);
data[count++] = p_elem;
}
}
@@ -77,49 +81,31 @@ public:
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
count--;
for (U i = p_index; i < count; i++) {
data[i] = std::move(data[i + 1]);
data[i] = data[i + 1];
}
if constexpr (!std::is_trivially_destructible_v<T> && !force_trivial) {
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_at`.
/// 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] = std::move(data[count]);
data[p_index] = data[count];
}
if constexpr (!std::is_trivially_destructible_v<T> && !force_trivial) {
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
_FORCE_INLINE_ bool erase(const T &p_val) {
void erase(const T &p_val) {
int64_t idx = find(p_val);
if (idx >= 0) {
remove_at(idx);
return true;
}
return false;
}
U erase_multiple_unordered(const T &p_val) {
U from = 0;
U occurrences = 0;
while (true) {
int64_t idx = find(p_val, from);
if (idx == -1) {
break;
}
remove_at_unordered(idx);
from = idx;
occurrences++;
}
return occurrences;
}
void invert() {
@@ -151,7 +137,7 @@ public:
_FORCE_INLINE_ U size() const { return count; }
void resize(U p_size) {
if (p_size < count) {
if constexpr (!std::is_trivially_destructible_v<T> && !force_trivial) {
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
for (U i = p_size; i < count; i++) {
data[i].~T();
}
@@ -159,11 +145,16 @@ public:
count = p_size;
} else if (p_size > count) {
if (unlikely(p_size > capacity)) {
capacity = tight ? p_size : nearest_power_of_2_templated(p_size);
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_v<T> && !force_trivial) {
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
for (U i = count; i < p_size; i++) {
memnew_placement(&data[i], T);
}
@@ -247,13 +238,13 @@ public:
void insert(U p_pos, T p_val) {
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
if (p_pos == count) {
push_back(std::move(p_val));
push_back(p_val);
} else {
resize(count + 1);
for (U i = count - 1; i > p_pos; i--) {
data[i] = std::move(data[i - 1]);
data[i] = data[i - 1];
}
data[p_pos] = std::move(p_val);
data[p_pos] = p_val;
}
}
@@ -266,10 +257,6 @@ public:
return -1;
}
bool has(const T &p_val) const {
return find(p_val) != -1;
}
template <typename C>
void sort_custom() {
U len = count;
@@ -297,17 +284,9 @@ public:
operator Vector<T>() const {
Vector<T> ret;
ret.resize(count);
ret.resize(size());
T *w = ret.ptrw();
if (w) {
if constexpr (std::is_trivially_copyable_v<T>) {
memcpy(w, data, sizeof(T) * count);
} else {
for (U i = 0; i < count; i++) {
w[i] = data[i];
}
}
}
memcpy(w, data, sizeof(T) * count);
return ret;
}
@@ -315,9 +294,7 @@ public:
Vector<uint8_t> ret;
ret.resize(count * sizeof(T));
uint8_t *w = ret.ptrw();
if (w) {
memcpy(w, data, sizeof(T) * count);
}
memcpy(w, data, sizeof(T) * count);
return ret;
}
@@ -334,16 +311,6 @@ public:
data[i] = p_from.data[i];
}
}
_FORCE_INLINE_ LocalVector(LocalVector &&p_from) {
data = p_from.data;
count = p_from.count;
capacity = p_from.capacity;
p_from.data = nullptr;
p_from.count = 0;
p_from.capacity = 0;
}
inline void operator=(const LocalVector &p_from) {
resize(p_from.size());
for (U i = 0; i < p_from.count; i++) {
@@ -356,26 +323,6 @@ public:
data[i] = p_from[i];
}
}
inline void operator=(LocalVector &&p_from) {
if (unlikely(this == &p_from)) {
return;
}
reset();
data = p_from.data;
count = p_from.count;
capacity = p_from.capacity;
p_from.data = nullptr;
p_from.count = 0;
p_from.capacity = 0;
}
inline void operator=(Vector<T> &&p_from) {
resize(p_from.size());
for (U i = 0; i < count; i++) {
data[i] = std::move(p_from[i]);
}
}
_FORCE_INLINE_ ~LocalVector() {
if (data) {
@@ -388,3 +335,5 @@ template <typename T, typename U = uint32_t, bool force_trivial = false>
using TightLocalVector = LocalVector<T, U, force_trivial, true>;
} // namespace godot
#endif // GODOT_LOCAL_VECTOR_HPP

View File

@@ -28,72 +28,80 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include <godot_cpp/core/defs.hpp>
#ifndef GODOT_PAIR_HPP
#define GODOT_PAIR_HPP
namespace godot {
template <typename F, typename S>
struct Pair {
F first{};
S second{};
F first;
S second;
constexpr Pair() = default;
constexpr Pair(const F &p_first, const S &p_second) :
first(p_first), second(p_second) {}
Pair() :
first(),
second() {
}
constexpr bool operator==(const Pair &p_other) const { return first == p_other.first && second == p_other.second; }
constexpr bool operator!=(const Pair &p_other) const { return first != p_other.first || second != p_other.second; }
constexpr bool operator<(const Pair &p_other) const { return first == p_other.first ? (second < p_other.second) : (first < p_other.first); }
constexpr bool operator<=(const Pair &p_other) const { return first == p_other.first ? (second <= p_other.second) : (first < p_other.first); }
constexpr bool operator>(const Pair &p_other) const { return first == p_other.first ? (second > p_other.second) : (first > p_other.first); }
constexpr bool operator>=(const Pair &p_other) const { return first == p_other.first ? (second >= p_other.second) : (first > p_other.first); }
Pair(F p_first, const S &p_second) :
first(p_first),
second(p_second) {
}
};
template <typename F, typename S>
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first == other.first) && (pair.second == other.second);
}
template <typename F, typename S>
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first != other.first) || (pair.second != other.second);
}
template <typename F, typename S>
struct PairSort {
constexpr bool operator()(const Pair<F, S> &p_lhs, const Pair<F, S> &p_rhs) const {
return p_lhs < p_rhs;
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;
}
};
// Pair is zero-constructible if and only if both constrained types are zero-constructible.
template <typename F, typename S>
struct is_zero_constructible<Pair<F, S>> : std::conjunction<is_zero_constructible<F>, is_zero_constructible<S>> {};
template <typename K, typename V>
struct KeyValue {
const K key{};
V value{};
const K key;
V value;
KeyValue &operator=(const KeyValue &p_kv) = delete;
KeyValue &operator=(KeyValue &&p_kv) = delete;
constexpr KeyValue(const KeyValue &p_kv) = default;
constexpr KeyValue(KeyValue &&p_kv) = default;
constexpr KeyValue(const K &p_key, const V &p_value) :
key(p_key), value(p_value) {}
constexpr KeyValue(const Pair<K, V> &p_pair) :
key(p_pair.first), value(p_pair.second) {}
constexpr bool operator==(const KeyValue &p_other) const { return key == p_other.key && value == p_other.value; }
constexpr bool operator!=(const KeyValue &p_other) const { return key != p_other.key || value != p_other.value; }
constexpr bool operator<(const KeyValue &p_other) const { return key == p_other.key ? (value < p_other.value) : (key < p_other.key); }
constexpr bool operator<=(const KeyValue &p_other) const { return key == p_other.key ? (value <= p_other.value) : (key < p_other.key); }
constexpr bool operator>(const KeyValue &p_other) const { return key == p_other.key ? (value > p_other.value) : (key > p_other.key); }
constexpr bool operator>=(const KeyValue &p_other) const { return key == p_other.key ? (value >= p_other.value) : (key > p_other.key); }
};
template <typename K, typename V>
struct KeyValueSort {
constexpr bool operator()(const KeyValue<K, V> &p_lhs, const KeyValue<K, V> &p_rhs) const {
return p_lhs.key < p_rhs.key;
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) {
}
};
// KeyValue is zero-constructible if and only if both constrained types are zero-constructible.
template <typename K, typename V>
struct is_zero_constructible<KeyValue<K, V>> : std::conjunction<is_zero_constructible<K>, is_zero_constructible<V>> {};
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key == other.key) && (pair.value == other.value);
}
template <typename K, typename V>
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key != other.key) || (pair.value != other.value);
}
template <typename K, typename V>
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

@@ -28,14 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#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>
#include <initializer_list>
namespace godot {
// based on the very nice implementation of rb-trees by:
@@ -99,8 +98,6 @@ public:
typedef KeyValue<K, V> ValueType;
struct Iterator {
friend class RBMap<K, V, C, A>;
_FORCE_INLINE_ KeyValue<K, V> &operator*() const {
return E->key_value();
}
@@ -114,16 +111,11 @@ public:
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &p_it) const { return E == p_it.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &p_it) const { return E != p_it.E; }
_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 &operator=(const Iterator &p_it) {
E = p_it.E;
return *this;
}
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
@@ -146,16 +138,11 @@ public:
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &p_it) const { return E == p_it.E; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &p_it) const { return E != p_it.E; }
_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 &operator=(const ConstIterator &p_it) {
E = p_it.E;
return *this;
}
ConstIterator(const Element *p_E) { E = p_E; }
ConstIterator() {}
ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
@@ -432,7 +419,7 @@ private:
new_node->right = _data._nil;
new_node->left = _data._nil;
//new_node->data=_data;
// new_node->data=_data;
if (new_parent == _data._root || less(p_key, new_parent->_data.key)) {
new_parent->left = new_node;
@@ -766,12 +753,6 @@ public:
_copy_from(p_map);
}
RBMap(std::initializer_list<KeyValue<K, V>> p_init) {
for (const KeyValue<K, V> &E : p_init) {
insert(E.key, E.value);
}
}
_FORCE_INLINE_ RBMap() {}
~RBMap() {
@@ -780,3 +761,5 @@ public:
};
} // namespace godot
#endif // GODOT_RB_MAP_HPP

View File

@@ -28,12 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_RB_SET_HPP
#define GODOT_RB_SET_HPP
#include <godot_cpp/core/memory.hpp>
#include <initializer_list>
// 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
@@ -400,7 +399,7 @@ private:
new_node->right = _data._nil;
new_node->left = _data._nil;
new_node->value = p_value;
//new_node->data=_data;
// new_node->data=_data;
if (new_parent == _data._root || less(p_value, new_parent->value)) {
new_parent->left = new_node;
@@ -703,12 +702,6 @@ public:
_copy_from(p_set);
}
RBSet(std::initializer_list<T> p_init) {
for (const T &E : p_init) {
insert(E);
}
}
_FORCE_INLINE_ RBSet() {}
~RBSet() {
@@ -717,3 +710,5 @@ public:
};
} // namespace godot
#endif // GODOT_RB_SET_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_RID_OWNER_HPP
#define GODOT_RID_OWNER_HPP
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/godot.hpp>
@@ -460,3 +461,5 @@ public:
};
} // namespace godot
#endif // GODOT_RID_OWNER_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_SAFE_REFCOUNT_HPP
#define GODOT_SAFE_REFCOUNT_HPP
#if !defined(NO_THREADS)
@@ -51,7 +52,7 @@ namespace godot {
#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \
static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type)); \
static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type)); \
static_assert(std::is_trivially_destructible_v<std::atomic<m_type>>);
static_assert(std::is_trivially_destructible<std::atomic<m_type>>::value);
#define SAFE_FLAG_TYPE_PUN_GUARANTEES \
static_assert(sizeof(SafeFlag) == sizeof(bool)); \
static_assert(alignof(SafeFlag) == alignof(bool));
@@ -102,17 +103,6 @@ public:
return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
}
_ALWAYS_INLINE_ T bit_or(T p_value) {
return value.fetch_or(p_value, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T bit_and(T p_value) {
return value.fetch_and(p_value, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T bit_xor(T p_value) {
return value.fetch_xor(p_value, std::memory_order_acq_rel);
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postsub(T p_value) {
return value.fetch_sub(p_value, std::memory_order_acq_rel);
@@ -124,8 +114,7 @@ public:
if (tmp >= p_value) {
return tmp; // already greater, or equal
}
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_acq_rel)) {
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
return p_value;
}
}
@@ -137,13 +126,13 @@ public:
if (c == 0) {
return 0;
}
if (value.compare_exchange_weak(c, c + 1, std::memory_order_acq_rel)) {
if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
return c + 1;
}
}
}
_ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast<T>(0)) {
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
set(p_value);
}
};
@@ -178,16 +167,6 @@ public:
class SafeRefCount {
SafeNumeric<uint32_t> count;
#ifdef DEV_ENABLED
_ALWAYS_INLINE_ void _check_unref_safety() {
// This won't catch every misuse, but it's better than nothing.
CRASH_COND_MSG(count.get() == 0,
"Trying to unreference a SafeRefCount which is already zero is wrong and a symptom of it being misused.\n"
"Upon a SafeRefCount reaching zero any object whose lifetime is tied to it, as well as the ref count itself, must be destroyed.\n"
"Moreover, to guarantee that, no multiple threads should be racing to do the final unreferencing to zero.");
}
#endif
public:
_ALWAYS_INLINE_ bool ref() { // true on success
return count.conditional_increment() != 0;
@@ -198,16 +177,10 @@ public:
}
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
#ifdef DEV_ENABLED
_check_unref_safety();
#endif
return count.decrement() == 0;
}
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
#ifdef DEV_ENABLED
_check_unref_safety();
#endif
return count.decrement();
}
@@ -220,6 +193,143 @@ public:
}
};
#else
template <typename 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 // !defined(NO_THREADS)
#endif // GODOT_SAFE_REFCOUNT_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_SEARCH_ARRAY_HPP
#define GODOT_SEARCH_ARRAY_HPP
#include <godot_cpp/templates/sort_array.hpp>
@@ -39,12 +40,12 @@ class SearchArray {
public:
Comparator compare;
inline int64_t bisect(const T *p_array, int64_t p_len, const T &p_value, bool p_before) const {
int64_t lo = 0;
int64_t hi = p_len;
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 int64_t mid = (lo + hi) / 2;
const int mid = (lo + hi) / 2;
if (compare(p_array[mid], p_value)) {
lo = mid + 1;
} else {
@@ -53,7 +54,7 @@ public:
}
} else {
while (lo < hi) {
const int64_t mid = (lo + hi) / 2;
const int mid = (lo + hi) / 2;
if (compare(p_value, p_array[mid])) {
hi = mid;
} else {
@@ -66,3 +67,5 @@ public:
};
} // namespace godot
#endif // GODOT_SEARCH_ARRAY_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_SELF_LIST_HPP
#define GODOT_SELF_LIST_HPP
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/error_macros.hpp>
@@ -100,74 +101,11 @@ public:
p_elem->_root = nullptr;
}
void clear() {
while (_first) {
remove(_first);
}
}
void sort() {
sort_custom<Comparator<T>>();
}
template <typename C>
void sort_custom() {
if (_first == _last) {
return;
}
SelfList<T> *from = _first;
SelfList<T> *current = from;
SelfList<T> *to = from;
while (current) {
SelfList<T> *next = current->_next;
if (from != current) {
current->_prev = nullptr;
current->_next = from;
SelfList<T> *find = from;
C less;
while (find && less(*find->_self, *current->_self)) {
current->_prev = find;
current->_next = find->_next;
find = find->_next;
}
if (current->_prev) {
current->_prev->_next = current;
} else {
from = current;
}
if (current->_next) {
current->_next->_prev = current;
} else {
to = current;
}
} else {
current->_prev = nullptr;
current->_next = nullptr;
}
current = next;
}
_first = from;
_last = to;
}
_FORCE_INLINE_ SelfList<T> *first() { return _first; }
_FORCE_INLINE_ const SelfList<T> *first() const { return _first; }
// Forbid copying, which has broken behavior.
void operator=(const List &) = delete;
_FORCE_INLINE_ List() {}
_FORCE_INLINE_ ~List() {
// A self list must be empty on destruction.
DEV_ASSERT(_first == nullptr);
}
_FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != nullptr); }
};
private:
@@ -189,9 +127,6 @@ public:
_FORCE_INLINE_ const SelfList<T> *prev() const { return _prev; }
_FORCE_INLINE_ T *self() const { return _self; }
// Forbid copying, which has broken behavior.
void operator=(const SelfList<T> &) = delete;
_FORCE_INLINE_ SelfList(T *p_self) {
_self = p_self;
}
@@ -204,3 +139,5 @@ public:
};
} // namespace godot
#endif // GODOT_SELF_LIST_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_SORT_ARRAY_HPP
#define GODOT_SORT_ARRAY_HPP
#include <godot_cpp/core/error_macros.hpp>
@@ -78,8 +79,8 @@ public:
}
}
inline int64_t bitlog(int64_t n) const {
int64_t k;
inline int bitlog(int n) const {
int k;
for (k = 0; n != 1; n >>= 1) {
++k;
}
@@ -88,8 +89,8 @@ public:
/* Heap / Heapsort functions */
inline void push_heap(int64_t p_first, int64_t p_hole_idx, int64_t p_top_index, T p_value, T *p_array) const {
int64_t parent = (p_hole_idx - 1) / 2;
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;
@@ -98,17 +99,17 @@ public:
p_array[p_first + p_hole_idx] = p_value;
}
inline void pop_heap(int64_t p_first, int64_t p_last, int64_t p_result, T p_value, T *p_array) const {
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(int64_t p_first, int64_t p_last, T *p_array) const {
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(int64_t p_first, int64_t p_hole_idx, int64_t p_len, T p_value, T *p_array) const {
int64_t top_index = p_hole_idx;
int64_t second_child = 2 * p_hole_idx + 2;
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)])) {
@@ -127,18 +128,18 @@ public:
push_heap(p_first, p_hole_idx, top_index, p_value, p_array);
}
inline void sort_heap(int64_t p_first, int64_t p_last, T *p_array) const {
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(int64_t p_first, int64_t p_last, T *p_array) const {
inline void make_heap(int p_first, int p_last, T *p_array) const {
if (p_last - p_first < 2) {
return;
}
int64_t len = p_last - p_first;
int64_t parent = (len - 2) / 2;
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);
@@ -149,9 +150,9 @@ public:
}
}
inline void partial_sort(int64_t p_first, int64_t p_last, int64_t p_middle, T *p_array) const {
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 (int64_t i = p_middle; i < p_last; i++) {
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);
}
@@ -159,29 +160,29 @@ public:
sort_heap(p_first, p_middle, p_array);
}
inline void partial_select(int64_t p_first, int64_t p_last, int64_t p_middle, T *p_array) const {
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 (int64_t i = p_middle; i < p_last; i++) {
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 int64_t partitioner(int64_t p_first, int64_t p_last, T p_pivot, T *p_array) const {
const int64_t unmodified_first = p_first;
const int64_t unmodified_last = p_last;
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 constexpr (Validate) {
if (Validate) {
ERR_BAD_COMPARE(p_first == unmodified_last - 1);
}
p_first++;
}
p_last--;
while (compare(p_pivot, p_array[p_last])) {
if constexpr (Validate) {
if (Validate) {
ERR_BAD_COMPARE(p_last == unmodified_first);
}
p_last--;
@@ -196,7 +197,7 @@ public:
}
}
inline void introsort(int64_t p_first, int64_t p_last, T *p_array, int64_t p_max_depth) const {
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);
@@ -205,7 +206,7 @@ public:
p_max_depth--;
int64_t cut = partitioner(
int cut = partitioner(
p_first,
p_last,
median_of_3(
@@ -219,7 +220,7 @@ public:
}
}
inline void introselect(int64_t p_first, int64_t p_nth, int64_t p_last, T *p_array, int64_t p_max_depth) const {
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);
@@ -229,7 +230,7 @@ public:
p_max_depth--;
int64_t cut = partitioner(
int cut = partitioner(
p_first,
p_last,
median_of_3(
@@ -248,10 +249,10 @@ public:
insertion_sort(p_first, p_last, p_array);
}
inline void unguarded_linear_insert(int64_t p_last, T p_value, T *p_array) const {
int64_t next = p_last - 1;
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 constexpr (Validate) {
if (Validate) {
ERR_BAD_COMPARE(next == 0);
}
p_array[p_last] = p_array[next];
@@ -261,10 +262,10 @@ public:
p_array[p_last] = p_value;
}
inline void linear_insert(int64_t p_first, int64_t p_last, T *p_array) const {
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 (int64_t i = p_last; i > p_first; i--) {
for (int i = p_last; i > p_first; i--) {
p_array[i] = p_array[i - 1];
}
@@ -274,22 +275,22 @@ public:
}
}
inline void insertion_sort(int64_t p_first, int64_t p_last, T *p_array) const {
inline void insertion_sort(int p_first, int p_last, T *p_array) const {
if (p_first == p_last) {
return;
}
for (int64_t i = p_first + 1; i != p_last; i++) {
for (int i = p_first + 1; i != p_last; i++) {
linear_insert(p_first, i, p_array);
}
}
inline void unguarded_insertion_sort(int64_t p_first, int64_t p_last, T *p_array) const {
for (int64_t i = p_first; i != p_last; i++) {
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(int64_t p_first, int64_t p_last, T *p_array) const {
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);
@@ -298,18 +299,18 @@ public:
}
}
inline void sort_range(int64_t p_first, int64_t p_last, T *p_array) const {
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, int64_t p_len) const {
inline void sort(T *p_array, int p_len) const {
sort_range(0, p_len, p_array);
}
inline void nth_element(int64_t p_first, int64_t p_last, int64_t p_nth, T *p_array) const {
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;
}
@@ -318,3 +319,5 @@ public:
};
} // namespace godot
#endif // GODOT_SORT_ARRAY_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_SPIN_LOCK_HPP
#define GODOT_SPIN_LOCK_HPP
#include <atomic>
@@ -49,3 +50,5 @@ public:
};
} // namespace godot
#endif // GODOT_SPIN_LOCK_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_THREAD_WORK_POOL_HPP
#define GODOT_THREAD_WORK_POOL_HPP
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/classes/semaphore.hpp>
@@ -200,3 +201,5 @@ public:
};
} // namespace godot
#endif // GODOT_THREAD_WORK_POOL_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_VECTOR_HPP
#define GODOT_VECTOR_HPP
/**
* @class Vector
@@ -68,7 +69,6 @@ private:
CowData<T> _cowdata;
public:
// Must take a copy instead of a reference (see GH-31736).
bool push_back(T p_elem);
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias
void fill(T p_elem);
@@ -97,13 +97,11 @@ public:
Error resize(Size p_size) { return _cowdata.resize(p_size); }
Error resize_zeroed(Size p_size) { return _cowdata.template resize<true>(p_size); }
_FORCE_INLINE_ const T &operator[](Size p_index) const { return _cowdata.get(p_index); }
// Must take a copy instead of a reference (see GH-31736).
Error insert(Size p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
Size find(const T &p_val, Size p_from = 0) const { return _cowdata.find(p_val, p_from); }
Size rfind(const T &p_val, Size p_from = -1) const { return _cowdata.rfind(p_val, p_from); }
Size count(const T &p_val) const { return _cowdata.count(p_val); }
// Must take a copy instead of a reference (see GH-31736).
void append_array(Vector<T> p_other);
_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
@@ -148,19 +146,17 @@ public:
insert(i, p_val);
}
void operator=(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
void operator=(Vector &&p_from) { _cowdata = std::move(p_from._cowdata); }
inline void operator=(const Vector &p_from) {
_cowdata._ref(p_from._cowdata);
}
Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> ret;
if (is_empty()) {
return ret;
}
size_t alloc_size = size() * sizeof(T);
ret.resize(alloc_size);
if (alloc_size) {
memcpy(ret.ptrw(), ptr(), alloc_size);
}
ret.resize(size() * sizeof(T));
memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
return ret;
}
@@ -283,11 +279,16 @@ public:
}
_FORCE_INLINE_ Vector() {}
_FORCE_INLINE_ Vector(std::initializer_list<T> p_init) :
_cowdata(p_init) {}
_FORCE_INLINE_ Vector(std::initializer_list<T> p_init) {
Error err = _cowdata.resize(p_init.size());
ERR_FAIL_COND(err);
Size i = 0;
for (const T &element : p_init) {
_cowdata.set(i++, element);
}
}
_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
_FORCE_INLINE_ Vector(Vector &&p_from) :
_cowdata(std::move(p_from._cowdata)) {}
_FORCE_INLINE_ ~Vector() {}
};
@@ -331,3 +332,5 @@ void Vector<T>::fill(T p_elem) {
}
} // namespace godot
#endif // GODOT_VECTOR_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_VMAP_HPP
#define GODOT_VMAP_HPP
#include <godot_cpp/templates/cowdata.hpp>
@@ -72,16 +73,16 @@ private:
middle = (low + high) / 2;
if (p_val < a[middle].key) {
high = middle - 1; //search low end of array
high = middle - 1; // search low end of array
} else if (a[middle].key < p_val) {
low = middle + 1; //search high end of array
low = middle + 1; // search high end of array
} else {
r_exact = true;
return middle;
}
}
//return the position where this would be inserted
// return the position where this would be inserted
if (a[middle].key < p_val) {
middle++;
}
@@ -102,9 +103,9 @@ private:
middle = (low + high) / 2;
if (p_val < a[middle].key) {
high = middle - 1; //search low end of array
high = middle - 1; // search low end of array
} else if (a[middle].key < p_val) {
low = middle + 1; //search high end of array
low = middle + 1; // search high end of array
} else {
return middle;
}
@@ -142,9 +143,6 @@ public:
}
int find_nearest(const T &p_val) const {
if (_cowdata.is_empty()) {
return -1;
}
bool exact;
return _find(p_val, exact);
}
@@ -194,8 +192,6 @@ public:
}
_FORCE_INLINE_ VMap() {}
_FORCE_INLINE_ VMap(std::initializer_list<T> p_init) :
_cowdata(p_init) {}
_FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); }
inline void operator=(const VMap &p_from) {
@@ -204,3 +200,5 @@ public:
};
} // namespace godot
#endif // GODOT_VMAP_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_VSET_HPP
#define GODOT_VSET_HPP
#include <godot_cpp/templates/vector.hpp>
@@ -59,16 +60,16 @@ class VSet {
middle = (low + high) / 2;
if (p_val < a[middle]) {
high = middle - 1; //search low end of array
high = middle - 1; // search low end of array
} else if (a[middle] < p_val) {
low = middle + 1; //search high end of array
low = middle + 1; // search high end of array
} else {
r_exact = true;
return middle;
}
}
//return the position where this would be inserted
// return the position where this would be inserted
if (a[middle] < p_val) {
middle++;
}
@@ -89,9 +90,9 @@ class VSet {
middle = (low + high) / 2;
if (p_val < a[middle]) {
high = middle - 1; //search low end of array
high = middle - 1; // search low end of array
} else if (a[middle] < p_val) {
low = middle + 1; //search high end of array
low = middle + 1; // search high end of array
} else {
return middle;
}
@@ -137,10 +138,8 @@ public:
inline const T &operator[](int p_index) const {
return _data[p_index];
}
_FORCE_INLINE_ VSet() {}
_FORCE_INLINE_ VSet(std::initializer_list<T> p_init) :
_data(p_init) {}
};
} // namespace godot
#endif // GODOT_VSET_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_AABB_HPP
#define GODOT_AABB_HPP
#include <godot_cpp/variant/plane.hpp>
#include <godot_cpp/variant/vector3.hpp>
@@ -42,7 +43,7 @@ namespace godot {
class Variant;
struct [[nodiscard]] AABB {
struct _NO_DISCARD_ AABB {
Vector3 position;
Vector3 size;
@@ -64,7 +65,6 @@ struct [[nodiscard]] AABB {
bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const;
bool is_finite() const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
@@ -72,21 +72,16 @@ struct [[nodiscard]] AABB {
AABB merge(const AABB &p_with) const;
void merge_with(const AABB &p_aabb); ///merge with another AABB
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t p_t0, real_t p_t1) const;
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_intersection_point = nullptr, Vector3 *r_normal = nullptr) const;
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir) const {
bool inside;
return find_intersects_ray(p_from, p_dir, inside);
}
bool find_intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, bool &r_inside, Vector3 *r_intersection_point = nullptr, Vector3 *r_normal = nullptr) const;
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_direction) const;
_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const;
Vector3 get_longest_axis() const;
int get_longest_axis_index() const;
@@ -107,7 +102,7 @@ struct [[nodiscard]] AABB {
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
_FORCE_INLINE_ AABB abs() const {
return AABB(position + size.minf(0), size.abs());
return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
}
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
@@ -206,25 +201,22 @@ inline bool AABB::encloses(const AABB &p_aabb) const {
return (
(src_min.x <= dst_min.x) &&
(src_max.x >= dst_max.x) &&
(src_max.x > dst_max.x) &&
(src_min.y <= dst_min.y) &&
(src_max.y >= dst_max.y) &&
(src_max.y > dst_max.y) &&
(src_min.z <= dst_min.z) &&
(src_max.z >= dst_max.z));
(src_max.z > dst_max.z));
}
Vector3 AABB::get_support(const Vector3 &p_direction) const {
Vector3 support = position;
if (p_direction.x > 0.0f) {
support.x += size.x;
}
if (p_direction.y > 0.0f) {
support.y += size.y;
}
if (p_direction.z > 0.0f) {
support.z += size.z;
}
return support;
Vector3 AABB::get_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 {
@@ -410,7 +402,7 @@ inline real_t AABB::get_shortest_axis_size() const {
return max_size;
}
bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t p_t0, real_t p_t1) const {
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.");
@@ -461,7 +453,7 @@ bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real
if (tzmax < tmax) {
tmax = tzmax;
}
return ((tmin < p_t1) && (tmax > p_t0));
return ((tmin < t1) && (tmax > t0));
}
void AABB::grow_by(real_t p_amount) {
@@ -498,3 +490,5 @@ AABB AABB::quantized(real_t p_unit) const {
}
} // namespace godot
#endif // GODOT_AABB_HPP

View File

@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
namespace godot {
namespace helpers {
template <typename T, typename ValueT>

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_BASIS_HPP
#define GODOT_BASIS_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/quaternion.hpp>
@@ -36,18 +37,18 @@
namespace godot {
struct [[nodiscard]] Basis {
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 p_row) const {
return rows[p_row];
_FORCE_INLINE_ const Vector3 &operator[](int axis) const {
return rows[axis];
}
_FORCE_INLINE_ Vector3 &operator[](int p_row) {
return rows[p_row];
_FORCE_INLINE_ Vector3 &operator[](int axis) {
return rows[axis];
}
void invert();
@@ -58,19 +59,21 @@ struct [[nodiscard]] Basis {
_FORCE_INLINE_ real_t determinant() const;
void from_z(const Vector3 &p_z);
void rotate(const Vector3 &p_axis, real_t p_angle);
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
void rotate_local(const Vector3 &p_axis, real_t p_angle);
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
void rotate(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ);
Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) 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 = EulerOrder::EULER_ORDER_YXZ) 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;
@@ -79,9 +82,9 @@ struct [[nodiscard]] Basis {
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ);
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) {
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;
@@ -101,29 +104,30 @@ struct [[nodiscard]] Basis {
void scale_orthogonal(const Vector3 &p_scale);
Basis scaled_orthogonal(const Vector3 &p_scale) const;
real_t get_uniform_scale() const;
void make_scale_uniform();
float get_uniform_scale() const;
Vector3 get_scale() const;
Vector3 get_scale_abs() const;
Vector3 get_scale_global() 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 = EulerOrder::EULER_ORDER_YXZ);
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 &p_v) const {
return rows[0][0] * p_v[0] + rows[1][0] * p_v[1] + rows[2][0] * p_v[2];
_FORCE_INLINE_ real_t 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 &p_v) const {
return rows[0][1] * p_v[0] + rows[1][1] * p_v[1] + rows[2][1] * p_v[2];
_FORCE_INLINE_ real_t 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 &p_v) const {
return rows[0][2] * p_v[0] + rows[1][2] * p_v[1] + rows[2][2] * p_v[2];
_FORCE_INLINE_ real_t tdotz(const Vector3 &v) const {
return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2];
}
bool is_equal_approx(const Basis &p_basis) const;
bool is_finite() const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
@@ -136,35 +140,31 @@ struct [[nodiscard]] Basis {
_FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const;
_FORCE_INLINE_ void operator-=(const Basis &p_matrix);
_FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const;
_FORCE_INLINE_ void operator*=(real_t p_val);
_FORCE_INLINE_ Basis operator*(real_t p_val) const;
_FORCE_INLINE_ void operator/=(real_t p_val);
_FORCE_INLINE_ Basis operator/(real_t p_val) const;
_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_orthonormal() const;
bool is_conformal() const;
bool is_diagonal() const;
bool is_rotation() const;
Basis lerp(const Basis &p_to, real_t p_weight) const;
Basis slerp(const Basis &p_to, real_t p_weight) 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 p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) {
rows[0][0] = p_xx;
rows[0][1] = p_xy;
rows[0][2] = p_xz;
rows[1][0] = p_yx;
rows[1][1] = p_yy;
rows[1][2] = p_yz;
rows[2][0] = p_zx;
rows[2][1] = p_zy;
rows[2][2] = p_zz;
_FORCE_INLINE_ void set(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);
@@ -194,20 +194,20 @@ struct [[nodiscard]] Basis {
rows[2].zero();
}
_FORCE_INLINE_ Basis transpose_xform(const Basis &p_m) const {
_FORCE_INLINE_ Basis transpose_xform(const Basis &m) const {
return Basis(
rows[0].x * p_m[0].x + rows[1].x * p_m[1].x + rows[2].x * p_m[2].x,
rows[0].x * p_m[0].y + rows[1].x * p_m[1].y + rows[2].x * p_m[2].y,
rows[0].x * p_m[0].z + rows[1].x * p_m[1].z + rows[2].x * p_m[2].z,
rows[0].y * p_m[0].x + rows[1].y * p_m[1].x + rows[2].y * p_m[2].x,
rows[0].y * p_m[0].y + rows[1].y * p_m[1].y + rows[2].y * p_m[2].y,
rows[0].y * p_m[0].z + rows[1].y * p_m[1].z + rows[2].y * p_m[2].z,
rows[0].z * p_m[0].x + rows[1].z * p_m[1].x + rows[2].z * p_m[2].x,
rows[0].z * p_m[0].y + rows[1].z * p_m[1].y + rows[2].z * p_m[2].y,
rows[0].z * p_m[0].z + rows[1].z * p_m[1].z + rows[2].z * p_m[2].z);
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 p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) {
set(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz);
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();
@@ -223,7 +223,7 @@ struct [[nodiscard]] Basis {
operator Quaternion() const { return get_quaternion(); }
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
@@ -281,30 +281,18 @@ _FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const {
return ret;
}
_FORCE_INLINE_ void Basis::operator*=(real_t p_val) {
_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*(real_t p_val) const {
_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const {
Basis ret(*this);
ret *= p_val;
return ret;
}
_FORCE_INLINE_ void Basis::operator/=(real_t p_val) {
rows[0] /= p_val;
rows[1] /= p_val;
rows[2] /= p_val;
}
_FORCE_INLINE_ Basis Basis::operator/(real_t p_val) const {
Basis ret(*this);
ret /= p_val;
return ret;
}
Vector3 Basis::xform(const Vector3 &p_vector) const {
return Vector3(
rows[0].dot(p_vector),
@@ -326,3 +314,5 @@ real_t Basis::determinant() const {
}
} // namespace godot
#endif // GODOT_BASIS_HPP

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_CHAR_STRING_HPP
#define GODOT_CHAR_STRING_HPP
#include <godot_cpp/templates/cowdata.hpp>
@@ -113,7 +114,7 @@ public:
CharStringT<T> &operator+=(T p_char);
int64_t length() const { return size() ? size() - 1 : 0; }
const T *get_data() const;
operator const T *() const { return get_data(); }
operator const T *() const { return get_data(); };
protected:
void copy_from(const T *p_cstr);
@@ -137,3 +138,5 @@ typedef CharStringT<char32_t> Char32String;
typedef CharStringT<wchar_t> CharWideString;
} // namespace godot
#endif // GODOT_CHAR_STRING_HPP

View File

@@ -28,107 +28,63 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_CHAR_UTILS_HPP
#define GODOT_CHAR_UTILS_HPP
#include "char_range.inc.hpp"
namespace godot {
#define BSEARCH_CHAR_RANGE(m_array) \
int low = 0; \
int high = sizeof(m_array) / sizeof(m_array[0]) - 1; \
int middle = (low + high) / 2; \
\
while (low <= high) { \
if (p_char < m_array[middle].start) { \
high = middle - 1; \
} else if (p_char > m_array[middle].end) { \
low = middle + 1; \
} else { \
return true; \
} \
\
middle = (low + high) / 2; \
} \
\
return false
constexpr bool is_unicode_identifier_start(char32_t p_char) {
BSEARCH_CHAR_RANGE(xid_start);
static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) {
return (c >= 'A' && c <= 'Z');
}
constexpr bool is_unicode_identifier_continue(char32_t p_char) {
BSEARCH_CHAR_RANGE(xid_continue);
static _FORCE_INLINE_ bool is_ascii_lower_case(char32_t c) {
return (c >= 'a' && c <= 'z');
}
constexpr bool is_unicode_upper_case(char32_t p_char) {
BSEARCH_CHAR_RANGE(uppercase_letter);
static _FORCE_INLINE_ bool is_digit(char32_t c) {
return (c >= '0' && c <= '9');
}
constexpr bool is_unicode_lower_case(char32_t p_char) {
BSEARCH_CHAR_RANGE(lowercase_letter);
static _FORCE_INLINE_ bool is_hex_digit(char32_t c) {
return (is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
constexpr bool is_unicode_letter(char32_t p_char) {
BSEARCH_CHAR_RANGE(unicode_letter);
static _FORCE_INLINE_ bool is_binary_digit(char32_t c) {
return (c == '0' || c == '1');
}
#undef BSEARCH_CHAR_RANGE
constexpr bool is_ascii_upper_case(char32_t p_char) {
return (p_char >= 'A' && p_char <= 'Z');
static _FORCE_INLINE_ bool is_ascii_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
constexpr bool is_ascii_lower_case(char32_t p_char) {
return (p_char >= 'a' && p_char <= 'z');
static _FORCE_INLINE_ bool is_ascii_alphanumeric_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
}
constexpr bool is_digit(char32_t p_char) {
return (p_char >= '0' && p_char <= '9');
static _FORCE_INLINE_ bool is_ascii_identifier_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
constexpr bool is_hex_digit(char32_t p_char) {
return (is_digit(p_char) || (p_char >= 'a' && p_char <= 'f') || (p_char >= 'A' && p_char <= 'F'));
static _FORCE_INLINE_ bool is_symbol(char32_t c) {
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
}
constexpr bool is_binary_digit(char32_t p_char) {
return (p_char == '0' || p_char == '1');
}
constexpr bool is_ascii_alphabet_char(char32_t p_char) {
return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z');
}
constexpr bool is_ascii_alphanumeric_char(char32_t p_char) {
return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z') || (p_char >= '0' && p_char <= '9');
}
constexpr bool is_ascii_identifier_char(char32_t p_char) {
return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z') || (p_char >= '0' && p_char <= '9') || p_char == '_';
}
constexpr bool is_symbol(char32_t p_char) {
return p_char != '_' && ((p_char >= '!' && p_char <= '/') || (p_char >= ':' && p_char <= '@') || (p_char >= '[' && p_char <= '`') || (p_char >= '{' && p_char <= '~') || p_char == '\t' || p_char == ' ');
}
constexpr bool is_control(char32_t p_char) {
static _FORCE_INLINE_ bool is_control(char32_t p_char) {
return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009f);
}
constexpr bool is_whitespace(char32_t p_char) {
return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200b) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
static _FORCE_INLINE_ bool is_whitespace(char32_t p_char) {
return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
}
constexpr bool is_linebreak(char32_t p_char) {
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);
}
constexpr bool is_punct(char32_t p_char) {
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);
}
constexpr bool is_underscore(char32_t p_char) {
static _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
return (p_char == '_');
}
} // namespace godot
#endif // GODOT_CHAR_UTILS_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_COLOR_HPP
#define GODOT_COLOR_HPP
#include <godot_cpp/core/math.hpp>
@@ -36,7 +37,7 @@ namespace godot {
class String;
struct [[nodiscard]] Color {
struct _NO_DISCARD_ Color {
union {
struct {
float r;
@@ -102,10 +103,12 @@ struct [[nodiscard]] Color {
_FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const {
Color res = *this;
res.r = Math::lerp(res.r, p_to.r, p_weight);
res.g = Math::lerp(res.g, p_to.g, p_weight);
res.b = Math::lerp(res.b, p_to.b, p_weight);
res.a = Math::lerp(res.a, p_to.a, p_weight);
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;
}
@@ -126,46 +129,33 @@ struct [[nodiscard]] Color {
}
_FORCE_INLINE_ uint32_t to_rgbe9995() const {
// https://github.com/microsoft/DirectX-Graphics-Samples/blob/v10.0.19041.0/MiniEngine/Core/Color.cpp
static const float kMaxVal = float(0x1FF << 7);
static const float kMinVal = float(1.f / (1 << 16));
const float pow2to9 = 512.0f;
const float B = 15.0f;
const float N = 9.0f;
// Clamp RGB to [0, 1.FF*2^16]
const float _r = CLAMP(r, 0.0f, kMaxVal);
const float _g = CLAMP(g, 0.0f, kMaxVal);
const float _b = CLAMP(b, 0.0f, kMaxVal);
float sharedexp = 65408.000f; // Result of: ((pow2to9 - 1.0f) / pow2to9) * powf(2.0f, 31.0f - 15.0f)
// Compute the maximum channel, no less than 1.0*2^-15
const float MaxChannel = MAX(MAX(_r, _g), MAX(_b, kMinVal));
float cRed = MAX(0.0f, MIN(sharedexp, r));
float cGreen = MAX(0.0f, MIN(sharedexp, g));
float cBlue = MAX(0.0f, MIN(sharedexp, b));
// Take the exponent of the maximum channel (rounding up the 9th bit) and
// add 15 to it. When added to the channels, it causes the implicit '1.0'
// bit and the first 8 mantissa bits to be shifted down to the low 9 bits
// of the mantissa, rounding the truncated bits.
union {
float f;
uint32_t i;
} R, G, B, E;
float cMax = MAX(cRed, MAX(cGreen, cBlue));
E.f = MaxChannel;
E.i += 0x07804000; // Add 15 to the exponent and 0x4000 to the mantissa
E.i &= 0x7F800000; // Zero the mantissa
float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
// This shifts the 9-bit values we need into the lowest bits, rounding as
// needed. Note that if the channel has a smaller exponent than the max
// channel, it will shift even more. This is intentional.
R.f = _r + E.f;
G.f = _g + E.f;
B.f = _b + E.f;
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
// Convert the Bias to the correct exponent in the upper 5 bits.
E.i <<= 4;
E.i += 0x10000000;
float exps = expp + 1.0f;
// Combine the fields. RGB floats have unwanted data in the upper 9
// bits. Only red needs to mask them off because green and blue shift
// it out to the left.
return E.i | (B.i << 18U) | (G.i << 9U) | (R.i & 511U);
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 {
@@ -184,16 +174,16 @@ struct [[nodiscard]] Color {
_FORCE_INLINE_ Color srgb_to_linear() const {
return Color(
r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow(float((r + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f),
g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow(float((g + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f),
b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow(float((b + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f),
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.0 + 0.055) * Math::pow(r, 1.0f / 2.4f) - 0.055,
g < 0.0031308f ? 12.92f * g : (1.0 + 0.055) * Math::pow(g, 1.0f / 2.4f) - 0.055,
b < 0.0031308f ? 12.92f * b : (1.0 + 0.055) * Math::pow(b, 1.0f / 2.4f) - 0.055, a);
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);
@@ -209,7 +199,6 @@ struct [[nodiscard]] Color {
static Color from_string(const String &p_string, const Color &p_default);
static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
static Color from_rgbe9995(uint32_t p_rgbe);
static Color from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8 = 255);
_FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys.
operator String() const;
@@ -296,3 +285,5 @@ _FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) {
}
} // namespace godot
#endif // GODOT_COLOR_HPP

View File

@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
namespace godot {
// Names from https://en.wikipedia.org/wiki/X11_color_names
@@ -187,6 +185,7 @@ static NamedColor named_colors[] = {
{ "WHITE_SMOKE", Color::hex(0xF5F5F5FF) },
{ "YELLOW", Color::hex(0xFFFF00FF) },
{ "YELLOW_GREEN", Color::hex(0x9ACD32FF) },
{ nullptr, Color() },
};
} // namespace godot

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_PLANE_HPP
#define GODOT_PLANE_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/vector3.hpp>
@@ -37,7 +38,7 @@ namespace godot {
class Variant;
struct [[nodiscard]] Plane {
struct _NO_DISCARD_ Plane {
Vector3 normal;
real_t d = 0;
@@ -49,7 +50,7 @@ struct [[nodiscard]] Plane {
/* Plane-Point operations */
_FORCE_INLINE_ Vector3 get_center() const { return normal * d; }
_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
@@ -76,7 +77,6 @@ struct [[nodiscard]] Plane {
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const;
bool is_finite() const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
@@ -136,3 +136,5 @@ bool Plane::operator!=(const Plane &p_plane) const {
}
} // namespace godot
#endif // GODOT_PLANE_HPP

View File

@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_PROJECTION_HPP
#define GODOT_PROJECTION_HPP
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/vector4.hpp>
@@ -44,7 +44,7 @@ struct Rect2;
struct Transform3D;
struct Vector2;
struct [[nodiscard]] Projection {
struct _NO_DISCARD_ Projection {
enum Planes {
PLANE_NEAR,
PLANE_FAR,
@@ -56,21 +56,21 @@ struct [[nodiscard]] Projection {
Vector4 columns[4];
_FORCE_INLINE_ const Vector4 &operator[](int p_axis) const {
_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[](int p_axis) {
_FORCE_INLINE_ Vector4 &operator[](const int p_axis) {
DEV_ASSERT((unsigned int)p_axis < 4);
return columns[p_axis];
}
real_t determinant() const;
float determinant() const;
void set_identity();
void set_zero();
void set_light_bias();
void set_depth_correction(bool p_flip_y = true, bool p_reverse_z = true, bool p_remap_z = true);
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);
@@ -107,7 +107,7 @@ struct [[nodiscard]] Projection {
real_t get_fov() const;
bool is_orthogonal() const;
Vector<Plane> get_projection_planes(const Transform3D &p_transform) 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;
@@ -149,11 +149,10 @@ struct [[nodiscard]] Projection {
return !(*this == p_cam);
}
real_t get_lod_multiplier() const;
float get_lod_multiplier() const;
Projection();
Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w);
Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww);
Projection(const Transform3D &p_transform);
~Projection();
};
@@ -168,3 +167,5 @@ Vector3 Projection::xform(const Vector3 &p_vec3) const {
}
} // namespace godot
#endif // GODOT_PROJECTION_HPP

View File

@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_QUATERNION_HPP
#define GODOT_QUATERNION_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/vector3.hpp>
namespace godot {
struct [[nodiscard]] Quaternion {
struct _NO_DISCARD_ Quaternion {
union {
struct {
real_t x;
@@ -47,15 +47,14 @@ struct [[nodiscard]] Quaternion {
real_t components[4] = { 0, 0, 0, 1.0 };
};
_FORCE_INLINE_ real_t &operator[](int p_idx) {
return components[p_idx];
_FORCE_INLINE_ real_t &operator[](int idx) {
return components[idx];
}
_FORCE_INLINE_ const real_t &operator[](int p_idx) const {
return components[p_idx];
_FORCE_INLINE_ const real_t &operator[](int idx) const {
return components[idx];
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
bool is_finite() const;
real_t length() const;
void normalize();
Quaternion normalized() const;
@@ -66,13 +65,14 @@ struct [[nodiscard]] Quaternion {
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
static Quaternion from_euler(const Vector3 &p_euler);
Vector3 get_euler_xyz() const;
Vector3 get_euler_yxz() const;
Vector3 get_euler() const { return get_euler_yxz(); }
Quaternion slerp(const Quaternion &p_to, real_t p_weight) const;
Quaternion slerpni(const Quaternion &p_to, real_t p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight) const;
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const;
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
Vector3 get_axis() const;
real_t get_angle() const;
@@ -88,28 +88,28 @@ struct [[nodiscard]] Quaternion {
void operator*=(const Quaternion &p_q);
Quaternion operator*(const Quaternion &p_q) const;
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_v) const {
_FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), p_v, "The quaternion " + operator String() + " must be normalized.");
ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized.");
#endif
Vector3 u(x, y, z);
Vector3 uv = u.cross(p_v);
return p_v + ((uv * w) + u.cross(uv)) * ((real_t)2);
Vector3 uv = u.cross(v);
return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
}
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_v) const {
return inverse().xform(p_v);
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
return inverse().xform(v);
}
_FORCE_INLINE_ void operator+=(const Quaternion &p_q);
_FORCE_INLINE_ void operator-=(const Quaternion &p_q);
_FORCE_INLINE_ void operator*=(real_t p_s);
_FORCE_INLINE_ void operator/=(real_t p_s);
_FORCE_INLINE_ Quaternion operator+(const Quaternion &p_q2) const;
_FORCE_INLINE_ Quaternion operator-(const Quaternion &p_q2) const;
_FORCE_INLINE_ void operator*=(const real_t &s);
_FORCE_INLINE_ void operator/=(const real_t &s);
_FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const;
_FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const;
_FORCE_INLINE_ Quaternion operator-() const;
_FORCE_INLINE_ Quaternion operator*(real_t p_s) const;
_FORCE_INLINE_ Quaternion operator/(real_t p_s) const;
_FORCE_INLINE_ Quaternion operator*(const real_t &s) const;
_FORCE_INLINE_ Quaternion operator/(const real_t &s) const;
_FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const;
_FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const;
@@ -127,6 +127,8 @@ struct [[nodiscard]] Quaternion {
Quaternion(const Vector3 &p_axis, real_t p_angle);
Quaternion(const Vector3 &p_euler);
Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
@@ -141,25 +143,16 @@ struct [[nodiscard]] Quaternion {
w = p_q.w;
}
Quaternion(const Vector3 &p_v0, const Vector3 &p_v1) { // Shortest arc.
#ifdef MATH_CHECKS
ERR_FAIL_COND_MSG(p_v0.is_zero_approx() || p_v1.is_zero_approx(), "The vectors must not be zero.");
#endif
constexpr real_t ALMOST_ONE = 1.0f - (real_t)CMP_EPSILON;
Vector3 n0 = p_v0.normalized();
Vector3 n1 = p_v1.normalized();
real_t d = n0.dot(n1);
if (Math::abs(d) > ALMOST_ONE) {
if (d >= 0) {
return; // Vectors are same.
}
Vector3 axis = n0.get_any_perpendicular();
x = axis.x;
y = axis.y;
z = axis.z;
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 {
Vector3 c = n0.cross(n1);
real_t s = Math::sqrt((1.0f + d) * 2.0f);
real_t rs = 1.0f / s;
@@ -193,25 +186,25 @@ void Quaternion::operator-=(const Quaternion &p_q) {
w -= p_q.w;
}
void Quaternion::operator*=(real_t p_s) {
x *= p_s;
y *= p_s;
z *= p_s;
w *= p_s;
void Quaternion::operator*=(const real_t &s) {
x *= s;
y *= s;
z *= s;
w *= s;
}
void Quaternion::operator/=(real_t p_s) {
*this *= 1.0f / p_s;
void Quaternion::operator/=(const real_t &s) {
*this *= 1.0f / s;
}
Quaternion Quaternion::operator+(const Quaternion &p_q2) const {
Quaternion Quaternion::operator+(const Quaternion &q2) const {
const Quaternion &q1 = *this;
return Quaternion(q1.x + p_q2.x, q1.y + p_q2.y, q1.z + p_q2.z, q1.w + p_q2.w);
return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
}
Quaternion Quaternion::operator-(const Quaternion &p_q2) const {
Quaternion Quaternion::operator-(const Quaternion &q2) const {
const Quaternion &q1 = *this;
return Quaternion(q1.x - p_q2.x, q1.y - p_q2.y, q1.z - p_q2.z, q1.w - p_q2.w);
return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
}
Quaternion Quaternion::operator-() const {
@@ -219,12 +212,12 @@ Quaternion Quaternion::operator-() const {
return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w);
}
Quaternion Quaternion::operator*(real_t p_s) const {
return Quaternion(x * p_s, y * p_s, z * p_s, w * p_s);
Quaternion Quaternion::operator*(const real_t &s) const {
return Quaternion(x * s, y * s, z * s, w * s);
}
Quaternion Quaternion::operator/(real_t p_s) const {
return *this * (1.0f / p_s);
Quaternion Quaternion::operator/(const real_t &s) const {
return *this * (1.0f / s);
}
bool Quaternion::operator==(const Quaternion &p_quaternion) const {
@@ -235,8 +228,10 @@ bool Quaternion::operator!=(const Quaternion &p_quaternion) const {
return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w;
}
_FORCE_INLINE_ Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) {
_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) {
return p_quaternion * p_real;
}
} // namespace godot
#endif // GODOT_QUATERNION_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_RECT2_HPP
#define GODOT_RECT2_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/vector2.hpp>
@@ -39,7 +40,7 @@ class String;
struct Rect2i;
struct Transform2D;
struct [[nodiscard]] Rect2 {
struct _NO_DISCARD_ Rect2 {
Point2 position;
Size2 size;
@@ -52,7 +53,7 @@ struct [[nodiscard]] Rect2 {
_FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5f); }
inline bool intersects(const Rect2 &p_rect, bool p_include_borders = false) const {
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.");
@@ -105,17 +106,17 @@ struct [[nodiscard]] Rect2 {
}
if (p_point.y < position.y) {
real_t d = position.y - p_point.y;
dist = inside ? d : MIN(dist, d);
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 : MIN(dist, d);
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 : MIN(dist, d);
dist = inside ? d : Math::min(dist, d);
inside = false;
}
@@ -145,7 +146,7 @@ struct [[nodiscard]] Rect2 {
return size.x > 0.0f && size.y > 0.0f;
}
// Returns the intersection between two Rect2s or an empty Rect2 if there is no intersection.
// Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
inline Rect2 intersection(const Rect2 &p_rect) const {
Rect2 new_rect = p_rect;
@@ -153,12 +154,14 @@ struct [[nodiscard]] Rect2 {
return Rect2();
}
new_rect.position = p_rect.position.max(position);
new_rect.position.x = Math::max(p_rect.position.x, position.x);
new_rect.position.y = Math::max(p_rect.position.y, position.y);
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
new_rect.size = p_rect_end.min(end) - new_rect.position;
new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
return new_rect;
}
@@ -171,9 +174,11 @@ struct [[nodiscard]] Rect2 {
#endif
Rect2 new_rect;
new_rect.position = p_rect.position.min(position);
new_rect.position.x = Math::min(p_rect.position.x, position.x);
new_rect.position.y = Math::min(p_rect.position.y, position.y);
new_rect.size = (p_rect.position + p_rect.size).max(position + size);
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
@@ -204,7 +209,6 @@ struct [[nodiscard]] Rect2 {
}
bool is_equal_approx(const Rect2 &p_rect) const;
bool is_finite() const;
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -279,22 +283,16 @@ struct [[nodiscard]] Rect2 {
}
_FORCE_INLINE_ Rect2 abs() const {
return Rect2(position + size.minf(0), size.abs());
return Rect2(Point2(position.x + Math::min(size.x, (real_t)0), position.y + Math::min(size.y, (real_t)0)), size.abs());
}
_FORCE_INLINE_ Rect2 round() const {
return Rect2(position.round(), size.round());
}
Vector2 get_support(const Vector2 &p_direction) const {
Vector2 support = position;
if (p_direction.x > 0.0f) {
support.x += size.x;
}
if (p_direction.y > 0.0f) {
support.y += size.y;
}
return support;
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 {
@@ -310,14 +308,14 @@ struct [[nodiscard]] Rect2 {
i_f = i;
Vector2 r = (b - a);
const real_t l = r.length();
float l = r.length();
if (l == 0.0f) {
continue;
}
// Check inside.
Vector2 tg = r.orthogonal();
const real_t s = tg.dot(center) - tg.dot(a);
float s = tg.dot(center) - tg.dot(a);
if (s < 0.0f) {
side_plus++;
} else {
@@ -333,8 +331,8 @@ struct [[nodiscard]] Rect2 {
Vector2 t13 = (position - a) * ir;
Vector2 t24 = (end - a) * ir;
const real_t tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y));
const real_t tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y));
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) {
@@ -374,3 +372,5 @@ struct [[nodiscard]] Rect2 {
};
} // namespace godot
#endif // GODOT_RECT2_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_RECT2I_HPP
#define GODOT_RECT2I_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/vector2i.hpp>
@@ -38,7 +39,7 @@ namespace godot {
class String;
struct Rect2;
struct [[nodiscard]] Rect2i {
struct _NO_DISCARD_ Rect2i {
Point2i position;
Size2i size;
@@ -88,7 +89,7 @@ struct [[nodiscard]] Rect2i {
return size.x > 0 && size.y > 0;
}
// Returns the intersection between two Rect2is or an empty Rect2i if there is no intersection.
// Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection
inline Rect2i intersection(const Rect2i &p_rect) const {
Rect2i new_rect = p_rect;
@@ -96,12 +97,14 @@ struct [[nodiscard]] Rect2i {
return Rect2i();
}
new_rect.position = p_rect.position.max(position);
new_rect.position.x = Math::max(p_rect.position.x, position.x);
new_rect.position.y = Math::max(p_rect.position.y, position.y);
Point2i p_rect_end = p_rect.position + p_rect.size;
Point2i end = position + size;
new_rect.size = p_rect_end.min(end) - new_rect.position;
new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
return new_rect;
}
@@ -114,9 +117,11 @@ struct [[nodiscard]] Rect2i {
#endif
Rect2i new_rect;
new_rect.position = p_rect.position.min(position);
new_rect.position.x = Math::min(p_rect.position.x, position.x);
new_rect.position.y = Math::min(p_rect.position.y, position.y);
new_rect.size = (p_rect.position + p_rect.size).max(position + size);
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
@@ -214,7 +219,7 @@ struct [[nodiscard]] Rect2i {
}
_FORCE_INLINE_ Rect2i abs() const {
return Rect2i(position + size.mini(0), size.abs());
return Rect2i(Point2i(position.x + Math::min(size.x, 0), position.y + Math::min(size.y, 0)), size.abs());
}
_FORCE_INLINE_ void set_end(const Vector2i &p_end) {
@@ -240,3 +245,5 @@ struct [[nodiscard]] Rect2i {
};
} // namespace godot
#endif // GODOT_RECT2I_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_TRANSFORM2D_HPP
#define GODOT_TRANSFORM2D_HPP
#include <godot_cpp/variant/packed_vector2_array.hpp>
#include <godot_cpp/variant/rect2.hpp>
@@ -38,25 +39,22 @@ namespace godot {
class String;
struct [[nodiscard]] Transform2D {
// WARNING: The basis of Transform2D is stored differently from Basis.
// In terms of columns array, the basis matrix looks like "on paper":
struct _NO_DISCARD_ Transform2D {
// Warning #1: basis of Transform2D is stored differently from Basis. In terms of columns array, the basis matrix looks like "on paper":
// M = (columns[0][0] columns[1][0])
// (columns[0][1] columns[1][1])
// This is such that the columns, which can be interpreted as basis vectors
// of the coordinate system "painted" on the object, can be accessed as columns[i].
// NOTE: This is the opposite of the indices in mathematical texts,
// meaning: $M_{12}$ in a math book corresponds to columns[1][0] here.
// This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as columns[i].
// Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to columns[1][0] here.
// This requires additional care when working with explicit indices.
// See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading.
// WARNING: Be aware that unlike 3D code, 2D code uses a left-handed coordinate system:
// Y-axis points down, and angle is measure from +X to +Y in a clockwise-fashion.
// 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 columns[3];
_FORCE_INLINE_ real_t tdotx(const Vector2 &p_v) const { return columns[0][0] * p_v.x + columns[1][0] * p_v.y; }
_FORCE_INLINE_ real_t tdoty(const Vector2 &p_v) const { return columns[0][1] * p_v.x + columns[1][1] * p_v.y; }
_FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return columns[0][0] * v.x + columns[1][0] * v.y; }
_FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return columns[0][1] * v.x + columns[1][1] * v.y; }
const Vector2 &operator[](int p_idx) const { return columns[p_idx]; }
Vector2 &operator[](int p_idx) { return columns[p_idx]; }
@@ -67,20 +65,20 @@ struct [[nodiscard]] Transform2D {
void affine_invert();
Transform2D affine_inverse() const;
void set_rotation(real_t p_rot);
void set_rotation(const real_t p_rot);
real_t get_rotation() const;
real_t get_skew() const;
void set_skew(real_t p_angle);
_FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale);
_FORCE_INLINE_ void set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, real_t p_skew);
void rotate(real_t p_angle);
void set_skew(const real_t p_angle);
_FORCE_INLINE_ void set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale);
_FORCE_INLINE_ void set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew);
void rotate(const real_t p_angle);
void scale(const Size2 &p_scale);
void scale_basis(const Size2 &p_scale);
void translate_local(real_t p_tx, real_t p_ty);
void translate_local(const real_t p_tx, const real_t p_ty);
void translate_local(const Vector2 &p_translation);
real_t determinant() const;
real_t basis_determinant() const;
Size2 get_scale() const;
void set_scale(const Size2 &p_scale);
@@ -88,20 +86,19 @@ struct [[nodiscard]] Transform2D {
_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
Transform2D basis_scaled(const Size2 &p_scale) const;
Transform2D scaled(const Size2 &p_scale) const;
Transform2D scaled_local(const Size2 &p_scale) const;
Transform2D translated(const Vector2 &p_offset) const;
Transform2D translated_local(const Vector2 &p_offset) const;
Transform2D rotated(real_t p_angle) const;
Transform2D rotated_local(real_t p_angle) const;
Transform2D rotated(const real_t p_angle) const;
Transform2D rotated_local(const real_t p_angle) const;
Transform2D untranslated() const;
void orthonormalize();
Transform2D orthonormalized() const;
bool is_conformal() const;
bool is_equal_approx(const Transform2D &p_transform) const;
bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const;
@@ -110,12 +107,10 @@ struct [[nodiscard]] Transform2D {
void operator*=(const Transform2D &p_transform);
Transform2D operator*(const Transform2D &p_transform) const;
void operator*=(real_t p_val);
Transform2D operator*(real_t p_val) const;
void operator/=(real_t p_val);
Transform2D operator/(real_t p_val) const;
void operator*=(const real_t p_val);
Transform2D operator*(const real_t p_val) const;
Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const;
Transform2D interpolate_with(const Transform2D &p_transform, const real_t p_c) const;
_FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const;
_FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const;
@@ -128,13 +123,13 @@ struct [[nodiscard]] Transform2D {
operator String() const;
Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) {
columns[0][0] = p_xx;
columns[0][1] = p_xy;
columns[1][0] = p_yx;
columns[1][1] = p_yy;
columns[2][0] = p_ox;
columns[2][1] = p_oy;
Transform2D(const real_t xx, const real_t xy, const real_t yx, const real_t yy, const real_t ox, const real_t oy) {
columns[0][0] = xx;
columns[0][1] = xy;
columns[1][0] = yx;
columns[1][1] = yy;
columns[2][0] = ox;
columns[2][1] = oy;
}
Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) {
@@ -143,9 +138,9 @@ struct [[nodiscard]] Transform2D {
columns[2] = p_origin;
}
Transform2D(real_t p_rot, const Vector2 &p_pos);
Transform2D(const real_t p_rot, const Vector2 &p_pos);
Transform2D(real_t p_rot, const Size2 &p_scale, real_t p_skew, const Vector2 &p_pos);
Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos);
Transform2D() {
columns[0][0] = 1.0;
@@ -193,14 +188,14 @@ Rect2 Transform2D::xform(const Rect2 &p_rect) const {
return new_rect;
}
void Transform2D::set_rotation_and_scale(real_t p_rot, const Size2 &p_scale) {
void Transform2D::set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale) {
columns[0][0] = Math::cos(p_rot) * p_scale.x;
columns[1][1] = Math::cos(p_rot) * p_scale.y;
columns[1][0] = -Math::sin(p_rot) * p_scale.y;
columns[0][1] = Math::sin(p_rot) * p_scale.x;
}
void Transform2D::set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, real_t p_skew) {
void Transform2D::set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew) {
columns[0][0] = Math::cos(p_rot) * p_scale.x;
columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
@@ -251,3 +246,5 @@ PackedVector2Array Transform2D::xform_inv(const PackedVector2Array &p_array) con
}
} // namespace godot
#endif // GODOT_TRANSFORM2D_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_TRANSFORM3D_HPP
#define GODOT_TRANSFORM3D_HPP
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/aabb.hpp>
@@ -38,7 +39,7 @@
namespace godot {
struct [[nodiscard]] Transform3D {
struct _NO_DISCARD_ Transform3D {
Basis basis;
Vector3 origin;
@@ -54,8 +55,8 @@ struct [[nodiscard]] Transform3D {
void rotate(const Vector3 &p_axis, real_t p_angle);
void rotate_basis(const Vector3 &p_axis, real_t p_angle);
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false) const;
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const;
void scale(const Vector3 &p_scale);
Transform3D scaled(const Vector3 &p_scale) const;
@@ -77,7 +78,6 @@ struct [[nodiscard]] Transform3D {
void orthogonalize();
Transform3D orthogonalized() const;
bool is_equal_approx(const Transform3D &p_transform) const;
bool is_finite() const;
bool operator==(const Transform3D &p_transform) const;
bool operator!=(const Transform3D &p_transform) const;
@@ -104,10 +104,8 @@ struct [[nodiscard]] Transform3D {
void operator*=(const Transform3D &p_transform);
Transform3D operator*(const Transform3D &p_transform) const;
void operator*=(real_t p_val);
Transform3D operator*(real_t p_val) const;
void operator/=(real_t p_val);
Transform3D operator/(real_t p_val) const;
void operator*=(const real_t p_val);
Transform3D operator*(const real_t p_val) const;
Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const;
@@ -117,11 +115,11 @@ struct [[nodiscard]] Transform3D {
basis.xform(v));
}
void set(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_tx, real_t p_ty, real_t p_tz) {
basis.set(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz);
origin.x = p_tx;
origin.y = p_ty;
origin.z = p_tz;
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) {
basis.set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
origin.x = tx;
origin.y = ty;
origin.z = tz;
}
operator String() const;
@@ -129,7 +127,7 @@ struct [[nodiscard]] Transform3D {
Transform3D() {}
Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3());
Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin);
Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz);
Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz);
};
_FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const {
@@ -273,3 +271,5 @@ _FORCE_INLINE_ Plane Transform3D::xform_inv_fast(const Plane &p_plane, const Tra
}
} // namespace godot
#endif // GODOT_TRANSFORM3D_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_TYPED_ARRAY_HPP
#define GODOT_TYPED_ARRAY_HPP
#include <godot_cpp/variant/array.hpp>
#include <godot_cpp/variant/variant.hpp>
@@ -40,21 +41,14 @@ class TypedArray : public Array {
public:
_FORCE_INLINE_ void operator=(const Array &p_array) {
ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type.");
Array::operator=(p_array);
_ref(p_array);
}
_FORCE_INLINE_ TypedArray(const Variant &p_variant) :
TypedArray(Array(p_variant)) {
Array(p_variant.operator Array(), Variant::OBJECT, T::get_class_static(), Variant()) {
}
_FORCE_INLINE_ TypedArray(const Array &p_array) {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
if (is_same_typed(p_array)) {
Array::operator=(p_array);
} else {
assign(p_array);
}
_FORCE_INLINE_ TypedArray(const Array &p_array) :
Array(p_array, Variant::OBJECT, T::get_class_static(), Variant()) {
}
_FORCE_INLINE_ TypedArray(std::initializer_list<Variant> p_init) :
TypedArray(Array(p_init)) {}
_FORCE_INLINE_ TypedArray() {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
}
@@ -68,29 +62,19 @@ public:
public: \
_FORCE_INLINE_ void operator=(const Array &p_array) { \
ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type."); \
Array::operator=(p_array); \
} \
_FORCE_INLINE_ TypedArray(std::initializer_list<Variant> p_init) : \
Array(Array(p_init), m_variant_type, StringName(), Variant()) { \
_ref(p_array); \
} \
_FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
TypedArray(Array(p_variant)) { \
Array(p_variant.operator Array(), m_variant_type, StringName(), Variant()) { \
} \
_FORCE_INLINE_ TypedArray(const Array &p_array) { \
set_typed(m_variant_type, StringName(), Variant()); \
if (is_same_typed(p_array)) { \
Array::operator=(p_array); \
} else { \
assign(p_array); \
} \
_FORCE_INLINE_ TypedArray(const Array &p_array) : \
Array(p_array, m_variant_type, StringName(), Variant()) { \
} \
_FORCE_INLINE_ TypedArray() { \
set_typed(m_variant_type, StringName(), Variant()); \
} \
};
// All Variant::OBJECT types are intentionally omitted from this list because they are handled by
// the unspecialized TypedArray definition.
MAKE_TYPED_ARRAY(bool, Variant::BOOL)
MAKE_TYPED_ARRAY(uint8_t, Variant::INT)
MAKE_TYPED_ARRAY(int8_t, Variant::INT)
@@ -110,14 +94,11 @@ MAKE_TYPED_ARRAY(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY(Vector4, Variant::VECTOR4)
MAKE_TYPED_ARRAY(Vector4i, Variant::VECTOR4I)
MAKE_TYPED_ARRAY(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY(AABB, Variant::AABB)
MAKE_TYPED_ARRAY(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY(Projection, Variant::PROJECTION)
MAKE_TYPED_ARRAY(Color, Variant::COLOR)
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
@@ -134,11 +115,8 @@ MAKE_TYPED_ARRAY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_ARRAY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
// If the IPAddress struct is added to godot-cpp, the following could also be added:
//MAKE_TYPED_ARRAY(IPAddress, Variant::STRING)
#undef MAKE_TYPED_ARRAY
} // namespace godot
#endif // GODOT_TYPED_ARRAY_HPP

View File

@@ -1,465 +0,0 @@
/**************************************************************************/
/* typed_dictionary.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include <godot_cpp/core/type_info.hpp>
#include <godot_cpp/templates/pair.hpp>
#include <godot_cpp/variant/dictionary.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
template <typename K, typename V>
class TypedDictionary : public Dictionary {
public:
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) {
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign a dictionary with a different element type.");
Dictionary::operator=(p_dictionary);
}
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) :
TypedDictionary(Dictionary(p_variant)) {
}
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) {
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
if (is_same_typed(p_dictionary)) {
Dictionary::operator=(p_dictionary);
} else {
assign(p_dictionary);
}
}
_FORCE_INLINE_ TypedDictionary() {
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
}
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<K, V>> p_init) :
Dictionary() {
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
for (const KeyValue<K, V> &E : p_init) {
operator[](E.key) = E.value;
}
}
};
//specialization for the rest of variant types
#define MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \
template <typename T> \
class TypedDictionary<T, m_type> : public Dictionary { \
public: \
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
Dictionary::operator=(p_dictionary); \
} \
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
TypedDictionary(Dictionary(p_variant)) { \
} \
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
if (is_same_typed(p_dictionary)) { \
Dictionary::operator=(p_dictionary); \
} else { \
assign(p_dictionary); \
} \
} \
_FORCE_INLINE_ TypedDictionary() { \
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
} \
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<T, m_type>> p_init) : \
Dictionary() { \
set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \
for (const KeyValue<T, m_type> &E : p_init) { \
operator[](E.key) = E.value; \
} \
} \
}; \
template <typename T> \
class TypedDictionary<m_type, T> : public Dictionary { \
public: \
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
Dictionary::operator=(p_dictionary); \
} \
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
TypedDictionary(Dictionary(p_variant)) { \
} \
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \
if (is_same_typed(p_dictionary)) { \
Dictionary::operator=(p_dictionary); \
} else { \
assign(p_dictionary); \
} \
} \
_FORCE_INLINE_ TypedDictionary() { \
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \
} \
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<m_type, T>> p_init) : \
Dictionary() { \
set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, std::remove_pointer<T>::type::get_class_static(), Variant()); \
for (const KeyValue<m_type, T> &E : p_init) { \
operator[](E.key) = E.value; \
} \
} \
};
#define MAKE_TYPED_DICTIONARY_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \
template <> \
class TypedDictionary<m_type_key, m_type_value> : public Dictionary { \
public: \
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \
Dictionary::operator=(p_dictionary); \
} \
_FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \
TypedDictionary(Dictionary(p_variant)) { \
} \
_FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
if (is_same_typed(p_dictionary)) { \
Dictionary::operator=(p_dictionary); \
} else { \
assign(p_dictionary); \
} \
} \
_FORCE_INLINE_ TypedDictionary() { \
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
} \
_FORCE_INLINE_ TypedDictionary(std::initializer_list<KeyValue<m_type_key, m_type_value>> p_init) : \
Dictionary() { \
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
for (const KeyValue<m_type_key, m_type_value> &E : p_init) { \
operator[](E.key) = E.value; \
} \
} \
};
#define MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \
/*MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING)*/
#define MAKE_TYPED_DICTIONARY(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \
MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type)
MAKE_TYPED_DICTIONARY_NIL(Variant, Variant::NIL)
MAKE_TYPED_DICTIONARY(bool, Variant::BOOL)
MAKE_TYPED_DICTIONARY(uint8_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int8_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint16_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int16_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint32_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int32_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint64_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int64_t, Variant::INT)
MAKE_TYPED_DICTIONARY(float, Variant::FLOAT)
MAKE_TYPED_DICTIONARY(double, Variant::FLOAT)
MAKE_TYPED_DICTIONARY(String, Variant::STRING)
MAKE_TYPED_DICTIONARY(Vector2, Variant::VECTOR2)
MAKE_TYPED_DICTIONARY(Vector2i, Variant::VECTOR2I)
MAKE_TYPED_DICTIONARY(Rect2, Variant::RECT2)
MAKE_TYPED_DICTIONARY(Rect2i, Variant::RECT2I)
MAKE_TYPED_DICTIONARY(Vector3, Variant::VECTOR3)
MAKE_TYPED_DICTIONARY(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_DICTIONARY(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_DICTIONARY(Plane, Variant::PLANE)
MAKE_TYPED_DICTIONARY(Quaternion, Variant::QUATERNION)
MAKE_TYPED_DICTIONARY(AABB, Variant::AABB)
MAKE_TYPED_DICTIONARY(Basis, Variant::BASIS)
MAKE_TYPED_DICTIONARY(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_DICTIONARY(Color, Variant::COLOR)
MAKE_TYPED_DICTIONARY(StringName, Variant::STRING_NAME)
MAKE_TYPED_DICTIONARY(NodePath, Variant::NODE_PATH)
MAKE_TYPED_DICTIONARY(RID, Variant::RID)
MAKE_TYPED_DICTIONARY(Callable, Variant::CALLABLE)
MAKE_TYPED_DICTIONARY(Signal, Variant::SIGNAL)
MAKE_TYPED_DICTIONARY(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_DICTIONARY(Array, Variant::ARRAY)
MAKE_TYPED_DICTIONARY(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_DICTIONARY(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_DICTIONARY(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_DICTIONARY(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_DICTIONARY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_DICTIONARY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_DICTIONARY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
/*
MAKE_TYPED_DICTIONARY(IPAddress, Variant::STRING)
*/
#undef MAKE_TYPED_DICTIONARY
#undef MAKE_TYPED_DICTIONARY_NIL
#undef MAKE_TYPED_DICTIONARY_EXPANDED
#undef MAKE_TYPED_DICTIONARY_WITH_OBJECT
template <typename K, typename V>
struct PtrToArg<TypedDictionary<K, V>> {
_FORCE_INLINE_ static TypedDictionary<K, V> convert(const void *p_ptr) {
return TypedDictionary<K, V>(*reinterpret_cast<const Dictionary *>(p_ptr));
}
typedef Dictionary EncodeT;
_FORCE_INLINE_ static void encode(TypedDictionary<K, V> p_val, void *p_ptr) {
*(Dictionary *)p_ptr = p_val;
}
};
template <typename K, typename V>
struct PtrToArg<const TypedDictionary<K, V> &> {
typedef Dictionary EncodeT;
_FORCE_INLINE_ static TypedDictionary<K, V>
convert(const void *p_ptr) {
return TypedDictionary<K, V>(*reinterpret_cast<const Dictionary *>(p_ptr));
}
};
template <typename K, typename V>
struct GetTypeInfo<TypedDictionary<K, V>> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static()));
}
};
template <typename K, typename V>
struct GetTypeInfo<const TypedDictionary<K, V> &> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static()));
}
};
#define MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT(m_type, m_variant_type) \
template <typename T> \
struct GetTypeInfo<TypedDictionary<T, m_type>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<const TypedDictionary<T, m_type> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<TypedDictionary<m_type, T>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data(), T::get_class_static())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<const TypedDictionary<m_type, T> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data(), T::get_class_static())); \
} \
};
#define MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \
template <> \
struct GetTypeInfo<TypedDictionary<m_type_key, m_type_value>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type_key == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key).utf8().get_data(), \
m_variant_type_value == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value).utf8().get_data())); \
} \
}; \
template <> \
struct GetTypeInfo<const TypedDictionary<m_type_key, m_type_value> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type_key == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key).utf8().get_data(), \
m_variant_type_value == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value).utf8().get_data())); \
} \
};
#define MAKE_TYPED_DICTIONARY_INFO_NIL(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \
/* MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING) */
#define MAKE_TYPED_DICTIONARY_INFO(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \
MAKE_TYPED_DICTIONARY_INFO_NIL(m_type, m_variant_type)
MAKE_TYPED_DICTIONARY_INFO_NIL(Variant, Variant::NIL)
MAKE_TYPED_DICTIONARY_INFO(bool, Variant::BOOL)
MAKE_TYPED_DICTIONARY_INFO(uint8_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int8_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint16_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int16_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint32_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int32_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint64_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int64_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(float, Variant::FLOAT)
MAKE_TYPED_DICTIONARY_INFO(double, Variant::FLOAT)
MAKE_TYPED_DICTIONARY_INFO(String, Variant::STRING)
MAKE_TYPED_DICTIONARY_INFO(Vector2, Variant::VECTOR2)
MAKE_TYPED_DICTIONARY_INFO(Vector2i, Variant::VECTOR2I)
MAKE_TYPED_DICTIONARY_INFO(Rect2, Variant::RECT2)
MAKE_TYPED_DICTIONARY_INFO(Rect2i, Variant::RECT2I)
MAKE_TYPED_DICTIONARY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_DICTIONARY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_DICTIONARY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_DICTIONARY_INFO(Plane, Variant::PLANE)
MAKE_TYPED_DICTIONARY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_DICTIONARY_INFO(AABB, Variant::AABB)
MAKE_TYPED_DICTIONARY_INFO(Basis, Variant::BASIS)
MAKE_TYPED_DICTIONARY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_DICTIONARY_INFO(Color, Variant::COLOR)
MAKE_TYPED_DICTIONARY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_DICTIONARY_INFO(NodePath, Variant::NODE_PATH)
MAKE_TYPED_DICTIONARY_INFO(RID, Variant::RID)
MAKE_TYPED_DICTIONARY_INFO(Callable, Variant::CALLABLE)
MAKE_TYPED_DICTIONARY_INFO(Signal, Variant::SIGNAL)
MAKE_TYPED_DICTIONARY_INFO(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_DICTIONARY_INFO(Array, Variant::ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
/*
MAKE_TYPED_DICTIONARY_INFO(IPAddress, Variant::STRING)
*/
#undef MAKE_TYPED_DICTIONARY_INFO
#undef MAKE_TYPED_DICTIONARY_INFO_NIL
#undef MAKE_TYPED_DICTIONARY_INFO_EXPANDED
#undef MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT
} // namespace godot

View File

@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_VARIANT_HPP
#define GODOT_VARIANT_HPP
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/variant/array.hpp>
#include <godot_cpp/variant/builtin_types.hpp>
#include <godot_cpp/variant/variant_size.hpp>
@@ -49,7 +49,6 @@ class Variant {
friend class GDExtensionBinding;
friend class MethodBind;
friend class VariantInternal;
static void init_bindings();
@@ -101,7 +100,6 @@ public:
PACKED_VECTOR2_ARRAY,
PACKED_VECTOR3_ARRAY,
PACKED_COLOR_ARRAY,
PACKED_VECTOR4_ARRAY,
VARIANT_MAX
};
@@ -145,7 +143,7 @@ private:
static GDExtensionTypeFromVariantConstructorFunc to_type_constructor[VARIANT_MAX];
public:
_FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast<uint8_t (*)[GODOT_CPP_VARIANT_SIZE]>(&opaque); }
_FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast<uint8_t(*)[GODOT_CPP_VARIANT_SIZE]>(&opaque); }
Variant();
Variant(std::nullptr_t n) :
Variant() {}
@@ -214,7 +212,6 @@ public:
Variant(const PackedVector2Array &v);
Variant(const PackedVector3Array &v);
Variant(const PackedColorArray &v);
Variant(const PackedVector4Array &v);
~Variant();
operator bool() const;
@@ -263,9 +260,6 @@ public:
operator PackedVector2Array() const;
operator PackedVector3Array() const;
operator PackedColorArray() const;
operator PackedVector4Array() const;
Object *get_validated_object() const;
Variant &operator=(const Variant &other);
Variant &operator=(Variant &&other);
@@ -330,6 +324,8 @@ public:
bool booleanize() const;
String stringify() const;
Variant duplicate(bool deep = false) const;
static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
static String get_type_name(Variant::Type type);
static bool can_convert(Variant::Type from, Variant::Type to);
@@ -358,72 +354,6 @@ String vformat(const String &p_text, const VarArgs... p_args) {
return p_text % args_array;
}
Variant &Array::Iterator::operator*() const {
return *elem_ptr;
}
Variant *Array::Iterator::operator->() const {
return elem_ptr;
}
Array::Iterator &Array::Iterator::operator++() {
elem_ptr++;
return *this;
}
Array::Iterator &Array::Iterator::operator--() {
elem_ptr--;
return *this;
}
const Variant &Array::ConstIterator::operator*() const {
return *elem_ptr;
}
const Variant *Array::ConstIterator::operator->() const {
return elem_ptr;
}
Array::ConstIterator &Array::ConstIterator::operator++() {
elem_ptr++;
return *this;
}
Array::ConstIterator &Array::ConstIterator::operator--() {
elem_ptr--;
return *this;
}
Array::Iterator Array::begin() {
return Array::Iterator(ptrw());
}
Array::Iterator Array::end() {
return Array::Iterator(ptrw() + size());
}
Array::ConstIterator Array::begin() const {
return Array::ConstIterator(ptr());
}
Array::ConstIterator Array::end() const {
return Array::ConstIterator(ptr() + size());
}
Array::Array(std::initializer_list<Variant> p_init) :
Array() {
ERR_FAIL_COND(resize(p_init.size()) != 0);
size_t i = 0;
for (const Variant &element : p_init) {
set(i++, element);
}
}
#include <godot_cpp/variant/builtin_vararg_methods.hpp>
#ifdef REAL_T_IS_DOUBLE
using PackedRealArray = PackedFloat64Array;
#else
using PackedRealArray = PackedFloat32Array;
#endif // REAL_T_IS_DOUBLE
} // namespace godot
#endif // GODOT_VARIANT_HPP

View File

@@ -1,506 +0,0 @@
/**************************************************************************/
/* variant_internal.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include <gdextension_interface.h>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
// For use when you want to access the internal pointer of a Variant directly.
// Use with caution. You need to be sure that the type is correct.
namespace internal {
template <typename T>
struct VariantInternalType {};
template <>
struct VariantInternalType<bool> {
static constexpr Variant::Type type = Variant::BOOL;
};
template <>
struct VariantInternalType<int64_t> {
static constexpr Variant::Type type = Variant::INT;
};
template <>
struct VariantInternalType<double> {
static constexpr Variant::Type type = Variant::FLOAT;
};
template <>
struct VariantInternalType<String> {
static constexpr Variant::Type type = Variant::STRING;
};
template <>
struct VariantInternalType<Vector2> {
static constexpr Variant::Type type = Variant::VECTOR2;
};
template <>
struct VariantInternalType<Vector2i> {
static constexpr Variant::Type type = Variant::VECTOR2I;
};
template <>
struct VariantInternalType<Rect2> {
static constexpr Variant::Type type = Variant::RECT2;
};
template <>
struct VariantInternalType<Rect2i> {
static constexpr Variant::Type type = Variant::RECT2I;
};
template <>
struct VariantInternalType<Vector3> {
static constexpr Variant::Type type = Variant::VECTOR3;
};
template <>
struct VariantInternalType<Vector3i> {
static constexpr Variant::Type type = Variant::VECTOR3I;
};
template <>
struct VariantInternalType<Transform2D> {
static constexpr Variant::Type type = Variant::TRANSFORM2D;
};
template <>
struct VariantInternalType<Vector4> {
static constexpr Variant::Type type = Variant::VECTOR4;
};
template <>
struct VariantInternalType<Vector4i> {
static constexpr Variant::Type type = Variant::VECTOR4I;
};
template <>
struct VariantInternalType<Plane> {
static constexpr Variant::Type type = Variant::PLANE;
};
template <>
struct VariantInternalType<Quaternion> {
static constexpr Variant::Type type = Variant::QUATERNION;
};
template <>
struct VariantInternalType<AABB> {
static constexpr Variant::Type type = Variant::AABB;
};
template <>
struct VariantInternalType<Basis> {
static constexpr Variant::Type type = Variant::BASIS;
};
template <>
struct VariantInternalType<Transform3D> {
static constexpr Variant::Type type = Variant::TRANSFORM3D;
};
template <>
struct VariantInternalType<Projection> {
static constexpr Variant::Type type = Variant::PROJECTION;
};
template <>
struct VariantInternalType<Color> {
static constexpr Variant::Type type = Variant::COLOR;
};
template <>
struct VariantInternalType<StringName> {
static constexpr Variant::Type type = Variant::STRING_NAME;
};
template <>
struct VariantInternalType<NodePath> {
static constexpr Variant::Type type = Variant::NODE_PATH;
};
template <>
struct VariantInternalType<RID> {
static constexpr Variant::Type type = Variant::RID;
};
template <>
struct VariantInternalType<Object *> {
static constexpr Variant::Type type = Variant::OBJECT;
};
template <>
struct VariantInternalType<Callable> {
static constexpr Variant::Type type = Variant::CALLABLE;
};
template <>
struct VariantInternalType<Signal> {
static constexpr Variant::Type type = Variant::SIGNAL;
};
template <>
struct VariantInternalType<Dictionary> {
static constexpr Variant::Type type = Variant::DICTIONARY;
};
template <>
struct VariantInternalType<Array> {
static constexpr Variant::Type type = Variant::ARRAY;
};
template <>
struct VariantInternalType<PackedByteArray> {
static constexpr Variant::Type type = Variant::PACKED_BYTE_ARRAY;
};
template <>
struct VariantInternalType<PackedInt32Array> {
static constexpr Variant::Type type = Variant::PACKED_INT32_ARRAY;
};
template <>
struct VariantInternalType<PackedInt64Array> {
static constexpr Variant::Type type = Variant::PACKED_INT64_ARRAY;
};
template <>
struct VariantInternalType<PackedFloat32Array> {
static constexpr Variant::Type type = Variant::PACKED_FLOAT32_ARRAY;
};
template <>
struct VariantInternalType<PackedFloat64Array> {
static constexpr Variant::Type type = Variant::PACKED_FLOAT64_ARRAY;
};
template <>
struct VariantInternalType<PackedStringArray> {
static constexpr Variant::Type type = Variant::PACKED_STRING_ARRAY;
};
template <>
struct VariantInternalType<PackedVector2Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR2_ARRAY;
};
template <>
struct VariantInternalType<PackedVector3Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR3_ARRAY;
};
template <>
struct VariantInternalType<PackedColorArray> {
static constexpr Variant::Type type = Variant::PACKED_COLOR_ARRAY;
};
template <>
struct VariantInternalType<PackedVector4Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR4_ARRAY;
};
} //namespace internal
class VariantInternal {
friend class Variant;
static GDExtensionVariantGetInternalPtrFunc get_internal_func[Variant::VARIANT_MAX];
static void init_bindings();
public:
template <typename T>
_FORCE_INLINE_ static T *get_internal_value(Variant *v) {
return static_cast<T *>(get_internal_func[internal::VariantInternalType<T>::type](v));
}
template <typename T>
_FORCE_INLINE_ static const T *get_internal_value(const Variant *v) {
return static_cast<const T *>(get_internal_func[internal::VariantInternalType<T>::type](const_cast<Variant *>(v)));
}
// Atomic types.
_FORCE_INLINE_ static bool *get_bool(Variant *v) { return get_internal_value<bool>(v); }
_FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return get_internal_value<bool>(v); }
_FORCE_INLINE_ static int64_t *get_int(Variant *v) { return get_internal_value<int64_t>(v); }
_FORCE_INLINE_ static const int64_t *get_int(const Variant *v) { return get_internal_value<int64_t>(v); }
_FORCE_INLINE_ static double *get_float(Variant *v) { return get_internal_value<double>(v); }
_FORCE_INLINE_ static const double *get_float(const Variant *v) { return get_internal_value<double>(v); }
_FORCE_INLINE_ static String *get_string(Variant *v) { return get_internal_value<String>(v); }
_FORCE_INLINE_ static const String *get_string(const Variant *v) { return get_internal_value<String>(v); }
// Math types.
_FORCE_INLINE_ static Vector2 *get_vector2(Variant *v) { return get_internal_value<Vector2>(v); }
_FORCE_INLINE_ static const Vector2 *get_vector2(const Variant *v) { return get_internal_value<Vector2>(v); }
_FORCE_INLINE_ static Vector2i *get_vector2i(Variant *v) { return get_internal_value<Vector2i>(v); }
_FORCE_INLINE_ static const Vector2i *get_vector2i(const Variant *v) { return get_internal_value<Vector2i>(v); }
_FORCE_INLINE_ static Rect2 *get_rect2(Variant *v) { return get_internal_value<Rect2>(v); }
_FORCE_INLINE_ static const Rect2 *get_rect2(const Variant *v) { return get_internal_value<Rect2>(v); }
_FORCE_INLINE_ static Rect2i *get_rect2i(Variant *v) { return get_internal_value<Rect2i>(v); }
_FORCE_INLINE_ static const Rect2i *get_rect2i(const Variant *v) { return get_internal_value<Rect2i>(v); }
_FORCE_INLINE_ static Vector3 *get_vector3(Variant *v) { return get_internal_value<Vector3>(v); }
_FORCE_INLINE_ static const Vector3 *get_vector3(const Variant *v) { return get_internal_value<Vector3>(v); }
_FORCE_INLINE_ static Vector3i *get_vector3i(Variant *v) { return get_internal_value<Vector3i>(v); }
_FORCE_INLINE_ static const Vector3i *get_vector3i(const Variant *v) { return get_internal_value<Vector3i>(v); }
_FORCE_INLINE_ static Vector4 *get_vector4(Variant *v) { return get_internal_value<Vector4>(v); }
_FORCE_INLINE_ static const Vector4 *get_vector4(const Variant *v) { return get_internal_value<Vector4>(v); }
_FORCE_INLINE_ static Vector4i *get_vector4i(Variant *v) { return get_internal_value<Vector4i>(v); }
_FORCE_INLINE_ static const Vector4i *get_vector4i(const Variant *v) { return get_internal_value<Vector4i>(v); }
_FORCE_INLINE_ static Transform2D *get_transform2d(Variant *v) { return get_internal_value<Transform2D>(v); }
_FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return get_internal_value<Transform2D>(v); }
_FORCE_INLINE_ static Plane *get_plane(Variant *v) { return get_internal_value<Plane>(v); }
_FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return get_internal_value<Plane>(v); }
_FORCE_INLINE_ static Quaternion *get_quaternion(Variant *v) { return get_internal_value<Quaternion>(v); }
_FORCE_INLINE_ static const Quaternion *get_quaternion(const Variant *v) { return get_internal_value<Quaternion>(v); }
_FORCE_INLINE_ static AABB *get_aabb(Variant *v) { return get_internal_value<AABB>(v); }
_FORCE_INLINE_ static const AABB *get_aabb(const Variant *v) { return get_internal_value<AABB>(v); }
_FORCE_INLINE_ static Basis *get_basis(Variant *v) { return get_internal_value<Basis>(v); }
_FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return get_internal_value<Basis>(v); }
_FORCE_INLINE_ static Transform3D *get_transform(Variant *v) { return get_internal_value<Transform3D>(v); }
_FORCE_INLINE_ static const Transform3D *get_transform(const Variant *v) { return get_internal_value<Transform3D>(v); }
_FORCE_INLINE_ static Projection *get_projection(Variant *v) { return get_internal_value<Projection>(v); }
_FORCE_INLINE_ static const Projection *get_projection(const Variant *v) { return get_internal_value<Projection>(v); }
// Misc types.
_FORCE_INLINE_ static Color *get_color(Variant *v) { return get_internal_value<Color>(v); }
_FORCE_INLINE_ static const Color *get_color(const Variant *v) { return get_internal_value<Color>(v); }
_FORCE_INLINE_ static StringName *get_string_name(Variant *v) { return get_internal_value<StringName>(v); }
_FORCE_INLINE_ static const StringName *get_string_name(const Variant *v) { return get_internal_value<StringName>(v); }
_FORCE_INLINE_ static NodePath *get_node_path(Variant *v) { return get_internal_value<NodePath>(v); }
_FORCE_INLINE_ static const NodePath *get_node_path(const Variant *v) { return get_internal_value<NodePath>(v); }
_FORCE_INLINE_ static RID *get_rid(Variant *v) { return get_internal_value<RID>(v); }
_FORCE_INLINE_ static const RID *get_rid(const Variant *v) { return get_internal_value<RID>(v); }
_FORCE_INLINE_ static Callable *get_callable(Variant *v) { return get_internal_value<Callable>(v); }
_FORCE_INLINE_ static const Callable *get_callable(const Variant *v) { return get_internal_value<Callable>(v); }
_FORCE_INLINE_ static Signal *get_signal(Variant *v) { return get_internal_value<Signal>(v); }
_FORCE_INLINE_ static const Signal *get_signal(const Variant *v) { return get_internal_value<Signal>(v); }
_FORCE_INLINE_ static Dictionary *get_dictionary(Variant *v) { return get_internal_value<Dictionary>(v); }
_FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return get_internal_value<Dictionary>(v); }
_FORCE_INLINE_ static Array *get_array(Variant *v) { return get_internal_value<Array>(v); }
_FORCE_INLINE_ static const Array *get_array(const Variant *v) { return get_internal_value<Array>(v); }
// Typed arrays.
_FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return get_internal_value<PackedByteArray>(v); }
_FORCE_INLINE_ static const PackedByteArray *get_byte_array(const Variant *v) { return get_internal_value<PackedByteArray>(v); }
_FORCE_INLINE_ static PackedInt32Array *get_int32_array(Variant *v) { return get_internal_value<PackedInt32Array>(v); }
_FORCE_INLINE_ static const PackedInt32Array *get_int32_array(const Variant *v) { return get_internal_value<PackedInt32Array>(v); }
_FORCE_INLINE_ static PackedInt64Array *get_int64_array(Variant *v) { return get_internal_value<PackedInt64Array>(v); }
_FORCE_INLINE_ static const PackedInt64Array *get_int64_array(const Variant *v) { return get_internal_value<PackedInt64Array>(v); }
_FORCE_INLINE_ static PackedFloat32Array *get_float32_array(Variant *v) { return get_internal_value<PackedFloat32Array>(v); }
_FORCE_INLINE_ static const PackedFloat32Array *get_float32_array(const Variant *v) { return get_internal_value<PackedFloat32Array>(v); }
_FORCE_INLINE_ static PackedFloat64Array *get_float64_array(Variant *v) { return get_internal_value<PackedFloat64Array>(v); }
_FORCE_INLINE_ static const PackedFloat64Array *get_float64_array(const Variant *v) { return get_internal_value<PackedFloat64Array>(v); }
_FORCE_INLINE_ static PackedStringArray *get_string_array(Variant *v) { return get_internal_value<PackedStringArray>(v); }
_FORCE_INLINE_ static const PackedStringArray *get_string_array(const Variant *v) { return get_internal_value<PackedStringArray>(v); }
_FORCE_INLINE_ static PackedVector2Array *get_vector2_array(Variant *v) { return get_internal_value<PackedVector2Array>(v); }
_FORCE_INLINE_ static const PackedVector2Array *get_vector2_array(const Variant *v) { return get_internal_value<PackedVector2Array>(v); }
_FORCE_INLINE_ static PackedVector3Array *get_vector3_array(Variant *v) { return get_internal_value<PackedVector3Array>(v); }
_FORCE_INLINE_ static const PackedVector3Array *get_vector3_array(const Variant *v) { return get_internal_value<PackedVector3Array>(v); }
_FORCE_INLINE_ static PackedColorArray *get_color_array(Variant *v) { return get_internal_value<PackedColorArray>(v); }
_FORCE_INLINE_ static const PackedColorArray *get_color_array(const Variant *v) { return get_internal_value<PackedColorArray>(v); }
_FORCE_INLINE_ static PackedVector4Array *get_vector4_array(Variant *v) { return get_internal_value<PackedVector4Array>(v); }
_FORCE_INLINE_ static const PackedVector4Array *get_vector4_array(const Variant *v) { return get_internal_value<PackedVector4Array>(v); }
_FORCE_INLINE_ static Object **get_object(Variant *v) { return get_internal_value<Object *>(v); }
_FORCE_INLINE_ static const Object **get_object(const Variant *v) { return (const Object **)get_internal_value<Object *>(v); }
_FORCE_INLINE_ static void *get_opaque_pointer(Variant *v) {
switch (v->get_type()) {
case Variant::NIL:
return nullptr;
case Variant::BOOL:
return get_bool(v);
case Variant::INT:
return get_int(v);
case Variant::FLOAT:
return get_float(v);
case Variant::STRING:
return get_string(v);
case Variant::VECTOR2:
return get_vector2(v);
case Variant::VECTOR2I:
return get_vector2i(v);
case Variant::VECTOR3:
return get_vector3(v);
case Variant::VECTOR3I:
return get_vector3i(v);
case Variant::VECTOR4:
return get_vector4(v);
case Variant::VECTOR4I:
return get_vector4i(v);
case Variant::RECT2:
return get_rect2(v);
case Variant::RECT2I:
return get_rect2i(v);
case Variant::TRANSFORM3D:
return get_transform(v);
case Variant::PROJECTION:
return get_projection(v);
case Variant::TRANSFORM2D:
return get_transform2d(v);
case Variant::QUATERNION:
return get_quaternion(v);
case Variant::PLANE:
return get_plane(v);
case Variant::BASIS:
return get_basis(v);
case Variant::AABB:
return get_aabb(v);
case Variant::COLOR:
return get_color(v);
case Variant::STRING_NAME:
return get_string_name(v);
case Variant::NODE_PATH:
return get_node_path(v);
case Variant::RID:
return get_rid(v);
case Variant::CALLABLE:
return get_callable(v);
case Variant::SIGNAL:
return get_signal(v);
case Variant::DICTIONARY:
return get_dictionary(v);
case Variant::ARRAY:
return get_array(v);
case Variant::PACKED_BYTE_ARRAY:
return get_byte_array(v);
case Variant::PACKED_INT32_ARRAY:
return get_int32_array(v);
case Variant::PACKED_INT64_ARRAY:
return get_int64_array(v);
case Variant::PACKED_FLOAT32_ARRAY:
return get_float32_array(v);
case Variant::PACKED_FLOAT64_ARRAY:
return get_float64_array(v);
case Variant::PACKED_STRING_ARRAY:
return get_string_array(v);
case Variant::PACKED_VECTOR2_ARRAY:
return get_vector2_array(v);
case Variant::PACKED_VECTOR3_ARRAY:
return get_vector3_array(v);
case Variant::PACKED_COLOR_ARRAY:
return get_color_array(v);
case Variant::PACKED_VECTOR4_ARRAY:
return get_vector4_array(v);
case Variant::OBJECT:
return get_object(v);
case Variant::VARIANT_MAX:
ERR_FAIL_V(nullptr);
}
ERR_FAIL_V(nullptr);
}
_FORCE_INLINE_ static const void *get_opaque_pointer(const Variant *v) {
switch (v->get_type()) {
case Variant::NIL:
return nullptr;
case Variant::BOOL:
return get_bool(v);
case Variant::INT:
return get_int(v);
case Variant::FLOAT:
return get_float(v);
case Variant::STRING:
return get_string(v);
case Variant::VECTOR2:
return get_vector2(v);
case Variant::VECTOR2I:
return get_vector2i(v);
case Variant::VECTOR3:
return get_vector3(v);
case Variant::VECTOR3I:
return get_vector3i(v);
case Variant::VECTOR4:
return get_vector4(v);
case Variant::VECTOR4I:
return get_vector4i(v);
case Variant::RECT2:
return get_rect2(v);
case Variant::RECT2I:
return get_rect2i(v);
case Variant::TRANSFORM3D:
return get_transform(v);
case Variant::PROJECTION:
return get_projection(v);
case Variant::TRANSFORM2D:
return get_transform2d(v);
case Variant::QUATERNION:
return get_quaternion(v);
case Variant::PLANE:
return get_plane(v);
case Variant::BASIS:
return get_basis(v);
case Variant::AABB:
return get_aabb(v);
case Variant::COLOR:
return get_color(v);
case Variant::STRING_NAME:
return get_string_name(v);
case Variant::NODE_PATH:
return get_node_path(v);
case Variant::RID:
return get_rid(v);
case Variant::CALLABLE:
return get_callable(v);
case Variant::SIGNAL:
return get_signal(v);
case Variant::DICTIONARY:
return get_dictionary(v);
case Variant::ARRAY:
return get_array(v);
case Variant::PACKED_BYTE_ARRAY:
return get_byte_array(v);
case Variant::PACKED_INT32_ARRAY:
return get_int32_array(v);
case Variant::PACKED_INT64_ARRAY:
return get_int64_array(v);
case Variant::PACKED_FLOAT32_ARRAY:
return get_float32_array(v);
case Variant::PACKED_FLOAT64_ARRAY:
return get_float64_array(v);
case Variant::PACKED_STRING_ARRAY:
return get_string_array(v);
case Variant::PACKED_VECTOR2_ARRAY:
return get_vector2_array(v);
case Variant::PACKED_VECTOR3_ARRAY:
return get_vector3_array(v);
case Variant::PACKED_COLOR_ARRAY:
return get_color_array(v);
case Variant::PACKED_VECTOR4_ARRAY:
return get_vector4_array(v);
case Variant::OBJECT:
return get_object(v);
case Variant::VARIANT_MAX:
ERR_FAIL_V(nullptr);
}
ERR_FAIL_V(nullptr);
}
};
template <typename T>
struct VariantGetInternalPtr {
static internal::VariantInternalType<T> *get_ptr(Variant *v) { return VariantInternal::get_internal_value<T>(v); }
static const internal::VariantInternalType<T> *get_ptr(const Variant *v) { return VariantInternal::get_internal_value<T>(v); }
};
template <typename T>
struct can_set_variant_internal_value {
static const bool value = true;
};
template <>
struct can_set_variant_internal_value<Object *> {
static const bool value = false;
};
template <typename T>
struct VariantInternalAccessor {
static _FORCE_INLINE_ const T &get(const Variant *v) { return *VariantInternal::get_internal_value<T>(v); }
// Enable set() only for those types where we can set (all but Object *).
template <typename U = T, typename = std::enable_if_t<can_set_variant_internal_value<U>::value>>
static _FORCE_INLINE_ void set(Variant *v, const internal::VariantInternalType<U> &p_value) {
*VariantInternal::get_internal_value<U>(v) = p_value;
}
};
template <typename T, std::enable_if_t<can_set_variant_internal_value<T>::value>>
struct VariantDefaultInitializer {
static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_internal_value<T>(v) = T(); }
};
} // namespace godot

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_VECTOR2_HPP
#define GODOT_VECTOR2_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/math.hpp>
@@ -38,7 +39,7 @@ namespace godot {
class String;
struct Vector2i;
struct [[nodiscard]] Vector2 {
struct _NO_DISCARD_ Vector2 {
static const int AXIS_COUNT = 2;
enum Axis {
@@ -61,13 +62,13 @@ struct [[nodiscard]] Vector2 {
real_t coord[2] = { 0 };
};
_FORCE_INLINE_ real_t &operator[](int p_axis) {
DEV_ASSERT((unsigned int)p_axis < 2);
return coord[p_axis];
_FORCE_INLINE_ real_t &operator[](int p_idx) {
DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
_FORCE_INLINE_ const real_t &operator[](int p_axis) const {
DEV_ASSERT((unsigned int)p_axis < 2);
return coord[p_axis];
_FORCE_INLINE_ const real_t &operator[](int p_idx) const {
DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
_FORCE_INLINE_ Vector2::Axis min_axis_index() const {
@@ -84,24 +85,16 @@ struct [[nodiscard]] Vector2 {
real_t length() const;
real_t length_squared() const;
Vector2 limit_length(real_t p_len = 1.0) const;
Vector2 limit_length(const real_t p_len = 1.0) const;
Vector2 min(const Vector2 &p_vector2) const {
return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y));
}
Vector2 minf(real_t p_scalar) const {
return Vector2(MIN(x, p_scalar), MIN(y, p_scalar));
}
Vector2 max(const Vector2 &p_vector2) const {
return Vector2(MAX(x, p_vector2.x), MAX(y, p_vector2.y));
}
Vector2 maxf(real_t p_scalar) const {
return Vector2(MAX(x, p_scalar), MAX(y, p_scalar));
}
real_t distance_to(const Vector2 &p_vector2) const;
real_t distance_squared_to(const Vector2 &p_vector2) const;
real_t angle_to(const Vector2 &p_vector2) const;
@@ -110,20 +103,19 @@ struct [[nodiscard]] Vector2 {
real_t dot(const Vector2 &p_other) const;
real_t cross(const Vector2 &p_other) const;
Vector2 posmod(real_t p_mod) const;
Vector2 posmod(const real_t p_mod) const;
Vector2 posmodv(const Vector2 &p_modv) const;
Vector2 project(const Vector2 &p_to) const;
Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const;
Vector2 plane_project(const real_t p_d, const Vector2 &p_vec) const;
_FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, real_t p_weight) const;
_FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, real_t p_weight) const;
_FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const;
_FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const;
_FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const;
_FORCE_INLINE_ Vector2 bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const;
_FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const;
_FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
Vector2 move_toward(const Vector2 &p_to, real_t p_delta) const;
Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const;
Vector2 slide(const Vector2 &p_normal) const;
Vector2 bounce(const Vector2 &p_normal) const;
@@ -131,7 +123,6 @@ struct [[nodiscard]] Vector2 {
bool is_equal_approx(const Vector2 &p_v) const;
bool is_zero_approx() const;
bool is_finite() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);
@@ -139,16 +130,16 @@ struct [[nodiscard]] Vector2 {
void operator-=(const Vector2 &p_v);
Vector2 operator*(const Vector2 &p_v1) const;
Vector2 operator*(real_t p_rvalue) const;
void operator*=(real_t p_rvalue);
void operator*=(const Vector2 &p_rvalue) { *this = *this * p_rvalue; }
Vector2 operator*(const real_t &rvalue) const;
void operator*=(const real_t &rvalue);
void operator*=(const Vector2 &rvalue) { *this = *this * rvalue; }
Vector2 operator/(const Vector2 &p_v1) const;
Vector2 operator/(real_t p_rvalue) const;
Vector2 operator/(const real_t &rvalue) const;
void operator/=(real_t p_rvalue);
void operator/=(const Vector2 &p_rvalue) { *this = *this / p_rvalue; }
void operator/=(const real_t &rvalue);
void operator/=(const Vector2 &rvalue) { *this = *this / rvalue; }
Vector2 operator-() const;
@@ -161,13 +152,13 @@ struct [[nodiscard]] Vector2 {
bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); }
real_t angle() const;
static Vector2 from_angle(real_t p_angle);
static Vector2 from_angle(const real_t p_angle);
_FORCE_INLINE_ Vector2 abs() const {
return Vector2(Math::abs(x), Math::abs(y));
}
Vector2 rotated(real_t p_by) const;
Vector2 rotated(const real_t p_by) const;
Vector2 orthogonal() const {
return Vector2(y, -x);
}
@@ -177,22 +168,20 @@ struct [[nodiscard]] Vector2 {
Vector2 ceil() const;
Vector2 round() const;
Vector2 snapped(const Vector2 &p_by) const;
Vector2 snappedf(real_t p_by) const;
Vector2 clamp(const Vector2 &p_min, const Vector2 &p_max) const;
Vector2 clampf(real_t p_min, real_t p_max) const;
real_t aspect() const { return width / height; }
operator String() const;
operator Vector2i() const;
_FORCE_INLINE_ Vector2() {}
_FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) {
_FORCE_INLINE_ Vector2(const real_t p_x, const real_t p_y) {
x = p_x;
y = p_y;
}
};
_FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const {
_FORCE_INLINE_ Vector2 Vector2::plane_project(const real_t p_d, const Vector2 &p_vec) const {
return p_vec - *this * (dot(p_vec) - p_d);
}
@@ -218,26 +207,26 @@ _FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const {
return Vector2(x * p_v1.x, y * p_v1.y);
}
_FORCE_INLINE_ Vector2 Vector2::operator*(real_t p_rvalue) const {
return Vector2(x * p_rvalue, y * p_rvalue);
_FORCE_INLINE_ Vector2 Vector2::operator*(const real_t &rvalue) const {
return Vector2(x * rvalue, y * rvalue);
}
_FORCE_INLINE_ void Vector2::operator*=(real_t p_rvalue) {
x *= p_rvalue;
y *= p_rvalue;
_FORCE_INLINE_ void Vector2::operator*=(const real_t &rvalue) {
x *= rvalue;
y *= rvalue;
}
_FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const {
return Vector2(x / p_v1.x, y / p_v1.y);
}
_FORCE_INLINE_ Vector2 Vector2::operator/(real_t p_rvalue) const {
return Vector2(x / p_rvalue, y / p_rvalue);
_FORCE_INLINE_ Vector2 Vector2::operator/(const real_t &rvalue) const {
return Vector2(x / rvalue, y / rvalue);
}
_FORCE_INLINE_ void Vector2::operator/=(real_t p_rvalue) {
x /= p_rvalue;
y /= p_rvalue;
_FORCE_INLINE_ void Vector2::operator/=(const real_t &rvalue) {
x /= rvalue;
y /= rvalue;
}
_FORCE_INLINE_ Vector2 Vector2::operator-() const {
@@ -252,14 +241,16 @@ _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
return x != p_vec2.x || y != p_vec2.y;
}
Vector2 Vector2::lerp(const Vector2 &p_to, real_t p_weight) const {
Vector2 Vector2::lerp(const Vector2 &p_to, const real_t p_weight) const {
Vector2 res = *this;
res.x = Math::lerp(res.x, p_to.x, p_weight);
res.y = Math::lerp(res.y, p_to.y, p_weight);
res.x += (p_weight * (p_to.x - x));
res.y += (p_weight * (p_to.y - y));
return res;
}
Vector2 Vector2::slerp(const Vector2 &p_to, real_t p_weight) const {
Vector2 Vector2::slerp(const Vector2 &p_to, const real_t p_weight) const {
real_t start_length_sq = length_squared();
real_t end_length_sq = p_to.length_squared();
if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) {
@@ -272,32 +263,31 @@ Vector2 Vector2::slerp(const Vector2 &p_to, real_t p_weight) const {
return rotated(angle * p_weight) * (result_length / start_length);
}
Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const {
Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const {
Vector2 res = *this;
res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
return res;
}
Vector2 Vector2::cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const {
Vector2 Vector2::cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
Vector2 res = *this;
res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
return res;
}
Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const {
Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const {
Vector2 res = *this;
res.x = Math::bezier_interpolate(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t);
res.y = Math::bezier_interpolate(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t);
return res;
}
Vector2 Vector2::bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const {
Vector2 res = *this;
res.x = Math::bezier_derivative(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t);
res.y = Math::bezier_derivative(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t);
return res;
/* Formula from Wikipedia article on Bezier curves. */
real_t omt = (1.0 - p_t);
real_t omt2 = omt * omt;
real_t omt3 = omt2 * omt;
real_t t2 = p_t * p_t;
real_t t3 = t2 * p_t;
return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
}
Vector2 Vector2::direction_to(const Vector2 &p_to) const {
@@ -309,19 +299,19 @@ Vector2 Vector2::direction_to(const Vector2 &p_to) const {
// Multiplication operators required to workaround issues with LLVM using implicit conversion
// to Vector2i instead for integers where it should not.
_FORCE_INLINE_ Vector2 operator*(float p_scalar, const Vector2 &p_vec) {
_FORCE_INLINE_ Vector2 operator*(const float p_scalar, const Vector2 &p_vec) {
return p_vec * p_scalar;
}
_FORCE_INLINE_ Vector2 operator*(double p_scalar, const Vector2 &p_vec) {
_FORCE_INLINE_ Vector2 operator*(const double p_scalar, const Vector2 &p_vec) {
return p_vec * p_scalar;
}
_FORCE_INLINE_ Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) {
_FORCE_INLINE_ Vector2 operator*(const int32_t p_scalar, const Vector2 &p_vec) {
return p_vec * p_scalar;
}
_FORCE_INLINE_ Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) {
_FORCE_INLINE_ Vector2 operator*(const int64_t p_scalar, const Vector2 &p_vec) {
return p_vec * p_scalar;
}
@@ -329,3 +319,5 @@ typedef Vector2 Size2;
typedef Vector2 Point2;
} // namespace godot
#endif // GODOT_VECTOR2_HPP

View File

@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#ifndef GODOT_VECTOR2I_HPP
#define GODOT_VECTOR2I_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/math.hpp>
@@ -38,7 +39,7 @@ namespace godot {
class String;
struct Vector2;
struct [[nodiscard]] Vector2i {
struct _NO_DISCARD_ Vector2i {
static const int AXIS_COUNT = 2;
enum Axis {
@@ -61,13 +62,13 @@ struct [[nodiscard]] Vector2i {
int32_t coord[2] = { 0 };
};
_FORCE_INLINE_ int32_t &operator[](int p_axis) {
DEV_ASSERT((unsigned int)p_axis < 2);
return coord[p_axis];
_FORCE_INLINE_ int32_t &operator[](int p_idx) {
DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
_FORCE_INLINE_ const int32_t &operator[](int p_axis) const {
DEV_ASSERT((unsigned int)p_axis < 2);
return coord[p_axis];
_FORCE_INLINE_ const int32_t &operator[](int p_idx) const {
DEV_ASSERT((unsigned int)p_idx < 2);
return coord[p_idx];
}
_FORCE_INLINE_ Vector2i::Axis min_axis_index() const {
@@ -82,42 +83,26 @@ struct [[nodiscard]] Vector2i {
return Vector2i(MIN(x, p_vector2i.x), MIN(y, p_vector2i.y));
}
Vector2i mini(int32_t p_scalar) const {
return Vector2i(MIN(x, p_scalar), MIN(y, p_scalar));
}
Vector2i max(const Vector2i &p_vector2i) const {
return Vector2i(MAX(x, p_vector2i.x), MAX(y, p_vector2i.y));
}
Vector2i maxi(int32_t p_scalar) const {
return Vector2i(MAX(x, p_scalar), MAX(y, p_scalar));
}
double distance_to(const Vector2i &p_to) const {
return (p_to - *this).length();
}
int64_t distance_squared_to(const Vector2i &p_to) const {
return (p_to - *this).length_squared();
}
Vector2i operator+(const Vector2i &p_v) const;
void operator+=(const Vector2i &p_v);
Vector2i operator-(const Vector2i &p_v) const;
void operator-=(const Vector2i &p_v);
Vector2i operator*(const Vector2i &p_v1) const;
Vector2i operator*(int32_t p_rvalue) const;
void operator*=(int32_t p_rvalue);
Vector2i operator*(const int32_t &rvalue) const;
void operator*=(const int32_t &rvalue);
Vector2i operator/(const Vector2i &p_v1) const;
Vector2i operator/(int32_t p_rvalue) const;
void operator/=(int32_t p_rvalue);
Vector2i operator/(const int32_t &rvalue) const;
void operator/=(const int32_t &rvalue);
Vector2i operator%(const Vector2i &p_v1) const;
Vector2i operator%(int32_t p_rvalue) const;
void operator%=(int32_t p_rvalue);
Vector2i operator%(const int32_t &rvalue) const;
void operator%=(const int32_t &rvalue);
Vector2i operator-() const;
bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
@@ -136,15 +121,12 @@ struct [[nodiscard]] Vector2i {
Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); }
Vector2i abs() const { return Vector2i(Math::abs(x), Math::abs(y)); }
Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const;
Vector2i clampi(int32_t p_min, int32_t p_max) const;
Vector2i snapped(const Vector2i &p_step) const;
Vector2i snappedi(int32_t p_step) const;
operator String() const;
operator Vector2() const;
inline Vector2i() {}
inline Vector2i(int32_t p_x, int32_t p_y) {
inline Vector2i(const int32_t p_x, const int32_t p_y) {
x = p_x;
y = p_y;
}
@@ -152,19 +134,19 @@ struct [[nodiscard]] Vector2i {
// Multiplication operators required to workaround issues with LLVM using implicit conversion.
_FORCE_INLINE_ Vector2i operator*(int32_t p_scalar, const Vector2i &p_vector) {
_FORCE_INLINE_ Vector2i operator*(const int32_t p_scalar, const Vector2i &p_vector) {
return p_vector * p_scalar;
}
_FORCE_INLINE_ Vector2i operator*(int64_t p_scalar, const Vector2i &p_vector) {
_FORCE_INLINE_ Vector2i operator*(const int64_t p_scalar, const Vector2i &p_vector) {
return p_vector * p_scalar;
}
_FORCE_INLINE_ Vector2i operator*(float p_scalar, const Vector2i &p_vector) {
_FORCE_INLINE_ Vector2i operator*(const float p_scalar, const Vector2i &p_vector) {
return p_vector * p_scalar;
}
_FORCE_INLINE_ Vector2i operator*(double p_scalar, const Vector2i &p_vector) {
_FORCE_INLINE_ Vector2i operator*(const double p_scalar, const Vector2i &p_vector) {
return p_vector * p_scalar;
}
@@ -172,3 +154,5 @@ typedef Vector2i Size2i;
typedef Vector2i Point2i;
} // namespace godot
#endif // GODOT_VECTOR2I_HPP

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