mirror of
https://github.com/godotengine/godot-cpp.git
synced 2026-01-01 05:48:37 +03:00
Compare commits
6 Commits
godot-4.1.
...
3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
290d629f14 | ||
|
|
2fb605531a | ||
|
|
e4ad265339 | ||
|
|
9bebf4feb7 | ||
|
|
7e8c24f0ac | ||
|
|
468dab8f01 |
115
.clang-format
115
.clang-format
@@ -1,40 +1,31 @@
|
||||
# Commented out parameters are those with the same value as base LLVM style.
|
||||
# Commented out parameters are those with the same value as base LLVM style
|
||||
# We can uncomment them if we want to change their value, or enforce the
|
||||
# chosen value in case the base style changes (last sync: Clang 14.0).
|
||||
# chosen value in case the base style changes (last sync: Clang 6.0.1).
|
||||
---
|
||||
### General config, applies to all languages ###
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
# AlignArrayOfStructures: None
|
||||
# AlignConsecutiveMacros: None
|
||||
# AlignConsecutiveAssignments: None
|
||||
# AlignConsecutiveBitFields: None
|
||||
# AlignConsecutiveDeclarations: None
|
||||
# AlignConsecutiveAssignments: false
|
||||
# AlignConsecutiveDeclarations: false
|
||||
# AlignEscapedNewlines: Right
|
||||
AlignOperands: DontAlign
|
||||
# AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
# AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
# AllowShortEnumsOnASingleLine: true
|
||||
# AllowShortBlocksOnASingleLine: Never
|
||||
# AllowShortCaseLabelsOnASingleLine: false
|
||||
# AllowShortFunctionsOnASingleLine: All
|
||||
# AllowShortLambdasOnASingleLine: All
|
||||
# AllowShortIfStatementsOnASingleLine: Never
|
||||
# AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
# AllowShortLoopsOnASingleLine: false
|
||||
# AlwaysBreakAfterDefinitionReturnType: None
|
||||
# AlwaysBreakAfterReturnType: None
|
||||
# AlwaysBreakBeforeMultilineStrings: false
|
||||
# AlwaysBreakTemplateDeclarations: MultiLine
|
||||
# AttributeMacros:
|
||||
# - __capability
|
||||
# AlwaysBreakTemplateDeclarations: false
|
||||
# BinPackArguments: true
|
||||
# BinPackParameters: true
|
||||
# BraceWrapping:
|
||||
# AfterCaseLabel: false
|
||||
# AfterClass: false
|
||||
# AfterControlStatement: Never
|
||||
# AfterControlStatement: false
|
||||
# AfterEnum: false
|
||||
# AfterFunction: false
|
||||
# AfterNamespace: false
|
||||
@@ -44,44 +35,32 @@ AllowAllParametersOfDeclarationOnNextLine: false
|
||||
# AfterExternBlock: false
|
||||
# BeforeCatch: false
|
||||
# BeforeElse: false
|
||||
# BeforeLambdaBody: false
|
||||
# BeforeWhile: false
|
||||
# IndentBraces: false
|
||||
# SplitEmptyFunction: true
|
||||
# SplitEmptyRecord: true
|
||||
# SplitEmptyNamespace: true
|
||||
# BreakBeforeBinaryOperators: None
|
||||
# BreakBeforeConceptDeclarations: true
|
||||
# BreakBeforeBraces: Attach
|
||||
# BreakBeforeInheritanceComma: false
|
||||
# BreakInheritanceList: BeforeColon
|
||||
# BreakBeforeTernaryOperators: true
|
||||
BreakBeforeTernaryOperators: false
|
||||
# BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
# BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
# CommentPragmas: '^ IWYU pragma:'
|
||||
# QualifierAlignment: Leave
|
||||
# CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: false
|
||||
# DeriveLineEnding: true
|
||||
# DerivePointerAlignment: false
|
||||
# DisableFormat: false
|
||||
# EmptyLineAfterAccessModifier: Never
|
||||
# EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
# ExperimentalAutoDetectBinPacking: false
|
||||
# PackConstructorInitializers: BinPack
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
# AllowAllConstructorInitializersOnNextLine: true
|
||||
# FixNamespaceComments: true
|
||||
# ForEachMacros:
|
||||
# - foreach
|
||||
# - Q_FOREACH
|
||||
# - BOOST_FOREACH
|
||||
# IfMacros:
|
||||
# - KJ_IF_MAYBE
|
||||
# IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '".*"'
|
||||
@@ -91,21 +70,13 @@ IncludeCategories:
|
||||
- Regex: '^<.*'
|
||||
Priority: 3
|
||||
# IncludeIsMainRegex: '(Test)?$'
|
||||
# IncludeIsMainSourceRegex: ''
|
||||
# IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
# IndentCaseBlocks: false
|
||||
# IndentGotoLabels: true
|
||||
# IndentPPDirectives: None
|
||||
# IndentExternBlock: AfterExternBlock
|
||||
# IndentRequires: false
|
||||
IndentWidth: 4
|
||||
# IndentWrappedFunctionNames: false
|
||||
# InsertTrailingCommas: None
|
||||
# JavaScriptQuotes: Leave
|
||||
# JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
# LambdaBodyIndentation: Signature
|
||||
# KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
# MacroBlockBegin: ''
|
||||
# MacroBlockEnd: ''
|
||||
# MaxEmptyLinesToKeep: 1
|
||||
@@ -114,86 +85,42 @@ KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
# PenaltyBreakBeforeFirstCallParameter: 19
|
||||
# PenaltyBreakComment: 300
|
||||
# PenaltyBreakFirstLessLess: 120
|
||||
# PenaltyBreakOpenParenthesis: 0
|
||||
# PenaltyBreakString: 1000
|
||||
# PenaltyBreakTemplateDeclaration: 10
|
||||
# PenaltyExcessCharacter: 1000000
|
||||
# PenaltyReturnTypeOnItsOwnLine: 60
|
||||
# PenaltyIndentedWhitespace: 0
|
||||
# PointerAlignment: Right
|
||||
# PPIndentWidth: -1
|
||||
# ReferenceAlignment: Pointer
|
||||
# RawStringFormats:
|
||||
# - Delimiter: pb
|
||||
# Language: TextProto
|
||||
# BasedOnStyle: google
|
||||
# ReflowComments: true
|
||||
# RemoveBracesLLVM: false
|
||||
# SeparateDefinitionBlocks: Leave
|
||||
# ShortNamespaceLines: 1
|
||||
# SortIncludes: CaseSensitive
|
||||
# SortJavaStaticImport: Before
|
||||
# SortIncludes: true
|
||||
# SortUsingDeclarations: true
|
||||
# SpaceAfterCStyleCast: false
|
||||
# SpaceAfterLogicalNot: false
|
||||
# SpaceAfterTemplateKeyword: true
|
||||
# SpaceBeforeAssignmentOperators: true
|
||||
# SpaceBeforeCaseColon: false
|
||||
# SpaceBeforeCpp11BracedList: false
|
||||
# SpaceBeforeCtorInitializerColon: true
|
||||
# SpaceBeforeInheritanceColon: true
|
||||
# SpaceBeforeParens: ControlStatements
|
||||
# SpaceBeforeParensOptions:
|
||||
# AfterControlStatements: true
|
||||
# AfterForeachMacros: true
|
||||
# AfterFunctionDefinitionName: false
|
||||
# AfterFunctionDeclarationName: false
|
||||
# AfterIfMacros: true
|
||||
# AfterOverloadedOperator: false
|
||||
# BeforeNonEmptyParentheses: false
|
||||
# SpaceAroundPointerQualifiers: Default
|
||||
# SpaceBeforeRangeBasedForLoopColon: true
|
||||
# SpaceInEmptyBlock: false
|
||||
# SpaceInEmptyParentheses: false
|
||||
# SpacesBeforeTrailingComments: 1
|
||||
# SpacesInAngles: Never
|
||||
# SpacesInConditionalStatement: false
|
||||
# SpacesInAngles: false
|
||||
# SpacesInContainerLiterals: true
|
||||
# SpacesInCStyleCastParentheses: false
|
||||
## Godot TODO: We'll want to use a min of 1, but we need to see how to fix
|
||||
## our comment capitalization at the same time.
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 0
|
||||
Maximum: -1
|
||||
# SpacesInParentheses: false
|
||||
# SpacesInSquareBrackets: false
|
||||
# SpaceBeforeSquareBrackets: false
|
||||
# BitFieldColonSpacing: Both
|
||||
# StatementAttributeLikeMacros:
|
||||
# - Q_EMIT
|
||||
# StatementMacros:
|
||||
# - Q_UNUSED
|
||||
# - QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
# UseCRLF: false
|
||||
UseTab: Always
|
||||
# WhitespaceSensitiveMacros:
|
||||
# - STRINGIZE
|
||||
# - PP_STRINGIZE
|
||||
# - BOOST_PP_STRINGIZE
|
||||
# - NS_SWIFT_NAME
|
||||
# - CF_SWIFT_NAME
|
||||
---
|
||||
### C++ specific config ###
|
||||
Language: Cpp
|
||||
Standard: c++17
|
||||
Standard: Cpp03
|
||||
---
|
||||
### 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']
|
||||
...
|
||||
|
||||
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
@@ -1,6 +0,0 @@
|
||||
# Lines starting with '#' are comments.
|
||||
# Each line is a file pattern followed by one or more owners.
|
||||
# Owners can be @users, @org/teams or emails
|
||||
|
||||
* @godotengine/gdextension
|
||||
.github/ @godotengine/buildsystem
|
||||
71
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
71
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,71 +0,0 @@
|
||||
name: Bug report
|
||||
description: Report a bug in the godot-cpp GDExtension/GDNative integration
|
||||
body:
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
- When reporting bugs, you'll make our life simpler (and the fix will come sooner) if you follow the guidelines in this template.
|
||||
- Write a descriptive issue title above.
|
||||
- The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them.
|
||||
- Search [open](https://github.com/godotengine/godot-cpp/issues) and [closed](https://github.com/godotengine/godot-cpp/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate.
|
||||
- Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/stable/about/release_policy.html).
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Godot version
|
||||
description: >
|
||||
Specify the Git commit hash if using a development or non-official build.
|
||||
If you use a custom build, please test if your issue is reproducible in official builds too.
|
||||
placeholder: 3.3.stable, 4.0.dev (3041becc6)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: godot-cpp version
|
||||
description: >
|
||||
Specify the Git commit hash if using a development build.
|
||||
placeholder: 3.3.stable, 4.0.dev (3041becc6)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: System information
|
||||
description: |
|
||||
- Specify the OS version, and when relevant hardware information.
|
||||
- For issues that are likely OS-specific and/or graphics-related, please specify the CPU model and architecture.
|
||||
- **Bug reports not including the required information may be closed at the maintainers' discretion.** If in doubt, always include all the requested information; it's better to include too much information than not enough information.
|
||||
placeholder: Windows 10, Intel Core i5-7200U
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Issue description
|
||||
description: |
|
||||
Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
|
||||
You can include images or videos with drag and drop, and format code blocks or logs with <code>```</code> tags.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them.
|
||||
If you include a minimal reproduction project below, you can detail how to use it here.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Minimal reproduction project
|
||||
description: |
|
||||
- A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`).
|
||||
- Required, unless the reproduction steps are trivial and don't require any project files to be followed. In this case, write "N/A" in the field.
|
||||
- Drag and drop a ZIP archive to upload it. **Do not select another field until the project is done uploading.**
|
||||
- **If you've been asked by a maintainer to upload a minimal reproduction project, you *must* do so within 7 days.** Otherwise, your bug report will be closed as it'll be considered too difficult to diagnose.
|
||||
validations:
|
||||
required: true
|
||||
14
.github/ISSUE_TEMPLATE/config.yml
vendored
14
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,14 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
- name: Godot proposals
|
||||
url: https://github.com/godotengine/godot-proposals
|
||||
about: Please submit feature proposals on the Godot proposals repository, not here.
|
||||
|
||||
- name: Godot documentation repository
|
||||
url: https://github.com/godotengine/godot-docs
|
||||
about: Please report issues with documentation on the Godot documentation repository, not here.
|
||||
|
||||
- name: Godot community channels
|
||||
url: https://godotengine.org/community
|
||||
about: Please ask for technical support on one of the other community channels, not here.
|
||||
22
.github/actions/godot-cache/action.yml
vendored
22
.github/actions/godot-cache/action.yml
vendored
@@ -1,22 +0,0 @@
|
||||
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}}
|
||||
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@@ -1,6 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
250
.github/workflows/ci.yml
vendored
250
.github/workflows/ci.yml
vendored
@@ -1,250 +0,0 @@
|
||||
name: Continuous integration
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
# Only used for the cache key. Increment version to force clean build.
|
||||
GODOT_BASE_BRANCH: master
|
||||
|
||||
concurrency:
|
||||
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: 🐧 Linux (GCC)
|
||||
os: ubuntu-20.04
|
||||
platform: linux
|
||||
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
|
||||
run-tests: true
|
||||
cache-name: linux-x86_64
|
||||
|
||||
- name: 🐧 Linux (GCC, Double Precision)
|
||||
os: ubuntu-20.04
|
||||
platform: linux
|
||||
artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release
|
||||
artifact-path: bin/libgodot-cpp.linux.template_release.double.x86_64.a
|
||||
flags: precision=double
|
||||
run-tests: false
|
||||
cache-name: linux-x86_64-f64
|
||||
|
||||
- name: 🏁 Windows (x86_64, MSVC)
|
||||
os: windows-2019
|
||||
platform: windows
|
||||
artifact-name: godot-cpp-windows-msvc2019-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.lib
|
||||
run-tests: false
|
||||
cache-name: windows-x86_64-msvc
|
||||
|
||||
- name: 🏁 Windows (x86_64, MinGW)
|
||||
os: windows-2019
|
||||
platform: windows
|
||||
artifact-name: godot-cpp-linux-mingw-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.a
|
||||
flags: use_mingw=yes
|
||||
run-tests: false
|
||||
cache-name: windows-x86_64-mingw
|
||||
|
||||
- name: 🍎 macOS (universal)
|
||||
os: macos-11
|
||||
platform: macos
|
||||
artifact-name: godot-cpp-macos-universal-release
|
||||
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
|
||||
flags: arch=universal
|
||||
run-tests: false
|
||||
cache-name: macos-universal
|
||||
|
||||
- name: 🤖 Android (arm64)
|
||||
os: ubuntu-20.04
|
||||
platform: android
|
||||
artifact-name: godot-cpp-android-arm64-release
|
||||
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
|
||||
flags: ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME arch=arm64
|
||||
run-tests: false
|
||||
cache-name: android-arm64
|
||||
|
||||
- name: 🍏 iOS (arm64)
|
||||
os: macos-11
|
||||
platform: ios
|
||||
artifact-name: godot-cpp-ios-arm64-release
|
||||
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
|
||||
flags: arch=arm64
|
||||
run-tests: false
|
||||
cache-name: ios-arm64
|
||||
|
||||
- name: 🌐 Web (wasm32)
|
||||
os: ubuntu-20.04
|
||||
platform: web
|
||||
artifact-name: godot-cpp-web-wasm32-release
|
||||
artifact-path: bin/libgodot-cpp.web.template_release.wasm32.a
|
||||
run-tests: false
|
||||
cache-name: web-wasm32
|
||||
|
||||
env:
|
||||
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
|
||||
EM_VERSION: 3.1.45
|
||||
EM_CACHE_FOLDER: "emsdk-cache"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Godot build cache
|
||||
uses: ./.github/actions/godot-cache
|
||||
with:
|
||||
cache-name: ${{ matrix.cache-name }}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Set up Python (for SCons)
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Linux dependencies
|
||||
if: ${{ matrix.platform == 'linux' }}
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qqq build-essential pkg-config
|
||||
|
||||
- name: Web dependencies
|
||||
if: ${{ matrix.platform == 'web' }}
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
with:
|
||||
version: ${{env.EM_VERSION}}
|
||||
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
||||
|
||||
- name: Install scons
|
||||
run: |
|
||||
python -m pip install scons==4.0.0
|
||||
|
||||
- name: Setup MinGW for Windows/MinGW build
|
||||
if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }}
|
||||
uses: egor-tensin/setup-mingw@v2
|
||||
with:
|
||||
version: 12.2.0
|
||||
|
||||
- name: Generate godot-cpp sources only
|
||||
run: |
|
||||
scons platform=${{ matrix.platform }} build_library=no ${{ matrix.flags }}
|
||||
scons -c
|
||||
|
||||
- name: Build godot-cpp (debug)
|
||||
run: |
|
||||
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }}
|
||||
|
||||
- name: Build test without rebuilding godot-cpp (debug)
|
||||
run: |
|
||||
cd test
|
||||
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }} build_library=no
|
||||
|
||||
- name: Build test and godot-cpp (release)
|
||||
run: |
|
||||
cd test
|
||||
scons platform=${{ matrix.platform }} target=template_release ${{ matrix.flags }}
|
||||
|
||||
- name: Download latest Godot artifacts
|
||||
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
|
||||
if: ${{ matrix.run-tests }}
|
||||
with:
|
||||
repo: godotengine/godot
|
||||
branch: master
|
||||
event: push
|
||||
workflow: linux_builds.yml
|
||||
workflow_conclusion: success
|
||||
name: linux-editor-mono
|
||||
search_artifacts: true
|
||||
check_artifacts: true
|
||||
ensure_latest: true
|
||||
path: godot-artifacts
|
||||
|
||||
- name: Run tests
|
||||
if: ${{ matrix.run-tests }}
|
||||
run: |
|
||||
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
|
||||
./godot-artifacts/godot.linuxbsd.editor.x86_64.mono --headless --version
|
||||
cd test
|
||||
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
|
||||
(cd project && (timeout 10 ../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true))
|
||||
GODOT=../godot-artifacts/godot.linuxbsd.editor.x86_64.mono ./run-tests.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: ${{ matrix.artifact-path }}
|
||||
if-no-files-found: error
|
||||
|
||||
linux-cmake:
|
||||
name: 🐧 Build (Linux, GCC, CMake)
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qqq build-essential pkg-config 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
|
||||
54
.github/workflows/static_checks.yml
vendored
54
.github/workflows/static_checks.yml
vendored
@@ -1,54 +0,0 @@
|
||||
name: 📊 Static Checks
|
||||
on: [push, pull_request]
|
||||
|
||||
concurrency:
|
||||
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
static-checks:
|
||||
name: Format (clang-format, black format, file format)
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Azure repositories are not reliable, we need to prevent Azure giving us packages.
|
||||
- name: Make apt sources.list use the default Ubuntu repositories
|
||||
run: |
|
||||
sudo rm -f /etc/apt/sources.list.d/*
|
||||
sudo cp -f misc/ci/sources.list /etc/apt/sources.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main"
|
||||
sudo apt-get update
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install -qq dos2unix recode clang-format-15 libxml2-utils python3-pip moreutils
|
||||
sudo update-alternatives --remove-all clang-format || true
|
||||
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100
|
||||
sudo pip3 install black==22.3.0 pygments pytest==7.1.2 mypy==0.971
|
||||
|
||||
- name: File formatting checks (file_format.sh)
|
||||
run: |
|
||||
bash ./misc/scripts/file_format.sh
|
||||
|
||||
- name: Header guards formatting checks (header_guards.sh)
|
||||
run: |
|
||||
bash ./misc/scripts/header_guards.sh
|
||||
|
||||
- name: Python style checks via black (black_format.sh)
|
||||
run: |
|
||||
bash ./misc/scripts/black_format.sh
|
||||
|
||||
- name: Python scripts static analysis (mypy_check.sh)
|
||||
run: |
|
||||
bash ./misc/scripts/mypy_check.sh
|
||||
|
||||
- name: Bindings generation checks (ensures get_file_list returns all generated files)
|
||||
run: |
|
||||
python ./misc/scripts/check_get_file_list.py
|
||||
|
||||
- name: Style checks via clang-format (clang_format.sh)
|
||||
run: |
|
||||
bash ./misc/scripts/clang_format.sh
|
||||
179
.gitignore
vendored
179
.gitignore
vendored
@@ -1,29 +1,11 @@
|
||||
# Godot auto generated files
|
||||
*.gen.*
|
||||
.import/
|
||||
.godot/
|
||||
/gen/
|
||||
|
||||
# Godot 3.x ignores
|
||||
include/gen
|
||||
src/gen
|
||||
|
||||
# Build configuarion.
|
||||
/custom.py
|
||||
|
||||
# Misc
|
||||
logs/*
|
||||
*.log
|
||||
|
||||
# The default cache directory
|
||||
cache/
|
||||
|
||||
# Binaries
|
||||
*.o
|
||||
*.os
|
||||
*.so
|
||||
*.obj
|
||||
*.bc
|
||||
*.pyc
|
||||
*.dblite
|
||||
*.pdb
|
||||
@@ -34,164 +16,3 @@ bin
|
||||
*.creator.user
|
||||
*.files
|
||||
*.includes
|
||||
*.idb
|
||||
|
||||
# Gprof output
|
||||
gmon.out
|
||||
|
||||
# Vim temp files
|
||||
*.swo
|
||||
*.swp
|
||||
|
||||
# Qt project files
|
||||
*.config
|
||||
*.creator
|
||||
*.creator.*
|
||||
*.files
|
||||
*.includes
|
||||
*.cflags
|
||||
*.cxxflags
|
||||
|
||||
# Eclipse CDT files
|
||||
.cproject
|
||||
.settings/
|
||||
|
||||
# Geany/geany-plugins files
|
||||
*.geany
|
||||
.geanyprj
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
logs/
|
||||
|
||||
# for projects that use SCons for building: http://http://www.scons.org/
|
||||
.sconf_temp
|
||||
.sconsign.dblite
|
||||
*.pyc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.opendb
|
||||
*.VC.VC.opendb
|
||||
enc_temp_folder/
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# CodeLite project files
|
||||
*.project
|
||||
*.workspace
|
||||
.codelite/
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.[Cc]ache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
__pycache__/
|
||||
|
||||
# KDE
|
||||
.directory
|
||||
|
||||
#Kdevelop project files
|
||||
*.kdev4
|
||||
|
||||
# xCode
|
||||
xcuserdata
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# =========================
|
||||
# Windows detritus
|
||||
# =========================
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
logo.h
|
||||
*.autosave
|
||||
|
||||
# https://github.com/github/gitignore/blob/master/Global/Tags.gitignore
|
||||
# Ignore tags created by etags, ctags, gtags (GNU global) and cscope
|
||||
TAGS
|
||||
!TAGS/
|
||||
tags
|
||||
*.tags
|
||||
!tags/
|
||||
gtags.files
|
||||
GTAGS
|
||||
GRTAGS
|
||||
GPATH
|
||||
cscope.files
|
||||
cscope.out
|
||||
cscope.in.out
|
||||
cscope.po.out
|
||||
godot.creator.*
|
||||
|
||||
# Visual Studio 2017 and Visual Studio Code workspace folder
|
||||
/.vs
|
||||
/.vscode
|
||||
|
||||
# Visual Studio Code workspace file
|
||||
*.code-workspace
|
||||
|
||||
# Scons progress indicator
|
||||
.scons_node_count
|
||||
|
||||
# ccls cache (https://github.com/MaskRay/ccls)
|
||||
.ccls-cache/
|
||||
|
||||
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
|
||||
compile_commands.json
|
||||
|
||||
# Python development
|
||||
.venv
|
||||
venv
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -0,0 +1,3 @@
|
||||
[submodule "godot_headers"]
|
||||
path = godot_headers
|
||||
url = https://github.com/godotengine/godot-headers
|
||||
|
||||
257
CMakeLists.txt
257
CMakeLists.txt
@@ -1,93 +1,80 @@
|
||||
# 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")
|
||||
#
|
||||
# GODOT_HEADERS_DIR: This is where the gdnative include folder is (godot_source/modules/gdnative/include)
|
||||
# GODOT_CUSTOM_API_FILE: This is if you have another path for the godot_api.json
|
||||
#
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(godot-cpp LANGUAGES CXX)
|
||||
project(godot-cpp)
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
|
||||
option(GODOT_CPP_SYSTEM_HEADERS "Expose headers as SYSTEM." ON)
|
||||
option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
|
||||
|
||||
# Add path to modules
|
||||
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
|
||||
|
||||
# Check if we are building ourself or being included
|
||||
if(${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME})
|
||||
set(GODOT_CPP_BUILDING_SELF ON)
|
||||
endif()
|
||||
|
||||
# Set some helper variables for readability
|
||||
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
|
||||
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
|
||||
set( compiler_is_msvc "$<CXX_COMPILER_ID:MSVC>" )
|
||||
# Change the output directory to the bin directory
|
||||
set(BUILD_PATH ${CMAKE_SOURCE_DIR}/bin)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${BUILD_PATH}")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${BUILD_PATH}")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${BUILD_PATH}")
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
|
||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
|
||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
|
||||
|
||||
# Default build type is Debug in the SConstruct
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED BITS)
|
||||
set(BITS 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(BITS 64)
|
||||
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
add_definitions(-D_DEBUG)
|
||||
else()
|
||||
add_definitions(-DNDEBUG)
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
||||
# 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 the c++ standard to c++14
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
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()
|
||||
# Input from user for godot headers and the api file
|
||||
set(GODOT_HEADERS_DIR "godot_headers" CACHE STRING "")
|
||||
set(GODOT_CUSTOM_API_FILE "godot_headers/api.json" CACHE STRING "")
|
||||
|
||||
set(GODOT_COMPILE_FLAGS )
|
||||
set(GODOT_LINKER_FLAGS )
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP
|
||||
set(GODOT_COMPILE_FLAGS "/EHsc /WX") # /GF /MP
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
|
||||
@@ -97,9 +84,44 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
||||
add_definitions(-DNOMINMAX)
|
||||
else() # GCC/Clang
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -g")
|
||||
# Disable conversion warning, trunkation, unreferenced var, signed missmatch
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /wd4244 /wd4305 /wd4101 /wd4018 /wd4267")
|
||||
|
||||
# Todo: Check if needed.
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
# Unkomment for warning level 4
|
||||
#if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
# string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
#endif()
|
||||
|
||||
else()
|
||||
|
||||
#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# using Clang
|
||||
#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC and maybe MinGW?
|
||||
|
||||
set(GODOT_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,-R,'$$ORIGIN'")
|
||||
|
||||
# Hmm.. maybe to strikt?
|
||||
set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wchar-subscripts -Wcomment -Wdisabled-optimization")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wformat -Wformat=2 -Wformat-security -Wformat-y2k")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wimport -Winit-self -Winline -Winvalid-pch -Werror")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wlong-long -Wmissing-braces -Wmissing-format-attribute")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpointer-arith")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wredundant-decls -Wreturn-type -Wsequence-point")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wswitch -Wswitch-enum -Wtrigraphs")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused-label")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wunused-value -Wvariadic-macros -Wvolatile-register-var -Wno-error=attributes")
|
||||
|
||||
# -Wshadow -Wextra -Wall -Weffc++ -Wfloat-equal -Wstack-protector -Wunused-parameter -Wsign-compare -Wunused-variable -Wcast-align
|
||||
# -Wunused-function -Wstrict-aliasing -Wstrict-aliasing=2 -Wmissing-field-initializers
|
||||
|
||||
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wno-ignored-attributes")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0")
|
||||
@@ -108,121 +130,52 @@ else() # GCC/Clang
|
||||
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)"
|
||||
message(STATUS "Generating Bindings")
|
||||
execute_process(COMMAND "python" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_CUSTOM_API_FILE}\")"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GENERATED_FILES_LIST
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
|
||||
COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${FLOAT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")"
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py
|
||||
COMMENT "Generating bindings"
|
||||
)
|
||||
RESULT_VARIABLE GENERATION_RESULT
|
||||
OUTPUT_VARIABLE GENERATION_OUTPUT)
|
||||
message(STATUS ${GENERATION_RESULT} ${GENERATION_OUTPUT})
|
||||
|
||||
# Get Sources
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**)
|
||||
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**)
|
||||
file(GLOB_RECURSE SOURCES src/*.c**)
|
||||
file(GLOB_RECURSE HEADERS include/*.h**)
|
||||
|
||||
# Define our godot-cpp library
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
${SOURCES}
|
||||
${HEADERS}
|
||||
${GENERATED_FILES_LIST}
|
||||
)
|
||||
add_library(godot::cpp ALIAS ${PROJECT_NAME})
|
||||
|
||||
include(GodotCompilerWarnings)
|
||||
|
||||
# Treat warnings as errors if we are building ourself
|
||||
if(GODOT_CPP_BUILDING_SELF)
|
||||
unset( GODOT_CPP_WARNING_AS_ERROR CACHE )
|
||||
set_warning_as_error()
|
||||
endif()
|
||||
|
||||
target_compile_features(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
cxx_std_17
|
||||
)
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC
|
||||
$<$<CONFIG:Debug>:
|
||||
DEBUG_ENABLED
|
||||
DEBUG_METHODS_ENABLED
|
||||
>
|
||||
$<${compiler_is_msvc}:
|
||||
TYPED_METHOD_BIND
|
||||
>
|
||||
)
|
||||
|
||||
target_link_options(${PROJECT_NAME} PRIVATE
|
||||
$<$<NOT:${compiler_is_msvc}>:
|
||||
-static-libgcc
|
||||
-static-libstdc++
|
||||
-Wl,-R,'$$ORIGIN'
|
||||
>
|
||||
)
|
||||
|
||||
# Optionally mark headers as SYSTEM
|
||||
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE "")
|
||||
if (GODOT_CPP_SYSTEM_HEADERS)
|
||||
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
|
||||
endif ()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} ${GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
|
||||
add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS})
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
include
|
||||
${CMAKE_CURRENT_BINARY_DIR}/gen/include
|
||||
${GODOT_GDEXTENSION_DIR}
|
||||
include/core
|
||||
include/gen
|
||||
)
|
||||
|
||||
# Put godot headers as SYSTEM PUBLIC to exclude warnings from irrelevant headers
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
SYSTEM PUBLIC
|
||||
${GODOT_HEADERS_DIR}
|
||||
)
|
||||
|
||||
# Add the compile flags
|
||||
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
|
||||
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS ${GODOT_LINKER_FLAGS})
|
||||
|
||||
# Create the correct name (godot.os.build_type.system_bits)
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
|
||||
|
||||
set(BITS 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(BITS 64)
|
||||
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME)
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILD_TYPE)
|
||||
|
||||
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}")
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
|
||||
else()
|
||||
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
CXX_EXTENSIONS OFF
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
OUTPUT_NAME "${OUTPUT_NAME}"
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (c) 2017-present Godot Engine contributors.
|
||||
Copyright (c) 2017-2019 GodotNativeTools
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
37
Makefile
37
Makefile
@@ -1,17 +1,17 @@
|
||||
TARGET = template_debug
|
||||
GENERATE_BINDINGS = no
|
||||
HEADERS = godot_headers
|
||||
TARGET = debug
|
||||
USE_CLANG = no
|
||||
|
||||
BASE = scons target=$(TARGET) $(EXTRA_ARGS)
|
||||
BASE = scons use_llvm=$(USE_CLANG) generate_bindings=$(GENERATE_BINDINGS) target=$(TARGET) headers=$(HEADERS) -j4
|
||||
LINUX = $(BASE) platform=linux
|
||||
WINDOWS = $(BASE) platform=windows
|
||||
MACOS = $(BASE) platform=macos
|
||||
OSX = $(BASE) platform=osx
|
||||
|
||||
|
||||
.PHONY: usage
|
||||
usage:
|
||||
@echo -e "Specify one of the available targets:\n"
|
||||
# https://stackoverflow.com/a/26339924
|
||||
@LC_ALL=C $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/(^|\n)# Files(\n|$$)/,/(^|\n)# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | grep -E -v -e '^[^[:alnum:]]' -e '^$@$$'
|
||||
@echo -e "\nDefine the SCons target with TARGET, and pass extra SCons arguments with EXTRA_ARGS."
|
||||
all:
|
||||
make linux
|
||||
make windows
|
||||
|
||||
|
||||
linux:
|
||||
@@ -19,10 +19,10 @@ linux:
|
||||
make linux64
|
||||
|
||||
linux32: SConstruct
|
||||
$(LINUX) arch=x86_32
|
||||
$(LINUX) bits=32
|
||||
|
||||
linux64: SConstruct
|
||||
$(LINUX) arch=x86_64
|
||||
$(LINUX) bits=64
|
||||
|
||||
|
||||
windows:
|
||||
@@ -30,11 +30,18 @@ windows:
|
||||
make windows64
|
||||
|
||||
windows32: SConstruct
|
||||
$(WINDOWS) arch=x86_32
|
||||
$(WINDOWS) bits=32
|
||||
|
||||
windows64: SConstruct
|
||||
$(WINDOWS) arch=x86_64
|
||||
$(WINDOWS) bits=64
|
||||
|
||||
|
||||
macos: SConstruct
|
||||
$(MACOS)
|
||||
osx:
|
||||
make osx32
|
||||
make osx64
|
||||
|
||||
osx32: SConstruct
|
||||
$(OSX) bits=32
|
||||
|
||||
osx64: SConstruct
|
||||
$(OSX) bits=64
|
||||
|
||||
293
README.md
293
README.md
@@ -1,143 +1,200 @@
|
||||
# godot-cpp
|
||||
C++ bindings for the Godot script API
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> This repository's `master` branch is only usable with
|
||||
> [GDExtension](https://godotengine.org/article/introducing-gd-extensions)
|
||||
> from Godot's `master` branch.
|
||||
>
|
||||
> For users of stable branches, switch to the branch matching your target Godot version:
|
||||
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
|
||||
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
|
||||
>
|
||||
> Or check out the Git tag matching your Godot version (e.g. `godot-4.1.1-stable`).
|
||||
>
|
||||
> For GDNative users (Godot 3.x), switch to the [`3.x`](https://github.com/godotengine/godot-cpp/tree/3.x)
|
||||
> or the [`3.5`](https://github.com/godotengine/godot-cpp/tree/3.5) branch.
|
||||
The instructions below feature the new NativeScript 1.1 class structure and will only work for modules created for Godot 3.1 and later. Use the following branches for older implementations:
|
||||
|
||||
This repository contains the *C++ bindings* for the [**Godot Engine**](https://github.com/godotengine/godot)'s GDExtensions API.
|
||||
Version | Branch
|
||||
--- | ---
|
||||
**Godot 3.0 Nativescript 1.0** | [3.0](https://github.com/GodotNativeTools/godot-cpp/tree/3.0)
|
||||
**Godot 3.1 Nativescript 1.0** | [nativescript-1.0](https://github.com/GodotNativeTools/godot-cpp/tree/nativescript-1.0)
|
||||
|
||||
- [**Versioning**](#versioning)
|
||||
- [**Compatibility**](#compatibility)
|
||||
- [**Contributing**](#contributing)
|
||||
- [**Getting started**](#getting-started)
|
||||
- [**Included example**](#included-example)
|
||||
|
||||
## Versioning
|
||||
|
||||
This repositories follows the same branch versioning as the main [Godot Engine
|
||||
repository](https://github.com/godotengine/godot):
|
||||
|
||||
- `master` tracks the current GDExtension development branch for the next Godot
|
||||
4.x minor release.
|
||||
- `3.x` tracks the development of the GDNative plugin for the next 3.x minor
|
||||
release.
|
||||
- Other versioned branches (e.g. `4.0`, `3.5`) track the latest stable release
|
||||
in the corresponding branch.
|
||||
|
||||
Stable releases are also tagged on this repository:
|
||||
[**Tags**](https://github.com/godotengine/godot-cpp/tags).
|
||||
|
||||
**For any project built against a stable release of Godot, we recommend using
|
||||
this repository as a Git submodule, checking out the specific tag matching your
|
||||
Godot version.**
|
||||
|
||||
> As the `master` branch of Godot is constantly getting updated, if you are
|
||||
> using `godot-cpp` against a more current version of Godot, see the instructions
|
||||
> in the `gdextension` folder to update the relevant files.
|
||||
|
||||
## Compatibility
|
||||
|
||||
**Warning:** The GDExtension API is brand new in Godot 4.0, and is still
|
||||
considered in **beta** stage, despite Godot 4.0 itself being released.
|
||||
|
||||
This applies to both the GDExtension interface header, the API JSON, and this
|
||||
first-party `godot-cpp` extension.
|
||||
|
||||
Some compatibility breakage is to be expected as GDExtension and `godot-cpp`
|
||||
get more used, documented, and critical issues get resolved. See the
|
||||
[Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension)
|
||||
and the [godot-cpp issue tracker](https://github.com/godotengine/godot/issues)
|
||||
for a list of known issues, and be sure to provide feedback on issues and PRs
|
||||
which affect your use of this extension.
|
||||
Index:
|
||||
- [**Contributing**](#contributing)
|
||||
- [**Getting Started**](#getting-started)
|
||||
- [**Creating a simple class**](#creating-a-simple-class)
|
||||
|
||||
## Contributing
|
||||
We greatly appreciate help in maintaining and extending this project.
|
||||
If you wish to help out ensure you have an account on Github and create a "fork" of the this repo.
|
||||
Rémi "Akien" Verschelde wrote an excellent bit of documentation for the main Godot project on this:
|
||||
https://docs.godotengine.org/en/3.0/community/contributing/pr_workflow.html
|
||||
|
||||
We greatly appreciate help in maintaining and extending this project. If you
|
||||
wish to help out, ensure you have an account on GitHub and create a "fork" of
|
||||
this repository. See [Pull request workflow](https://docs.godotengine.org/en/stable/community/contributing/pr_workflow.html)
|
||||
for instructions.
|
||||
It is advisible to also install clang-format and copy the files in `misc/hooks` into `.git/hooks` so format checking is done before your changes are submitted.
|
||||
|
||||
Please install clang-format and copy the files in `misc/hooks` into `.git/hooks`
|
||||
so formatting is done before your changes are submitted.
|
||||
## Getting Started
|
||||
|
||||
## Getting started
|
||||
| **Build latest version of Godot** | [**GitHub**](https://github.com/godotengine/godot) | [**Docs**](https://godot.readthedocs.io/en/latest/development/compiling/index.html) |
|
||||
| --- | --- | --- |
|
||||
|
||||
It's a bit similar to what it was for 3.x but also a bit different.
|
||||
This new approach is much more akin to how core Godot modules are structured.
|
||||
### Setting up a new project
|
||||
|
||||
Compiling this repository generates a static library to be linked with your shared lib,
|
||||
just like before.
|
||||
We recommend using git for managing your project and the instructions below assume so. Alternatively you can download the source code directly from GitHub in which case you need to download both [godot-cpp](https://github.com/GodotNativeTools/godot-cpp) and [godot_headers](https://github.com/GodotNativeTools/godot_headers).
|
||||
|
||||
To use the shared lib in your Godot project you'll need a `.gdextension`
|
||||
file, which replaces what was the `.gdnlib` before.
|
||||
See [example.gdextension](test/project/example.gdextension) used in the test project:
|
||||
|
||||
```ini
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "example_library_init"
|
||||
compatibility_minimum = "4.1"
|
||||
|
||||
[libraries]
|
||||
|
||||
macos.debug = "res://bin/libgdexample.macos.debug.framework"
|
||||
macos.release = "res://bin/libgdexample.macos.release.framework"
|
||||
windows.debug.x86_64 = "res://bin/libgdexample.windows.debug.x86_64.dll"
|
||||
windows.release.x86_64 = "res://bin/libgdexample.windows.release.x86_64.dll"
|
||||
linux.debug.x86_64 = "res://bin/libgdexample.linux.debug.x86_64.so"
|
||||
linux.release.x86_64 = "res://bin/libgdexample.linux.release.x86_64.so"
|
||||
# Repeat for other architectures to support arm64, rv64, etc.
|
||||
```
|
||||
$ mkdir SimpleLibrary
|
||||
$ cd SimpleLibrary
|
||||
$ mkdir bin
|
||||
$ mkdir src
|
||||
$ git clone --recursive https://github.com/GodotNativeTools/godot-cpp
|
||||
```
|
||||
|
||||
The `entry_symbol` is the name of the function that initializes
|
||||
your library. It should be similar to following layout:
|
||||
|
||||
```cpp
|
||||
extern "C" {
|
||||
|
||||
// Initialization.
|
||||
|
||||
GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
|
||||
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
|
||||
|
||||
init_obj.register_initializer(initialize_example_module);
|
||||
init_obj.register_terminator(uninitialize_example_module);
|
||||
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
|
||||
|
||||
return init_obj.init();
|
||||
}
|
||||
}
|
||||
Note that if you wish to use a specific branch, add the -b option to the clone command:
|
||||
```
|
||||
$ git clone --recursive https://github.com/GodotNativeTools/godot-cpp -b 3.0
|
||||
```
|
||||
|
||||
The `initialize_example_module()` should register the classes in ClassDB, very like a Godot module would do.
|
||||
If your project is an existing repository, use git submodule instead:
|
||||
```
|
||||
$ git submodule add https://github.com/GodotNativeTools/godot-cpp
|
||||
$ git submodule update --init --recursive
|
||||
```
|
||||
|
||||
Right now our directory structure should look like this:
|
||||
```
|
||||
SimpleLibrary/
|
||||
├─godot-cpp/
|
||||
| └─godot_headers/
|
||||
├─bin/
|
||||
└─src/
|
||||
```
|
||||
|
||||
### Updating the api.json
|
||||
Our api.json file contains meta data of all the classes that are part of the Godot core and are needed to generate the C++ binding classes for use in GDNative modules.
|
||||
|
||||
This file is supplied with our godot_headers repository for your convinience but if you are running a custom build of Godot and need access to classes that have recent changes a new api.json file must be generated. You do this by starting your Godot executable with the following parameters:
|
||||
|
||||
```
|
||||
$ godot --gdnative-generate-json-api api.json
|
||||
```
|
||||
|
||||
Now copy the api.json file into your folder structure so its easy to access. **Note** the remark below for the extra ```custom_api_file``` command line parameter needed to tell scons where to find your file.
|
||||
|
||||
### Compiling the cpp bindings library
|
||||
The final step is to compile our cpp bindings library:
|
||||
```
|
||||
$ cd godot-cpp
|
||||
$ scons platform=<your platform> generate_bindings=yes
|
||||
$ cd ..
|
||||
```
|
||||
|
||||
> Replace `<your platform>` with either `windows`, `linux` or `osx`.
|
||||
|
||||
> Include `use_llvm=yes` for using clang++
|
||||
|
||||
> Include `target=runtime` to build a runtime build (windows only at the moment)
|
||||
|
||||
> The resulting library will be created in `godot-cpp/bin/`, take note of its name as it will be different depending on platform.
|
||||
|
||||
> If you want to use an alternative api.json file add `use_custom_api_file=yes custom_api_file=../api.json`, be sure to specify the correct location of where you placed your file.
|
||||
|
||||
## Creating a simple class
|
||||
|
||||
Create `init.cpp` under `SimpleLibrary/src/` and add the following code
|
||||
```cpp
|
||||
#include <Godot.hpp>
|
||||
#include <Reference.hpp>
|
||||
|
||||
using namespace godot;
|
||||
void initialize_example_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
ClassDB::register_class<Example>();
|
||||
|
||||
class SimpleClass : public Reference {
|
||||
GODOT_CLASS(SimpleClass, Reference);
|
||||
public:
|
||||
SimpleClass() { }
|
||||
|
||||
/* _init must exist as it is called by Godot */
|
||||
void _init() { }
|
||||
|
||||
void test_void_method() {
|
||||
Godot::print("This is test");
|
||||
}
|
||||
|
||||
Variant method(Variant arg) {
|
||||
Variant ret;
|
||||
ret = arg;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _register_methods() {
|
||||
register_method("method", &SimpleClass::method);
|
||||
|
||||
/**
|
||||
* How to register exports like gdscript
|
||||
* export var _name = "SimpleClass"
|
||||
**/
|
||||
register_property<SimpleClass, String>("base/name", &SimpleClass::_name, String("SimpleClass"));
|
||||
|
||||
/* or alternatively with getter and setter methods */
|
||||
register_property<SimpleClass, int>("base/value", &SimpleClass::set_value, &SimpleClass::get_value, 0);
|
||||
|
||||
/** For registering signal **/
|
||||
// register_signal<SimpleClass>("signal_name");
|
||||
// register_signal<SimpleClass>("signal_name", "string_argument", GODOT_VARIANT_TYPE_STRING)
|
||||
}
|
||||
|
||||
String _name;
|
||||
int _value;
|
||||
|
||||
void set_value(int p_value) {
|
||||
_value = p_value;
|
||||
}
|
||||
|
||||
int get_value() const {
|
||||
return _value;
|
||||
}
|
||||
};
|
||||
|
||||
/** GDNative Initialize **/
|
||||
extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
|
||||
godot::Godot::gdnative_init(o);
|
||||
}
|
||||
|
||||
/** GDNative Terminate **/
|
||||
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
|
||||
godot::Godot::gdnative_terminate(o);
|
||||
}
|
||||
|
||||
/** NativeScript Initialize **/
|
||||
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
|
||||
godot::Godot::nativescript_init(handle);
|
||||
|
||||
godot::register_class<SimpleClass>();
|
||||
}
|
||||
```
|
||||
|
||||
Any node and resource you register will be available in the corresponding `Create...` dialog. Any class will be available to scripting as well.
|
||||
### Compiling
|
||||
|
||||
## Examples and templates
|
||||
*Linux*
|
||||
```
|
||||
$ cd SimpleLibrary
|
||||
$ clang -fPIC -o src/init.os -c src/init.cpp -g -O3 -std=c++14 -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Igodot-cpp/godot_headers
|
||||
$ clang -o bin/libtest.so -shared src/init.os -Lgodot-cpp/bin -l<name of the godot-cpp>
|
||||
```
|
||||
> This creates the file `libtest.so` in your `SimpleLibrary/bin` directory.
|
||||
|
||||
See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template) project for a
|
||||
generic reusable template.
|
||||
> You will need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library)
|
||||
|
||||
*Windows*
|
||||
```
|
||||
$ cd SimpleLibrary
|
||||
$ cl /Fosrc/init.obj /c src/init.cpp /nologo -EHsc -DNDEBUG /MDd /Igodot-cpp\include /Igodot-cpp\include\core /Igodot-cpp\include\gen /Igodot-cpp\godot_headers
|
||||
$ link /nologo /dll /out:bin\libtest.dll /implib:bin\libsimple.lib src\init.obj godot-cpp\bin\<name of the godot-cpp>
|
||||
```
|
||||
> This creates the file `libtest.dll` in your `SimpleLibrary/bin` directory.
|
||||
|
||||
> You will need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library)
|
||||
|
||||
> Finally replace `/MDd` with `/MD` if you're generated a runtime build.
|
||||
|
||||
*macOS*
|
||||
For OSX you need to find out what compiler flags need to be used.
|
||||
|
||||
### Creating `.gdnlib` and `.gdns` files
|
||||
follow [godot_header/README.md](https://github.com/GodotNativeTools/godot_headers/blob/master/README.md#how-do-i-use-native-scripts-from-the-editor) to create the `.gdns`
|
||||
|
||||
### Implementing with gdscript
|
||||
```gdscript
|
||||
var simpleclass = load("res://simpleclass.gdns").new();
|
||||
simpleclass.method("Test argument");
|
||||
```
|
||||
|
||||
Or checkout the code for the [Summator example](https://github.com/paddy-exe/GDExtensionSummator)
|
||||
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/gdextension/gdextension_cpp_example.html).
|
||||
|
||||
172
SConstruct
172
SConstruct
@@ -1,56 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
#!python
|
||||
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import subprocess
|
||||
from binding_generator import scons_generate_bindings, scons_emit_files
|
||||
import os, subprocess, platform, sys
|
||||
|
||||
|
||||
EnsureSConsVersion(4, 0)
|
||||
def add_sources(sources, dir, extension):
|
||||
for f in os.listdir(dir):
|
||||
if f.endswith('.' + extension):
|
||||
sources.append(dir + '/' + f)
|
||||
|
||||
# Try to detect the host platform automatically
|
||||
# This is used if no `platform` argument is passed
|
||||
if sys.platform.startswith('linux'):
|
||||
host_platform = 'linux'
|
||||
elif sys.platform == 'darwin':
|
||||
host_platform = 'osx'
|
||||
elif sys.platform == 'win32':
|
||||
host_platform = 'windows'
|
||||
else:
|
||||
raise ValueError('Could not detect platform automatically, please specify with platform=<platform>')
|
||||
|
||||
try:
|
||||
Import("env")
|
||||
except:
|
||||
# Default tools with no platform defaults to gnu toolchain.
|
||||
# We apply platform specific toolchains via our custom tools.
|
||||
env = Environment(tools=["default"], PLATFORM="")
|
||||
opts = Variables([], ARGUMENTS)
|
||||
|
||||
env.PrependENVPath("PATH", os.getenv("PATH"))
|
||||
opts.Add(EnumVariable('platform', 'Target platform', host_platform,
|
||||
allowed_values=('linux', 'osx', 'windows'),
|
||||
ignorecase=2))
|
||||
opts.Add(EnumVariable('bits', 'Target platform bits', 'default', ('default', '32', '64')))
|
||||
opts.Add(BoolVariable('use_llvm', 'Use the LLVM compiler - only effective when targeting Linux', False))
|
||||
opts.Add(BoolVariable('use_mingw', 'Use the MinGW compiler - only effective on Windows', False))
|
||||
# Must be the same setting as used for cpp_bindings
|
||||
opts.Add(EnumVariable('target', 'Compilation target', 'debug',
|
||||
allowed_values=('debug', 'release'),
|
||||
ignorecase=2))
|
||||
opts.Add(PathVariable('headers_dir', 'Path to the directory containing Godot headers', 'godot_headers', PathVariable.PathIsDir))
|
||||
opts.Add(BoolVariable('use_custom_api_file', 'Use a custom JSON API file', False))
|
||||
opts.Add(PathVariable('custom_api_file', 'Path to the custom JSON API file', None, PathVariable.PathIsFile))
|
||||
opts.Add(BoolVariable('generate_bindings', 'Generate GDNative API bindings', False))
|
||||
|
||||
# Custom options and profile flags.
|
||||
customs = ["custom.py"]
|
||||
try:
|
||||
customs += Import("customs")
|
||||
except:
|
||||
pass
|
||||
profile = ARGUMENTS.get("profile", "")
|
||||
if profile:
|
||||
if os.path.isfile(profile):
|
||||
customs.append(profile)
|
||||
elif os.path.isfile(profile + ".py"):
|
||||
customs.append(profile + ".py")
|
||||
opts = Variables(customs, ARGUMENTS)
|
||||
cpp_tool = Tool("godotcpp", toolpath=["tools"])
|
||||
cpp_tool.options(opts, env)
|
||||
opts.Update(env)
|
||||
|
||||
Help(opts.GenerateHelpText(env))
|
||||
|
||||
# Detect and print a warning listing unknown SCons variables to ease troubleshooting.
|
||||
unknown = opts.UnknownVariables()
|
||||
if unknown:
|
||||
print("WARNING: Unknown SCons variables were passed and will be ignored:")
|
||||
for item in unknown.items():
|
||||
print(" " + item[0] + "=" + item[1])
|
||||
print("Unknown variables:" + unknown.keys())
|
||||
Exit(1)
|
||||
|
||||
scons_cache_path = os.environ.get("SCONS_CACHE")
|
||||
if scons_cache_path is not None:
|
||||
CacheDir(scons_cache_path)
|
||||
Decider("MD5")
|
||||
env = Environment()
|
||||
opts.Update(env)
|
||||
Help(opts.GenerateHelpText(env))
|
||||
|
||||
cpp_tool.generate(env)
|
||||
library = env.GodotCPP()
|
||||
# This makes sure to keep the session environment variables on Windows
|
||||
# This way, you can run SCons in a Visual Studio 2017 prompt and it will find all the required tools
|
||||
if env['platform'] == 'windows':
|
||||
if env['bits'] == '64':
|
||||
env = Environment(TARGET_ARCH='amd64')
|
||||
elif env['bits'] == '32':
|
||||
env = Environment(TARGET_ARCH='x86')
|
||||
else:
|
||||
print("Warning: bits argument not specified, target arch is=" + env['TARGET_ARCH'])
|
||||
opts.Update(env)
|
||||
|
||||
Return("env")
|
||||
is64 = False
|
||||
if (env['platform'] == 'osx' or env['TARGET_ARCH'] == 'amd64' or env['TARGET_ARCH'] == 'emt64' or env['TARGET_ARCH'] == 'x86_64'):
|
||||
is64 = True
|
||||
if env['bits'] == 'default':
|
||||
env['bits'] = '64' if is64 else '32'
|
||||
|
||||
if env['platform'] == 'linux':
|
||||
if env['use_llvm']:
|
||||
env['CXX'] = 'clang++'
|
||||
|
||||
env.Append(CCFLAGS=['-fPIC', '-g', '-std=c++14', '-Wwrite-strings'])
|
||||
env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"])
|
||||
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['-Og'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['-O3'])
|
||||
|
||||
if env['bits'] == '64':
|
||||
env.Append(CCFLAGS=['-m64'])
|
||||
env.Append(LINKFLAGS=['-m64'])
|
||||
elif env['bits'] == '32':
|
||||
env.Append(CCFLAGS=['-m32'])
|
||||
env.Append(LINKFLAGS=['-m32'])
|
||||
|
||||
elif env['platform'] == 'osx':
|
||||
if env['bits'] == '32':
|
||||
raise ValueError('Only 64-bit builds are supported for the macOS target.')
|
||||
|
||||
env.Append(CCFLAGS=['-g', '-std=c++14', '-arch', 'x86_64'])
|
||||
env.Append(LINKFLAGS=['-arch', 'x86_64', '-framework', 'Cocoa', '-Wl,-undefined,dynamic_lookup'])
|
||||
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['-Og'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['-O3'])
|
||||
|
||||
elif env['platform'] == 'windows':
|
||||
if host_platform == 'windows' and not env['use_mingw']:
|
||||
# MSVC
|
||||
env.Append(LINKFLAGS=['/WX'])
|
||||
if env['target'] == 'debug':
|
||||
env.Append(CCFLAGS=['/EHsc', '/D_DEBUG', '/MDd'])
|
||||
elif env['target'] == 'release':
|
||||
env.Append(CCFLAGS=['/O2', '/EHsc', '/DNDEBUG', '/MD'])
|
||||
else:
|
||||
# MinGW
|
||||
if env['bits'] == '64':
|
||||
env['CXX'] = 'x86_64-w64-mingw32-g++'
|
||||
elif env['bits'] == '32':
|
||||
env['CXX'] = 'i686-w64-mingw32-g++'
|
||||
|
||||
env.Append(CCFLAGS=['-g', '-O3', '-std=c++14', '-Wwrite-strings'])
|
||||
env.Append(LINKFLAGS=['--static', '-Wl,--no-undefined', '-static-libgcc', '-static-libstdc++'])
|
||||
|
||||
|
||||
env.Append(CPPPATH=['.', env['headers_dir'], 'include', 'include/gen', 'include/core'])
|
||||
|
||||
# Generate bindings?
|
||||
json_api_file = ''
|
||||
|
||||
if env['use_custom_api_file']:
|
||||
json_api_file = env['custom_api_file']
|
||||
else:
|
||||
json_api_file = os.path.join(os.getcwd(), 'godot_headers', 'api.json')
|
||||
|
||||
if env['generate_bindings']:
|
||||
# Actually create the bindings here
|
||||
|
||||
import binding_generator
|
||||
|
||||
binding_generator.generate_bindings(json_api_file)
|
||||
|
||||
# source to compile
|
||||
sources = []
|
||||
add_sources(sources, 'src/core', 'cpp')
|
||||
add_sources(sources, 'src/gen', 'cpp')
|
||||
|
||||
library = env.StaticLibrary(
|
||||
target='bin/' + 'libgodot-cpp.{}.{}.{}'.format(env['platform'], env['target'], env['bits']), source=sources
|
||||
)
|
||||
Default(library)
|
||||
|
||||
3092
binding_generator.py
3092
binding_generator.py
File diff suppressed because it is too large
Load Diff
@@ -1,94 +0,0 @@
|
||||
# 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()
|
||||
@@ -1,20 +0,0 @@
|
||||
# GDExtension header and API
|
||||
|
||||
This repository contains the C header and API JSON for
|
||||
[**Godot Engine**](https://github.com/godotengine/godot)'s *GDExtensions* API.
|
||||
|
||||
## Updating header and API
|
||||
|
||||
If the current branch is not up-to-date for your needs, or if you want to sync
|
||||
the header and API JSON with your own modified version of Godot, here is the
|
||||
update procedure used to sync this repository with upstream releases:
|
||||
|
||||
- Compile [Godot Engine](https://github.com/godotengine/godot) at the specific
|
||||
version/commit which you are using.
|
||||
* Or if you use an official release, download that version of the Godot editor.
|
||||
- Use the compiled or downloaded executable to generate the `extension_api.json`
|
||||
and `gdextension_interface.h` files with:
|
||||
|
||||
```
|
||||
godot --dump-extension-api --dump-gdextension-interface
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1
godot_headers
Submodule
1
godot_headers
Submodule
Submodule godot_headers added at 75d6c51496
82
include/core/AABB.hpp
Normal file
82
include/core/AABB.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef AABB_H
|
||||
#define AABB_H
|
||||
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include "Plane.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class AABB {
|
||||
public:
|
||||
Vector3 position;
|
||||
Vector3 size;
|
||||
|
||||
real_t get_area() const; /// get area
|
||||
inline bool has_no_area() const {
|
||||
|
||||
return (size.x <= CMP_EPSILON || size.y <= CMP_EPSILON || size.z <= CMP_EPSILON);
|
||||
}
|
||||
|
||||
inline bool has_no_surface() const {
|
||||
|
||||
return (size.x <= CMP_EPSILON && size.y <= CMP_EPSILON && size.z <= CMP_EPSILON);
|
||||
}
|
||||
|
||||
inline const Vector3 &get_position() const { return position; }
|
||||
inline void set_position(const Vector3 &p_position) { position = p_position; }
|
||||
inline const Vector3 &get_size() const { return size; }
|
||||
inline void set_size(const Vector3 &p_size) { size = p_size; }
|
||||
|
||||
bool operator==(const AABB &p_rval) const;
|
||||
bool operator!=(const AABB &p_rval) const;
|
||||
|
||||
bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
|
||||
bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
|
||||
bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
|
||||
|
||||
AABB merge(const AABB &p_with) const;
|
||||
void merge_with(const AABB &p_aabb); ///merge with another AABB
|
||||
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
|
||||
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
|
||||
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
|
||||
bool smits_intersect_ray(const Vector3 &from, const Vector3 &p_dir, real_t t0, real_t t1) const;
|
||||
|
||||
bool intersects_convex_shape(const Plane *p_plane, int p_plane_count) const;
|
||||
bool intersects_plane(const Plane &p_plane) const;
|
||||
|
||||
bool has_point(const Vector3 &p_point) const;
|
||||
Vector3 get_support(const Vector3 &p_normal) const;
|
||||
|
||||
Vector3 get_longest_axis() const;
|
||||
int get_longest_axis_index() const;
|
||||
real_t get_longest_axis_size() const;
|
||||
|
||||
Vector3 get_shortest_axis() const;
|
||||
int get_shortest_axis_index() const;
|
||||
real_t get_shortest_axis_size() const;
|
||||
|
||||
AABB grow(real_t p_by) const;
|
||||
void grow_by(real_t p_amount);
|
||||
|
||||
void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const;
|
||||
Vector3 get_endpoint(int p_point) const;
|
||||
|
||||
AABB expand(const Vector3 &p_vector) const;
|
||||
void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
|
||||
void expand_to(const Vector3 &p_vector); /** expand to contain a point if necesary */
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline AABB() {}
|
||||
inline AABB(const Vector3 &p_pos, const Vector3 &p_size) {
|
||||
position = p_pos;
|
||||
size = p_size;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // RECT3_H
|
||||
106
include/core/Array.hpp
Normal file
106
include/core/Array.hpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include <gdnative/array.h>
|
||||
|
||||
#include "Defs.hpp"
|
||||
#include "String.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Variant;
|
||||
class PoolByteArray;
|
||||
class PoolIntArray;
|
||||
class PoolRealArray;
|
||||
class PoolStringArray;
|
||||
class PoolVector2Array;
|
||||
class PoolVector3Array;
|
||||
class PoolColorArray;
|
||||
|
||||
class Object;
|
||||
|
||||
class Array {
|
||||
godot_array _godot_array;
|
||||
|
||||
public:
|
||||
Array();
|
||||
Array(const Array &other);
|
||||
Array &operator=(const Array &other);
|
||||
|
||||
Array(const PoolByteArray &a);
|
||||
|
||||
Array(const PoolIntArray &a);
|
||||
|
||||
Array(const PoolRealArray &a);
|
||||
|
||||
Array(const PoolStringArray &a);
|
||||
|
||||
Array(const PoolVector2Array &a);
|
||||
|
||||
Array(const PoolVector3Array &a);
|
||||
|
||||
Array(const PoolColorArray &a);
|
||||
|
||||
template <class... Args>
|
||||
static Array make(Args... args) {
|
||||
return helpers::append_all(Array(), args...);
|
||||
}
|
||||
|
||||
Variant &operator[](const int idx);
|
||||
|
||||
Variant operator[](const int idx) const;
|
||||
|
||||
void append(const Variant &v);
|
||||
|
||||
void clear();
|
||||
|
||||
int count(const Variant &v);
|
||||
|
||||
bool empty() const;
|
||||
|
||||
void erase(const Variant &v);
|
||||
|
||||
Variant front() const;
|
||||
|
||||
Variant back() const;
|
||||
|
||||
int find(const Variant &what, const int from = 0);
|
||||
|
||||
int find_last(const Variant &what);
|
||||
|
||||
bool has(const Variant &what) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
|
||||
void insert(const int pos, const Variant &value);
|
||||
|
||||
void invert();
|
||||
|
||||
bool is_shared() const;
|
||||
|
||||
Variant pop_back();
|
||||
|
||||
Variant pop_front();
|
||||
|
||||
void push_back(const Variant &v);
|
||||
|
||||
void push_front(const Variant &v);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
int rfind(const Variant &what, const int from = -1);
|
||||
|
||||
void sort();
|
||||
|
||||
void sort_custom(Object *obj, const String &func);
|
||||
|
||||
~Array();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // ARRAY_H
|
||||
132
include/core/Basis.hpp
Normal file
132
include/core/Basis.hpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#ifndef BASIS_H
|
||||
#define BASIS_H
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "Vector3.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Quat;
|
||||
|
||||
class Basis {
|
||||
public:
|
||||
union {
|
||||
Vector3 elements[3];
|
||||
Vector3 x, y, z;
|
||||
};
|
||||
|
||||
Basis(const Quat &p_quat); // euler
|
||||
Basis(const Vector3 &p_euler); // euler
|
||||
Basis(const Vector3 &p_axis, real_t p_phi);
|
||||
|
||||
Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2);
|
||||
|
||||
Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz);
|
||||
|
||||
Basis();
|
||||
|
||||
const Vector3 &operator[](int axis) const;
|
||||
Vector3 &operator[](int axis);
|
||||
|
||||
void invert();
|
||||
|
||||
bool isequal_approx(const Basis &a, const Basis &b) const;
|
||||
|
||||
bool is_orthogonal() const;
|
||||
|
||||
bool is_rotation() const;
|
||||
|
||||
void transpose();
|
||||
|
||||
Basis inverse() const;
|
||||
|
||||
Basis transposed() const;
|
||||
|
||||
real_t determinant() const;
|
||||
|
||||
Vector3 get_axis(int p_axis) const;
|
||||
|
||||
void set_axis(int p_axis, const Vector3 &p_value);
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_phi);
|
||||
|
||||
Basis rotated(const Vector3 &p_axis, real_t p_phi) const;
|
||||
|
||||
void scale(const Vector3 &p_scale);
|
||||
|
||||
Basis scaled(const Vector3 &p_scale) const;
|
||||
|
||||
Vector3 get_scale() const;
|
||||
|
||||
Vector3 get_euler_xyz() const;
|
||||
void set_euler_xyz(const Vector3 &p_euler);
|
||||
Vector3 get_euler_yxz() const;
|
||||
void set_euler_yxz(const Vector3 &p_euler);
|
||||
|
||||
inline Vector3 get_euler() const { return get_euler_yxz(); }
|
||||
inline void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }
|
||||
|
||||
// transposed dot products
|
||||
real_t tdotx(const Vector3 &v) const;
|
||||
real_t tdoty(const Vector3 &v) const;
|
||||
real_t tdotz(const Vector3 &v) const;
|
||||
|
||||
bool operator==(const Basis &p_matrix) const;
|
||||
|
||||
bool operator!=(const Basis &p_matrix) const;
|
||||
|
||||
Vector3 xform(const Vector3 &p_vector) const;
|
||||
|
||||
Vector3 xform_inv(const Vector3 &p_vector) const;
|
||||
void operator*=(const Basis &p_matrix);
|
||||
|
||||
Basis operator*(const Basis &p_matrix) const;
|
||||
|
||||
void operator+=(const Basis &p_matrix);
|
||||
|
||||
Basis operator+(const Basis &p_matrix) const;
|
||||
|
||||
void operator-=(const Basis &p_matrix);
|
||||
|
||||
Basis operator-(const Basis &p_matrix) const;
|
||||
|
||||
void operator*=(real_t p_val);
|
||||
|
||||
Basis operator*(real_t p_val) const;
|
||||
|
||||
int get_orthogonal_index() const; // down below
|
||||
|
||||
void set_orthogonal_index(int p_index); // down below
|
||||
|
||||
operator String() const;
|
||||
|
||||
void get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const;
|
||||
|
||||
/* create / set */
|
||||
|
||||
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz);
|
||||
|
||||
Vector3 get_column(int i) const;
|
||||
|
||||
Vector3 get_row(int i) const;
|
||||
Vector3 get_main_diagonal() const;
|
||||
|
||||
void set_row(int i, const Vector3 &p_row);
|
||||
|
||||
Basis transpose_xform(const Basis &m) const;
|
||||
|
||||
void orthonormalize();
|
||||
|
||||
Basis orthonormalized() const;
|
||||
|
||||
bool is_symmetric() const;
|
||||
|
||||
Basis diagonalize();
|
||||
|
||||
operator Quat() const;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // BASIS_H
|
||||
101
include/core/Color.hpp
Normal file
101
include/core/Color.hpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#ifndef COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
#include <gdnative/color.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct Color {
|
||||
|
||||
private:
|
||||
// static float _parse_col(const String& p_str, int p_ofs);
|
||||
public:
|
||||
union {
|
||||
|
||||
struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
};
|
||||
float components[4];
|
||||
};
|
||||
|
||||
inline bool operator==(const Color &p_color) const { return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a); }
|
||||
inline bool operator!=(const Color &p_color) const { return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a); }
|
||||
|
||||
uint32_t to_32() const;
|
||||
|
||||
uint32_t to_ARGB32() const;
|
||||
|
||||
float gray() const;
|
||||
|
||||
float get_h() const;
|
||||
|
||||
float get_s() const;
|
||||
|
||||
float get_v() const;
|
||||
|
||||
void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
|
||||
|
||||
inline float &operator[](int idx) {
|
||||
return components[idx];
|
||||
}
|
||||
inline const float &operator[](int idx) const {
|
||||
return components[idx];
|
||||
}
|
||||
|
||||
void invert();
|
||||
|
||||
void contrast();
|
||||
|
||||
Color inverted() const;
|
||||
|
||||
Color contrasted() const;
|
||||
|
||||
Color linear_interpolate(const Color &p_b, float p_t) const;
|
||||
|
||||
Color blend(const Color &p_over) const;
|
||||
|
||||
Color to_linear() const;
|
||||
|
||||
static Color hex(uint32_t p_hex);
|
||||
|
||||
static Color html(const String &p_color);
|
||||
|
||||
static bool html_is_valid(const String &p_color);
|
||||
|
||||
String to_html(bool p_alpha = true) const;
|
||||
|
||||
bool operator<(const Color &p_color) const; //used in set keys
|
||||
|
||||
operator String() const;
|
||||
|
||||
/**
|
||||
* No construct parameters, r=0, g=0, b=0. a=255
|
||||
*/
|
||||
inline Color() {
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
a = 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0
|
||||
*/
|
||||
inline Color(float p_r, float p_g, float p_b, float p_a = 1.0) {
|
||||
r = p_r;
|
||||
g = p_g;
|
||||
b = p_b;
|
||||
a = p_a;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // COLOR_H
|
||||
26
include/core/CoreTypes.hpp
Normal file
26
include/core/CoreTypes.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef CORETYPES_H
|
||||
#define CORETYPES_H
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "AABB.hpp"
|
||||
#include "Array.hpp"
|
||||
#include "Basis.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "Dictionary.hpp"
|
||||
#include "NodePath.hpp"
|
||||
#include "Plane.hpp"
|
||||
#include "PoolArrays.hpp"
|
||||
#include "Quat.hpp"
|
||||
#include "RID.hpp"
|
||||
#include "Rect2.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Transform.hpp"
|
||||
#include "Transform2D.hpp"
|
||||
#include "Variant.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include "Wrapped.hpp"
|
||||
|
||||
#endif // CORETYPES_H
|
||||
180
include/core/Defs.hpp
Normal file
180
include/core/Defs.hpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#ifndef DEFS_H
|
||||
#define DEFS_H
|
||||
|
||||
namespace godot {
|
||||
|
||||
enum class Error {
|
||||
OK,
|
||||
FAILED, ///< Generic fail error
|
||||
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
|
||||
ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet
|
||||
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
|
||||
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
|
||||
ERR_OUT_OF_MEMORY, ///< Out of memory
|
||||
ERR_FILE_NOT_FOUND,
|
||||
ERR_FILE_BAD_DRIVE,
|
||||
ERR_FILE_BAD_PATH,
|
||||
ERR_FILE_NO_PERMISSION, // (10)
|
||||
ERR_FILE_ALREADY_IN_USE,
|
||||
ERR_FILE_CANT_OPEN,
|
||||
ERR_FILE_CANT_WRITE,
|
||||
ERR_FILE_CANT_READ,
|
||||
ERR_FILE_UNRECOGNIZED, // (15)
|
||||
ERR_FILE_CORRUPT,
|
||||
ERR_FILE_MISSING_DEPENDENCIES,
|
||||
ERR_FILE_EOF,
|
||||
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
|
||||
ERR_CANT_CREATE, // (20)
|
||||
ERR_QUERY_FAILED,
|
||||
ERR_ALREADY_IN_USE,
|
||||
ERR_LOCKED, ///< resource is locked
|
||||
ERR_TIMEOUT,
|
||||
ERR_CANT_CONNECT, // (25)
|
||||
ERR_CANT_RESOLVE,
|
||||
ERR_CONNECTION_ERROR,
|
||||
ERR_CANT_AQUIRE_RESOURCE,
|
||||
ERR_CANT_FORK,
|
||||
ERR_INVALID_DATA, ///< Data passed is invalid (30)
|
||||
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
|
||||
ERR_ALREADY_EXISTS, ///< When adding, item already exists
|
||||
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist
|
||||
ERR_DATABASE_CANT_READ, ///< database is full
|
||||
ERR_DATABASE_CANT_WRITE, ///< database is full (35)
|
||||
ERR_COMPILATION_FAILED,
|
||||
ERR_METHOD_NOT_FOUND,
|
||||
ERR_LINK_FAILED,
|
||||
ERR_SCRIPT_FAILED,
|
||||
ERR_CYCLIC_LINK, // (40)
|
||||
ERR_INVALID_DECLARATION,
|
||||
ERR_DUPLICATE_SYMBOL,
|
||||
ERR_PARSE_ERROR,
|
||||
ERR_BUSY,
|
||||
ERR_SKIP, // (45)
|
||||
ERR_HELP, ///< user requested help!!
|
||||
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
|
||||
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
|
||||
ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though
|
||||
ERR_WTF = ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above
|
||||
};
|
||||
|
||||
namespace helpers {
|
||||
template <typename T, typename ValueT>
|
||||
T append_all(T appendable, ValueT value) {
|
||||
appendable.append(value);
|
||||
return appendable;
|
||||
}
|
||||
|
||||
template <typename T, typename ValueT, typename... Args>
|
||||
T append_all(T appendable, ValueT value, Args... args) {
|
||||
appendable.append(value);
|
||||
return append_all(appendable, args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T append_all(T appendable) {
|
||||
return appendable;
|
||||
}
|
||||
|
||||
template <typename KV, typename KeyT, typename ValueT>
|
||||
KV add_all(KV kv, KeyT key, ValueT value) {
|
||||
kv[key] = value;
|
||||
return kv;
|
||||
}
|
||||
|
||||
template <typename KV, typename KeyT, typename ValueT, typename... Args>
|
||||
KV add_all(KV kv, KeyT key, ValueT value, Args... args) {
|
||||
kv[key] = value;
|
||||
return add_all(kv, args...);
|
||||
}
|
||||
|
||||
template <typename KV>
|
||||
KV add_all(KV kv) {
|
||||
return kv;
|
||||
}
|
||||
} // namespace helpers
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef float real_t;
|
||||
|
||||
#define CMP_EPSILON 0.00001
|
||||
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
|
||||
#define Math_PI 3.14159265358979323846
|
||||
|
||||
#define _PLANE_EQ_DOT_EPSILON 0.999
|
||||
#define _PLANE_EQ_D_EPSILON 0.0001
|
||||
|
||||
// ERR/WARN macros
|
||||
#ifndef WARN_PRINT
|
||||
#define WARN_PRINT(msg) \
|
||||
fprintf(stdout, "ERROR: %s\n", msg); \
|
||||
fflush(stdout)
|
||||
#endif
|
||||
|
||||
#ifndef WARN_PRINTS
|
||||
#define WARN_PRINTS(msg) WARN_PRINT((msg).utf8().get_data())
|
||||
#endif
|
||||
|
||||
#ifndef ERR_PRINT
|
||||
#define ERR_PRINT(x) fprintf(stderr, "ERROR: %s\n", x)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_PRINTS
|
||||
#define ERR_PRINTS(msg) ERR_PRINT((msg).utf8().get_data())
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL
|
||||
#define ERR_FAIL() ERR_PRINT("Failed")
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_V
|
||||
#define ERR_FAIL_V(a) \
|
||||
{ \
|
||||
ERR_FAIL(); \
|
||||
return a; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_COND
|
||||
#define ERR_FAIL_COND(a) \
|
||||
do { \
|
||||
if (a) { \
|
||||
ERR_PRINT(#a); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_COND_V
|
||||
#define ERR_FAIL_COND_V(cond, ret) \
|
||||
do { \
|
||||
if (cond) { \
|
||||
ERR_PRINT(#cond); \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_INDEX
|
||||
#define ERR_FAIL_INDEX(a, b) \
|
||||
do { \
|
||||
if (a < 0 || a >= b) { \
|
||||
ERR_FAIL(); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ERR_FAIL_INDEX_V
|
||||
#define ERR_FAIL_INDEX_V(a, b, c) \
|
||||
do { \
|
||||
if (a < 0 || a >= b) { \
|
||||
ERR_FAIL(); \
|
||||
return c; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif // DEFS_H
|
||||
54
include/core/Dictionary.hpp
Normal file
54
include/core/Dictionary.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include "Variant.hpp"
|
||||
|
||||
#include "Array.hpp"
|
||||
|
||||
#include <gdnative/dictionary.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Dictionary {
|
||||
godot_dictionary _godot_dictionary;
|
||||
|
||||
public:
|
||||
Dictionary();
|
||||
Dictionary(const Dictionary &other);
|
||||
Dictionary &operator=(const Dictionary &other);
|
||||
|
||||
template <class... Args>
|
||||
static Dictionary make(Args... args) {
|
||||
return helpers::add_all(Dictionary(), args...);
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
bool empty() const;
|
||||
|
||||
void erase(const Variant &key);
|
||||
|
||||
bool has(const Variant &key) const;
|
||||
|
||||
bool has_all(const Array &keys) const;
|
||||
|
||||
uint32_t hash() const;
|
||||
|
||||
Array keys() const;
|
||||
|
||||
Variant &operator[](const Variant &key);
|
||||
|
||||
const Variant &operator[](const Variant &key) const;
|
||||
|
||||
int size() const;
|
||||
|
||||
String to_json() const;
|
||||
|
||||
Array values() const;
|
||||
|
||||
~Dictionary();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // DICTIONARY_H
|
||||
460
include/core/Godot.hpp
Normal file
460
include/core/Godot.hpp
Normal file
@@ -0,0 +1,460 @@
|
||||
#ifndef GODOT_HPP
|
||||
#define GODOT_HPP
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <gdnative_api_struct.gen.h>
|
||||
#include <nativescript/godot_nativescript.h>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "CoreTypes.hpp"
|
||||
#include "Ref.hpp"
|
||||
#include "TagDB.hpp"
|
||||
#include "Variant.hpp"
|
||||
|
||||
#include "Object.hpp"
|
||||
|
||||
#include "GodotGlobal.hpp"
|
||||
|
||||
#include <GDNativeLibrary.hpp>
|
||||
#include <NativeScript.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
T *as(const Object *obj) {
|
||||
return (obj) ? (T *)godot::nativescript_api->godot_nativescript_get_userdata(obj->_owner) : nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *get_wrapper(godot_object *obj) {
|
||||
return (T *)godot::nativescript_1_1_api->godot_nativescript_get_instance_binding_data(godot::_RegisterState::language_index, obj);
|
||||
}
|
||||
|
||||
#define GODOT_CLASS(Name, Base) \
|
||||
\
|
||||
public: \
|
||||
inline static const char *___get_type_name() { return static_cast<const char *>(#Name); } \
|
||||
enum { ___CLASS_IS_SCRIPT = 1, \
|
||||
}; \
|
||||
inline static Name *_new() { \
|
||||
godot::NativeScript *script = godot::NativeScript::_new(); \
|
||||
script->set_library(godot::get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib)); \
|
||||
script->set_class_name(#Name); \
|
||||
Name *instance = godot::as<Name>(script->new_()); \
|
||||
return instance; \
|
||||
} \
|
||||
inline static size_t ___get_id() { return typeid(Name).hash_code(); }; \
|
||||
inline static size_t ___get_base_id() { return typeid(Base).hash_code(); }; \
|
||||
inline static const char *___get_base_type_name() { return Base::___get_class_name(); } \
|
||||
inline static Object *___get_from_variant(godot::Variant a) { return (godot::Object *)godot::as<Name>(godot::Object::___get_from_variant(a)); } \
|
||||
\
|
||||
private:
|
||||
|
||||
#define GODOT_SUBCLASS(Name, Base) \
|
||||
\
|
||||
public: \
|
||||
inline static const char *___get_type_name() { return static_cast<const char *>(#Name); } \
|
||||
enum { ___CLASS_IS_SCRIPT = 1, \
|
||||
}; \
|
||||
inline static Name *_new() { \
|
||||
godot::NativeScript *script = godot::NativeScript::_new(); \
|
||||
script->set_library(godot::get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib)); \
|
||||
script->set_class_name(#Name); \
|
||||
Name *instance = godot::as<Name>(script->new_()); \
|
||||
return instance; \
|
||||
} \
|
||||
inline static size_t ___get_id() { return typeid(Name).hash_code(); }; \
|
||||
inline static size_t ___get_base_id() { return typeid(Base).hash_code(); }; \
|
||||
inline static const char *___get_base_type_name() { return #Base; } \
|
||||
inline static Object *___get_from_variant(godot::Variant a) { return (godot::Object *)godot::as<Name>(godot::Object::___get_from_variant(a)); } \
|
||||
\
|
||||
private:
|
||||
|
||||
template <class T>
|
||||
struct _ArgCast {
|
||||
static T _arg_cast(Variant a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct _ArgCast<T *> {
|
||||
static T *_arg_cast(Variant a) {
|
||||
return (T *)T::___get_from_variant(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct _ArgCast<Variant> {
|
||||
static Variant _arg_cast(Variant a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
// instance and destroy funcs
|
||||
|
||||
template <class T>
|
||||
void *_godot_class_instance_func(godot_object *p, void *method_data) {
|
||||
T *d = new T();
|
||||
d->_owner = p;
|
||||
d->_type_tag = typeid(T).hash_code();
|
||||
d->_init();
|
||||
return d;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void _godot_class_destroy_func(godot_object *p, void *method_data, void *data) {
|
||||
T *d = (T *)data;
|
||||
delete d;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void register_class() {
|
||||
godot_instance_create_func create = {};
|
||||
create.create_func = _godot_class_instance_func<T>;
|
||||
|
||||
godot_instance_destroy_func destroy = {};
|
||||
destroy.destroy_func = _godot_class_destroy_func<T>;
|
||||
|
||||
_TagDB::register_type(T::___get_id(), T::___get_base_id());
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_class(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_base_type_name(), create, destroy);
|
||||
godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, T::___get_type_name(), (const void *)typeid(T).hash_code());
|
||||
T::_register_methods();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void register_tool_class() {
|
||||
godot_instance_create_func create = {};
|
||||
create.create_func = _godot_class_instance_func<T>;
|
||||
|
||||
godot_instance_destroy_func destroy = {};
|
||||
destroy.destroy_func = _godot_class_destroy_func<T>;
|
||||
|
||||
_TagDB::register_type(T::___get_id(), T::___get_base_id());
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_tool_class(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_base_type_name(), create, destroy);
|
||||
godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, T::___get_type_name(), (const void *)typeid(T).hash_code());
|
||||
T::_register_methods();
|
||||
}
|
||||
|
||||
// method registering
|
||||
|
||||
typedef godot_variant (*__godot_wrapper_method)(godot_object *, void *, void *, int, godot_variant **);
|
||||
|
||||
template <class T, class R, class... args>
|
||||
const char *___get_method_class_name(R (T::*p)(args... a)) {
|
||||
return T::___get_type_name();
|
||||
}
|
||||
|
||||
template <class T, class R, class... args>
|
||||
const char *___get_method_class_name(R (T::*p)(args... a) const) {
|
||||
return T::___get_type_name();
|
||||
}
|
||||
|
||||
// Okay, time for some template magic.
|
||||
// Many thanks to manpat from the GDL Discord Server.
|
||||
|
||||
// This is stuff that's available in C++14 I think, but whatever.
|
||||
|
||||
template <int... I>
|
||||
struct __Sequence {};
|
||||
|
||||
template <int N, int... I>
|
||||
struct __construct_sequence {
|
||||
using type = typename __construct_sequence<N - 1, N - 1, I...>::type;
|
||||
};
|
||||
|
||||
template <int... I>
|
||||
struct __construct_sequence<0, I...> {
|
||||
using type = __Sequence<I...>;
|
||||
};
|
||||
|
||||
// Now the wrapping part.
|
||||
template <class T, class R, class... As>
|
||||
struct _WrappedMethod {
|
||||
R(T::*f)
|
||||
(As...);
|
||||
|
||||
template <int... I>
|
||||
void apply(Variant *ret, T *obj, Variant **args, __Sequence<I...>) {
|
||||
*ret = (obj->*f)(_ArgCast<As>::_arg_cast(*args[I])...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... As>
|
||||
struct _WrappedMethod<T, void, As...> {
|
||||
void (T::*f)(As...);
|
||||
|
||||
template <int... I>
|
||||
void apply(Variant *ret, T *obj, Variant **args, __Sequence<I...>) {
|
||||
(obj->*f)(_ArgCast<As>::_arg_cast(*args[I])...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class R, class... As>
|
||||
godot_variant __wrapped_method(godot_object *, void *method_data, void *user_data, int num_args, godot_variant **args) {
|
||||
godot_variant v;
|
||||
godot::api->godot_variant_new_nil(&v);
|
||||
|
||||
T *obj = (T *)user_data;
|
||||
_WrappedMethod<T, R, As...> *method = (_WrappedMethod<T, R, As...> *)method_data;
|
||||
|
||||
Variant *var = (Variant *)&v;
|
||||
Variant **arg = (Variant **)args;
|
||||
|
||||
method->apply(var, obj, arg, typename __construct_sequence<sizeof...(As)>::type{});
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T, class R, class... As>
|
||||
void *___make_wrapper_function(R (T::*f)(As...)) {
|
||||
using MethodType = _WrappedMethod<T, R, As...>;
|
||||
MethodType *p = (MethodType *)godot::api->godot_alloc(sizeof(MethodType));
|
||||
p->f = f;
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
template <class T, class R, class... As>
|
||||
__godot_wrapper_method ___get_wrapper_function(R (T::*f)(As...)) {
|
||||
return (__godot_wrapper_method)&__wrapped_method<T, R, As...>;
|
||||
}
|
||||
|
||||
template <class T, class R, class... A>
|
||||
void *___make_wrapper_function(R (T::*f)(A...) const) {
|
||||
return ___make_wrapper_function((R(T::*)(A...))f);
|
||||
}
|
||||
|
||||
template <class T, class R, class... A>
|
||||
__godot_wrapper_method ___get_wrapper_function(R (T::*f)(A...) const) {
|
||||
return ___get_wrapper_function((R(T::*)(A...))f);
|
||||
}
|
||||
|
||||
template <class M>
|
||||
void register_method(const char *name, M method_ptr, godot_method_rpc_mode rpc_type = GODOT_METHOD_RPC_MODE_DISABLED) {
|
||||
godot_instance_method method = {};
|
||||
method.method_data = ___make_wrapper_function(method_ptr);
|
||||
method.free_func = godot::api->godot_free;
|
||||
method.method = (__godot_wrapper_method)___get_wrapper_function(method_ptr);
|
||||
|
||||
godot_method_attributes attr = {};
|
||||
attr.rpc_type = rpc_type;
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_method(godot::_RegisterState::nativescript_handle, ___get_method_class_name(method_ptr), name, attr, method);
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
struct _PropertySetFunc {
|
||||
void (T::*f)(P);
|
||||
static void _wrapped_setter(godot_object *object, void *method_data, void *user_data, godot_variant *value) {
|
||||
_PropertySetFunc<T, P> *set_func = (_PropertySetFunc<T, P> *)method_data;
|
||||
T *obj = (T *)user_data;
|
||||
|
||||
Variant *v = (Variant *)value;
|
||||
|
||||
(obj->*(set_func->f))(_ArgCast<P>::_arg_cast(*v));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
struct _PropertyGetFunc {
|
||||
P(T::*f)
|
||||
();
|
||||
static godot_variant _wrapped_getter(godot_object *object, void *method_data, void *user_data) {
|
||||
_PropertyGetFunc<T, P> *get_func = (_PropertyGetFunc<T, P> *)method_data;
|
||||
T *obj = (T *)user_data;
|
||||
|
||||
godot_variant var;
|
||||
godot::api->godot_variant_new_nil(&var);
|
||||
|
||||
Variant *v = (Variant *)&var;
|
||||
|
||||
*v = (obj->*(get_func->f))();
|
||||
|
||||
return var;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
struct _PropertyDefaultSetFunc {
|
||||
P(T::*f);
|
||||
static void _wrapped_setter(godot_object *object, void *method_data, void *user_data, godot_variant *value) {
|
||||
_PropertyDefaultSetFunc<T, P> *set_func = (_PropertyDefaultSetFunc<T, P> *)method_data;
|
||||
T *obj = (T *)user_data;
|
||||
|
||||
Variant *v = (Variant *)value;
|
||||
|
||||
(obj->*(set_func->f)) = _ArgCast<P>::_arg_cast(*v);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
struct _PropertyDefaultGetFunc {
|
||||
P(T::*f);
|
||||
static godot_variant _wrapped_getter(godot_object *object, void *method_data, void *user_data) {
|
||||
_PropertyDefaultGetFunc<T, P> *get_func = (_PropertyDefaultGetFunc<T, P> *)method_data;
|
||||
T *obj = (T *)user_data;
|
||||
|
||||
godot_variant var;
|
||||
godot::api->godot_variant_new_nil(&var);
|
||||
|
||||
Variant *v = (Variant *)&var;
|
||||
|
||||
*v = (obj->*(get_func->f));
|
||||
|
||||
return var;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
void register_property(const char *name, P(T::*var), P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
|
||||
Variant def_val = default_value;
|
||||
|
||||
usage = (godot_property_usage_flags)((int)usage | GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||
|
||||
if (def_val.get_type() == Variant::OBJECT) {
|
||||
Object *o = get_wrapper<Object>(def_val.operator godot_object *());
|
||||
if (o && o->is_class("Resource")) {
|
||||
hint = (godot_property_hint)((int)hint | GODOT_PROPERTY_HINT_RESOURCE_TYPE);
|
||||
hint_string = o->get_class();
|
||||
}
|
||||
}
|
||||
|
||||
godot_string *_hint_string = (godot_string *)&hint_string;
|
||||
|
||||
godot_property_attributes attr = {};
|
||||
attr.type = def_val.get_type();
|
||||
attr.default_value = *(godot_variant *)&def_val;
|
||||
attr.hint = hint;
|
||||
attr.rset_type = rpc_mode;
|
||||
attr.usage = usage;
|
||||
attr.hint_string = *_hint_string;
|
||||
|
||||
_PropertyDefaultSetFunc<T, P> *wrapped_set = (_PropertyDefaultSetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultSetFunc<T, P>));
|
||||
wrapped_set->f = var;
|
||||
|
||||
_PropertyDefaultGetFunc<T, P> *wrapped_get = (_PropertyDefaultGetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultGetFunc<T, P>));
|
||||
wrapped_get->f = var;
|
||||
|
||||
godot_property_set_func set_func = {};
|
||||
set_func.method_data = (void *)wrapped_set;
|
||||
set_func.free_func = godot::api->godot_free;
|
||||
set_func.set_func = &_PropertyDefaultSetFunc<T, P>::_wrapped_setter;
|
||||
|
||||
godot_property_get_func get_func = {};
|
||||
get_func.method_data = (void *)wrapped_get;
|
||||
get_func.free_func = godot::api->godot_free;
|
||||
get_func.get_func = &_PropertyDefaultGetFunc<T, P>::_wrapped_getter;
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle, T::___get_type_name(), name, &attr, set_func, get_func);
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
void register_property(const char *name, void (T::*setter)(P), P (T::*getter)(), P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
|
||||
Variant def_val = default_value;
|
||||
|
||||
godot_property_attributes attr = {};
|
||||
attr.type = def_val.get_type();
|
||||
attr.default_value = *(godot_variant *)&def_val;
|
||||
attr.hint = hint;
|
||||
attr.rset_type = rpc_mode;
|
||||
attr.usage = usage;
|
||||
|
||||
_PropertySetFunc<T, P> *wrapped_set = (_PropertySetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertySetFunc<T, P>));
|
||||
wrapped_set->f = setter;
|
||||
|
||||
_PropertyGetFunc<T, P> *wrapped_get = (_PropertyGetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyGetFunc<T, P>));
|
||||
wrapped_get->f = getter;
|
||||
|
||||
godot_property_set_func set_func = {};
|
||||
set_func.method_data = (void *)wrapped_set;
|
||||
set_func.free_func = godot::api->godot_free;
|
||||
set_func.set_func = &_PropertySetFunc<T, P>::_wrapped_setter;
|
||||
|
||||
godot_property_get_func get_func = {};
|
||||
get_func.method_data = (void *)wrapped_get;
|
||||
get_func.free_func = godot::api->godot_free;
|
||||
get_func.get_func = &_PropertyGetFunc<T, P>::_wrapped_getter;
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle, T::___get_type_name(), name, &attr, set_func, get_func);
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
void register_property(const char *name, void (T::*setter)(P), P (T::*getter)() const, P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
|
||||
register_property(name, setter, (P(T::*)())getter, default_value, rpc_mode, usage, hint, hint_string);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void register_signal(String name, Dictionary args = Dictionary()) {
|
||||
godot_signal signal = {};
|
||||
signal.name = *(godot_string *)&name;
|
||||
signal.num_args = args.size();
|
||||
signal.num_default_args = 0;
|
||||
|
||||
// Need to check because malloc(0) is platform-dependent. Zero arguments will leave args to nullptr.
|
||||
if (signal.num_args != 0) {
|
||||
signal.args = (godot_signal_argument *)godot::api->godot_alloc(sizeof(godot_signal_argument) * signal.num_args);
|
||||
memset((void *)signal.args, 0, sizeof(godot_signal_argument) * signal.num_args);
|
||||
}
|
||||
|
||||
for (int i = 0; i < signal.num_args; i++) {
|
||||
// Array entry = args[i];
|
||||
// String name = entry[0];
|
||||
String name = args.keys()[i];
|
||||
godot_string *_key = (godot_string *)&name;
|
||||
godot::api->godot_string_new_copy(&signal.args[i].name, _key);
|
||||
|
||||
// if (entry.size() > 1) {
|
||||
// signal.args[i].type = entry[1];
|
||||
// }
|
||||
signal.args[i].type = args.values()[i];
|
||||
}
|
||||
|
||||
godot::nativescript_api->godot_nativescript_register_signal(godot::_RegisterState::nativescript_handle, T::___get_type_name(), &signal);
|
||||
|
||||
for (int i = 0; i < signal.num_args; i++) {
|
||||
godot::api->godot_string_destroy(&signal.args[i].name);
|
||||
}
|
||||
|
||||
if (signal.args) {
|
||||
godot::api->godot_free(signal.args);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
void register_signal(String name, Args... varargs) {
|
||||
register_signal<T>(name, Dictionary::make(varargs...));
|
||||
}
|
||||
|
||||
#ifndef GODOT_CPP_NO_OBJECT_CAST
|
||||
template <class T>
|
||||
T *Object::cast_to(const Object *obj) {
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
size_t have_tag = (size_t)godot::nativescript_1_1_api->godot_nativescript_get_type_tag(obj->_owner);
|
||||
|
||||
if (have_tag) {
|
||||
if (!godot::_TagDB::is_type_known((size_t)have_tag)) {
|
||||
have_tag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_tag) {
|
||||
have_tag = obj->_type_tag;
|
||||
}
|
||||
|
||||
if (godot::_TagDB::is_type_compatible(typeid(T).hash_code(), have_tag)) {
|
||||
return (T::___CLASS_IS_SCRIPT) ? godot::as<T>(obj) : (T *)obj;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_H
|
||||
43
include/core/GodotGlobal.hpp
Normal file
43
include/core/GodotGlobal.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef GODOT_GLOBAL_HPP
|
||||
#define GODOT_GLOBAL_HPP
|
||||
|
||||
#include "Array.hpp"
|
||||
#include "String.hpp"
|
||||
#include <gdnative_api_struct.gen.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
extern "C" const godot_gdnative_core_api_struct *api;
|
||||
extern "C" const godot_gdnative_ext_nativescript_api_struct *nativescript_api;
|
||||
extern "C" const godot_gdnative_ext_nativescript_1_1_api_struct *nativescript_1_1_api;
|
||||
|
||||
extern "C" const void *gdnlib;
|
||||
|
||||
class Godot {
|
||||
|
||||
public:
|
||||
static void print(const String &message);
|
||||
static void print_warning(const String &description, const String &function, const String &file, int line);
|
||||
static void print_error(const String &description, const String &function, const String &file, int line);
|
||||
|
||||
static void gdnative_init(godot_gdnative_init_options *o);
|
||||
static void gdnative_terminate(godot_gdnative_terminate_options *o);
|
||||
static void nativescript_init(void *handle);
|
||||
static void nativescript_terminate(void *handle);
|
||||
|
||||
static void gdnative_profiling_add_data(const char *p_signature, uint64_t p_time);
|
||||
|
||||
template <class... Args>
|
||||
static void print(const String &fmt, Args... values) {
|
||||
print(fmt.format(Array::make(values...)));
|
||||
}
|
||||
};
|
||||
|
||||
struct _RegisterState {
|
||||
static void *nativescript_handle;
|
||||
static int language_index;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif
|
||||
34
include/core/GodotProfiling.hpp
Normal file
34
include/core/GodotProfiling.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef GODOT_PROFILING_HPP
|
||||
#define GODOT_PROFILING_HPP
|
||||
|
||||
#include "OS.hpp"
|
||||
|
||||
|
||||
namespace godot {
|
||||
|
||||
class FunctionProfiling {
|
||||
char signature[1024];
|
||||
uint64_t ticks;
|
||||
|
||||
public:
|
||||
FunctionProfiling(const char *p_function, const int p_line) {
|
||||
snprintf(signature, 1024, "::%d::%s", p_line, p_function);
|
||||
ticks = OS::get_singleton()->get_ticks_usec();
|
||||
}
|
||||
~FunctionProfiling() {
|
||||
uint64_t t = OS::get_singleton()->get_ticks_usec() - ticks;
|
||||
if (t > 0) {
|
||||
Godot::gdnative_profiling_add_data(signature, t);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define GODOT_PROFILING_FUNCTION FunctionProfiling __function_profiling(__FUNCTION__, __LINE__);
|
||||
#else
|
||||
#define GODOT_PROFILING_FUNCTION
|
||||
#endif
|
||||
|
||||
#endif
|
||||
45
include/core/NodePath.hpp
Normal file
45
include/core/NodePath.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef NODEPATH_H
|
||||
#define NODEPATH_H
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
#include <gdnative/node_path.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class NodePath {
|
||||
godot_node_path _node_path;
|
||||
|
||||
public:
|
||||
NodePath();
|
||||
|
||||
NodePath(const NodePath &other);
|
||||
|
||||
NodePath(const String &from);
|
||||
|
||||
NodePath(const char *contents);
|
||||
|
||||
String get_name(const int idx) const;
|
||||
|
||||
int get_name_count() const;
|
||||
|
||||
String get_subname(const int idx) const;
|
||||
|
||||
int get_subname_count() const;
|
||||
|
||||
bool is_absolute() const;
|
||||
|
||||
bool is_empty() const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
void operator=(const NodePath &other);
|
||||
|
||||
bool operator==(const NodePath &other);
|
||||
|
||||
~NodePath();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // NODEPATH_H
|
||||
68
include/core/Plane.hpp
Normal file
68
include/core/Plane.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef PLANE_H
|
||||
#define PLANE_H
|
||||
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace godot {
|
||||
|
||||
enum ClockDirection {
|
||||
|
||||
CLOCKWISE,
|
||||
COUNTERCLOCKWISE
|
||||
};
|
||||
|
||||
class Plane {
|
||||
public:
|
||||
Vector3 normal;
|
||||
real_t d;
|
||||
|
||||
void set_normal(const Vector3 &p_normal);
|
||||
|
||||
inline Vector3 get_normal() const { return normal; } ///Point is coplanar, CMP_EPSILON for precision
|
||||
|
||||
void normalize();
|
||||
|
||||
Plane normalized() const;
|
||||
|
||||
/* Plane-Point operations */
|
||||
|
||||
inline Vector3 center() const { return normal * d; }
|
||||
Vector3 get_any_point() const;
|
||||
Vector3 get_any_perpendicular_normal() const;
|
||||
|
||||
bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
|
||||
real_t distance_to(const Vector3 &p_point) const;
|
||||
bool has_point(const Vector3 &p_point, real_t _epsilon = CMP_EPSILON) const;
|
||||
|
||||
/* intersections */
|
||||
|
||||
bool intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result = 0) const;
|
||||
bool intersects_ray(Vector3 p_from, Vector3 p_dir, Vector3 *p_intersection) const;
|
||||
bool intersects_segment(Vector3 p_begin, Vector3 p_end, Vector3 *p_intersection) const;
|
||||
|
||||
Vector3 project(const Vector3 &p_point) const;
|
||||
|
||||
/* misc */
|
||||
|
||||
inline Plane operator-() const { return Plane(-normal, -d); }
|
||||
bool is_almost_like(const Plane &p_plane) const;
|
||||
|
||||
bool operator==(const Plane &p_plane) const;
|
||||
bool operator!=(const Plane &p_plane) const;
|
||||
operator String() const;
|
||||
|
||||
inline Plane() { d = 0; }
|
||||
inline Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
|
||||
normal(p_a, p_b, p_c),
|
||||
d(p_d) {}
|
||||
|
||||
Plane(const Vector3 &p_normal, real_t p_d);
|
||||
Plane(const Vector3 &p_point, const Vector3 &p_normal);
|
||||
Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE);
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // PLANE_H
|
||||
700
include/core/PoolArrays.hpp
Normal file
700
include/core/PoolArrays.hpp
Normal file
@@ -0,0 +1,700 @@
|
||||
#ifndef POOLARRAYS_H
|
||||
#define POOLARRAYS_H
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "GodotGlobal.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include <gdnative/pool_arrays.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Array;
|
||||
|
||||
class PoolByteArray {
|
||||
godot_pool_byte_array _godot_array;
|
||||
|
||||
public:
|
||||
class Read {
|
||||
|
||||
friend class PoolByteArray;
|
||||
godot_pool_byte_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_byte_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_byte_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const uint8_t *ptr() const {
|
||||
return godot::api->godot_pool_byte_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const uint8_t &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_byte_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolByteArray;
|
||||
godot_pool_byte_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_byte_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_byte_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline uint8_t *ptr() const {
|
||||
return godot::api->godot_pool_byte_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline uint8_t &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_byte_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolByteArray();
|
||||
PoolByteArray(const PoolByteArray &p_other);
|
||||
PoolByteArray &operator=(const PoolByteArray &p_other);
|
||||
|
||||
PoolByteArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const uint8_t data);
|
||||
|
||||
void append_array(const PoolByteArray &array);
|
||||
|
||||
int insert(const int idx, const uint8_t data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const uint8_t data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const uint8_t data);
|
||||
|
||||
uint8_t operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolByteArray();
|
||||
};
|
||||
|
||||
class PoolIntArray {
|
||||
godot_pool_int_array _godot_array;
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolIntArray;
|
||||
godot_pool_int_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_int_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_int_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const int *ptr() const {
|
||||
return godot::api->godot_pool_int_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const int &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_int_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolIntArray;
|
||||
godot_pool_int_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_int_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_int_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline int *ptr() const {
|
||||
return godot::api->godot_pool_int_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline int &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_int_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolIntArray();
|
||||
PoolIntArray(const PoolIntArray &p_other);
|
||||
PoolIntArray &operator=(const PoolIntArray &p_other);
|
||||
|
||||
PoolIntArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const int data);
|
||||
|
||||
void append_array(const PoolIntArray &array);
|
||||
|
||||
int insert(const int idx, const int data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const int data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const int data);
|
||||
|
||||
int operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolIntArray();
|
||||
};
|
||||
|
||||
class PoolRealArray {
|
||||
godot_pool_real_array _godot_array;
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolRealArray;
|
||||
godot_pool_real_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_real_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_real_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const real_t *ptr() const {
|
||||
return godot::api->godot_pool_real_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const real_t &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_real_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolRealArray;
|
||||
godot_pool_real_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_real_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_real_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline real_t *ptr() const {
|
||||
return godot::api->godot_pool_real_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline real_t &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_real_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolRealArray();
|
||||
PoolRealArray(const PoolRealArray &p_other);
|
||||
PoolRealArray &operator=(const PoolRealArray &p_other);
|
||||
|
||||
PoolRealArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const real_t data);
|
||||
|
||||
void append_array(const PoolRealArray &array);
|
||||
|
||||
int insert(const int idx, const real_t data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const real_t data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const real_t data);
|
||||
|
||||
real_t operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolRealArray();
|
||||
};
|
||||
|
||||
class PoolStringArray {
|
||||
godot_pool_string_array _godot_array;
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolStringArray;
|
||||
godot_pool_string_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_string_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_string_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const String *ptr() const {
|
||||
return (const String *)godot::api->godot_pool_string_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const String &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_string_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolStringArray;
|
||||
godot_pool_string_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_string_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_string_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline String *ptr() const {
|
||||
return (String *)godot::api->godot_pool_string_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline String &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_string_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolStringArray();
|
||||
PoolStringArray(const PoolStringArray &p_other);
|
||||
PoolStringArray &operator=(const PoolStringArray &p_other);
|
||||
|
||||
PoolStringArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const String &data);
|
||||
|
||||
void append_array(const PoolStringArray &array);
|
||||
|
||||
int insert(const int idx, const String &data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const String &data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const String &data);
|
||||
|
||||
const String operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolStringArray();
|
||||
};
|
||||
|
||||
class PoolVector2Array {
|
||||
godot_pool_vector2_array _godot_array;
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolVector2Array;
|
||||
godot_pool_vector2_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_vector2_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_vector2_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const Vector2 *ptr() const {
|
||||
return (const Vector2 *)godot::api->godot_pool_vector2_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const Vector2 &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_vector2_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolVector2Array;
|
||||
godot_pool_vector2_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_vector2_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_vector2_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline Vector2 *ptr() const {
|
||||
return (Vector2 *)godot::api->godot_pool_vector2_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline Vector2 &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_vector2_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolVector2Array();
|
||||
PoolVector2Array(const PoolVector2Array &p_other);
|
||||
PoolVector2Array &operator=(const PoolVector2Array &p_other);
|
||||
|
||||
PoolVector2Array(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const Vector2 &data);
|
||||
|
||||
void append_array(const PoolVector2Array &array);
|
||||
|
||||
int insert(const int idx, const Vector2 &data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const Vector2 &data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const Vector2 &data);
|
||||
|
||||
const Vector2 operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolVector2Array();
|
||||
};
|
||||
|
||||
class PoolVector3Array {
|
||||
godot_pool_vector3_array _godot_array;
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolVector3Array;
|
||||
godot_pool_vector3_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_vector3_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_vector3_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const Vector3 *ptr() const {
|
||||
return (const Vector3 *)godot::api->godot_pool_vector3_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const Vector3 &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_vector3_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolVector3Array;
|
||||
godot_pool_vector3_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_vector3_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_vector3_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline Vector3 *ptr() const {
|
||||
return (Vector3 *)godot::api->godot_pool_vector3_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline Vector3 &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_vector3_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolVector3Array();
|
||||
PoolVector3Array(const PoolVector3Array &p_other);
|
||||
PoolVector3Array &operator=(const PoolVector3Array &p_other);
|
||||
|
||||
PoolVector3Array(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const Vector3 &data);
|
||||
|
||||
void append_array(const PoolVector3Array &array);
|
||||
|
||||
int insert(const int idx, const Vector3 &data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const Vector3 &data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const Vector3 &data);
|
||||
|
||||
const Vector3 operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolVector3Array();
|
||||
};
|
||||
|
||||
class PoolColorArray {
|
||||
godot_pool_color_array _godot_array;
|
||||
|
||||
public:
|
||||
class Read {
|
||||
friend class PoolColorArray;
|
||||
godot_pool_color_array_read_access *_read_access;
|
||||
|
||||
public:
|
||||
inline Read() {
|
||||
_read_access = nullptr;
|
||||
}
|
||||
|
||||
inline Read(const Read &p_other) {
|
||||
_read_access = godot::api->godot_pool_color_array_read_access_copy(p_other._read_access);
|
||||
}
|
||||
|
||||
inline ~Read() {
|
||||
godot::api->godot_pool_color_array_read_access_destroy(_read_access);
|
||||
}
|
||||
|
||||
inline const Color *ptr() const {
|
||||
return (const Color *)godot::api->godot_pool_color_array_read_access_ptr(_read_access);
|
||||
}
|
||||
|
||||
inline const Color &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Read &p_other) {
|
||||
godot::api->godot_pool_color_array_read_access_operator_assign(_read_access, p_other._read_access);
|
||||
}
|
||||
};
|
||||
|
||||
class Write {
|
||||
friend class PoolColorArray;
|
||||
godot_pool_color_array_write_access *_write_access;
|
||||
|
||||
public:
|
||||
inline Write() {
|
||||
_write_access = nullptr;
|
||||
}
|
||||
|
||||
inline Write(const Write &p_other) {
|
||||
_write_access = godot::api->godot_pool_color_array_write_access_copy(p_other._write_access);
|
||||
}
|
||||
|
||||
inline ~Write() {
|
||||
godot::api->godot_pool_color_array_write_access_destroy(_write_access);
|
||||
}
|
||||
|
||||
inline Color *ptr() const {
|
||||
return (Color *)godot::api->godot_pool_color_array_write_access_ptr(_write_access);
|
||||
}
|
||||
|
||||
inline Color &operator[](int p_idx) const {
|
||||
return ptr()[p_idx];
|
||||
}
|
||||
|
||||
inline void operator=(const Write &p_other) {
|
||||
godot::api->godot_pool_color_array_write_access_operator_assign(_write_access, p_other._write_access);
|
||||
}
|
||||
};
|
||||
|
||||
PoolColorArray();
|
||||
PoolColorArray(const PoolColorArray &p_other);
|
||||
PoolColorArray &operator=(const PoolColorArray &p_other);
|
||||
|
||||
PoolColorArray(const Array &array);
|
||||
|
||||
Read read() const;
|
||||
|
||||
Write write();
|
||||
|
||||
void append(const Color &data);
|
||||
|
||||
void append_array(const PoolColorArray &array);
|
||||
|
||||
int insert(const int idx, const Color &data);
|
||||
|
||||
void invert();
|
||||
|
||||
void push_back(const Color &data);
|
||||
|
||||
void remove(const int idx);
|
||||
|
||||
void resize(const int size);
|
||||
|
||||
void set(const int idx, const Color &data);
|
||||
|
||||
const Color operator[](const int idx);
|
||||
|
||||
int size() const;
|
||||
|
||||
~PoolColorArray();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // POOLARRAYS_H
|
||||
89
include/core/Quat.hpp
Normal file
89
include/core/Quat.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef QUAT_H
|
||||
#define QUAT_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Vector3.hpp"
|
||||
|
||||
// #include "Basis.h"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Quat {
|
||||
public:
|
||||
real_t x, y, z, w;
|
||||
|
||||
real_t length_squared() const;
|
||||
real_t length() const;
|
||||
|
||||
void normalize();
|
||||
|
||||
Quat normalized() const;
|
||||
|
||||
Quat inverse() const;
|
||||
|
||||
void set_euler_xyz(const Vector3 &p_euler);
|
||||
Vector3 get_euler_xyz() const;
|
||||
void set_euler_yxz(const Vector3 &p_euler);
|
||||
Vector3 get_euler_yxz() const;
|
||||
|
||||
inline void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }
|
||||
inline Vector3 get_euler() const { return get_euler_yxz(); }
|
||||
|
||||
real_t dot(const Quat &q) const;
|
||||
|
||||
Quat slerp(const Quat &q, const real_t &t) const;
|
||||
|
||||
Quat slerpni(const Quat &q, const real_t &t) const;
|
||||
|
||||
Quat cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const;
|
||||
|
||||
void get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const;
|
||||
|
||||
void operator*=(const Quat &q);
|
||||
Quat operator*(const Quat &q) const;
|
||||
|
||||
Quat operator*(const Vector3 &v) const;
|
||||
|
||||
Vector3 xform(const Vector3 &v) const;
|
||||
|
||||
void operator+=(const Quat &q);
|
||||
void operator-=(const Quat &q);
|
||||
void operator*=(const real_t &s);
|
||||
void operator/=(const real_t &s);
|
||||
Quat operator+(const Quat &q2) const;
|
||||
Quat operator-(const Quat &q2) const;
|
||||
Quat operator-() const;
|
||||
Quat operator*(const real_t &s) const;
|
||||
Quat operator/(const real_t &s) const;
|
||||
|
||||
bool operator==(const Quat &p_quat) const;
|
||||
bool operator!=(const Quat &p_quat) const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline void set(real_t p_x, real_t p_y, real_t p_z, real_t p_w) {
|
||||
x = p_x;
|
||||
y = p_y;
|
||||
z = p_z;
|
||||
w = p_w;
|
||||
}
|
||||
inline Quat(real_t p_x, real_t p_y, real_t p_z, real_t p_w) {
|
||||
x = p_x;
|
||||
y = p_y;
|
||||
z = p_z;
|
||||
w = p_w;
|
||||
}
|
||||
Quat(const Vector3 &axis, const real_t &angle);
|
||||
|
||||
Quat(const Vector3 &v0, const Vector3 &v1);
|
||||
|
||||
inline Quat() {
|
||||
x = y = z = 0;
|
||||
w = 1;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // QUAT_H
|
||||
35
include/core/RID.hpp
Normal file
35
include/core/RID.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef RID_H
|
||||
#define RID_H
|
||||
|
||||
#include <gdnative/rid.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Object;
|
||||
|
||||
class RID {
|
||||
godot_rid _godot_rid;
|
||||
|
||||
public:
|
||||
RID();
|
||||
|
||||
RID(Object *p);
|
||||
|
||||
int32_t get_rid() const;
|
||||
|
||||
inline bool is_valid() const {
|
||||
// is_valid() is not available in the C API...
|
||||
return *this != RID();
|
||||
}
|
||||
|
||||
bool operator==(const RID &p_other) const;
|
||||
bool operator!=(const RID &p_other) const;
|
||||
bool operator<(const RID &p_other) const;
|
||||
bool operator>(const RID &p_other) const;
|
||||
bool operator<=(const RID &p_other) const;
|
||||
bool operator>=(const RID &p_other) const;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // RID_H
|
||||
135
include/core/Rect2.hpp
Normal file
135
include/core/Rect2.hpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#ifndef RECT2_H
|
||||
#define RECT2_H
|
||||
|
||||
#include "Vector2.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
typedef Vector2 Size2;
|
||||
typedef Vector2 Point2;
|
||||
|
||||
struct Transform2D;
|
||||
|
||||
struct Rect2 {
|
||||
|
||||
Point2 position;
|
||||
Size2 size;
|
||||
|
||||
inline const Vector2 &get_position() const { return position; }
|
||||
inline void set_position(const Vector2 &p_position) { position = p_position; }
|
||||
inline const Vector2 &get_size() const { return size; }
|
||||
inline void set_size(const Vector2 &p_size) { size = p_size; }
|
||||
|
||||
inline real_t get_area() const { return size.width * size.height; }
|
||||
|
||||
inline bool intersects(const Rect2 &p_rect) const {
|
||||
if (position.x >= (p_rect.position.x + p_rect.size.width))
|
||||
return false;
|
||||
if ((position.x + size.width) <= p_rect.position.x)
|
||||
return false;
|
||||
if (position.y >= (p_rect.position.y + p_rect.size.height))
|
||||
return false;
|
||||
if ((position.y + size.height) <= p_rect.position.y)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
real_t distance_to(const Vector2 &p_point) const;
|
||||
|
||||
bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const;
|
||||
|
||||
bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_position = nullptr, Point2 *r_normal = nullptr) const;
|
||||
|
||||
inline bool encloses(const Rect2 &p_rect) const {
|
||||
|
||||
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
|
||||
((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) &&
|
||||
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
|
||||
}
|
||||
|
||||
inline bool has_no_area() const {
|
||||
|
||||
return (size.x <= 0 || size.y <= 0);
|
||||
}
|
||||
Rect2 clip(const Rect2 &p_rect) const;
|
||||
|
||||
Rect2 merge(const Rect2 &p_rect) const;
|
||||
|
||||
inline bool has_point(const Point2 &p_point) const {
|
||||
if (p_point.x < position.x)
|
||||
return false;
|
||||
if (p_point.y < position.y)
|
||||
return false;
|
||||
|
||||
if (p_point.x >= (position.x + size.x))
|
||||
return false;
|
||||
if (p_point.y >= (position.y + size.y))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool no_area() const { return (size.width <= 0 || size.height <= 0); }
|
||||
|
||||
inline bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
|
||||
inline bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
|
||||
|
||||
inline Rect2 grow(real_t p_by) const {
|
||||
|
||||
Rect2 g = *this;
|
||||
g.position.x -= p_by;
|
||||
g.position.y -= p_by;
|
||||
g.size.width += p_by * 2;
|
||||
g.size.height += p_by * 2;
|
||||
return g;
|
||||
}
|
||||
|
||||
inline Rect2 expand(const Vector2 &p_vector) const {
|
||||
|
||||
Rect2 r = *this;
|
||||
r.expand_to(p_vector);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void expand_to(const Vector2 &p_vector) { //in place function for speed
|
||||
|
||||
Vector2 begin = position;
|
||||
Vector2 end = position + size;
|
||||
|
||||
if (p_vector.x < begin.x)
|
||||
begin.x = p_vector.x;
|
||||
if (p_vector.y < begin.y)
|
||||
begin.y = p_vector.y;
|
||||
|
||||
if (p_vector.x > end.x)
|
||||
end.x = p_vector.x;
|
||||
if (p_vector.y > end.y)
|
||||
end.y = p_vector.y;
|
||||
|
||||
position = begin;
|
||||
size = end - begin;
|
||||
}
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline Rect2() {}
|
||||
inline Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) {
|
||||
position = Point2(p_x, p_y);
|
||||
size = Size2(p_width, p_height);
|
||||
}
|
||||
inline Rect2(const Point2 &p_position, const Size2 &p_size) {
|
||||
position = p_position;
|
||||
size = p_size;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // RECT2_H
|
||||
214
include/core/Ref.hpp
Normal file
214
include/core/Ref.hpp
Normal file
@@ -0,0 +1,214 @@
|
||||
#ifndef REF_H
|
||||
#define REF_H
|
||||
|
||||
#include "GodotGlobal.hpp"
|
||||
#include "Reference.hpp"
|
||||
#include "Variant.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
// Replicates Godot's Ref<T> behavior
|
||||
// Rewritten from f5234e70be7dec4930c2d5a0e829ff480d044b1d.
|
||||
template <class T>
|
||||
class Ref {
|
||||
|
||||
T *reference = nullptr;
|
||||
|
||||
void ref(const Ref &p_from) {
|
||||
|
||||
if (p_from.reference == reference)
|
||||
return;
|
||||
|
||||
unref();
|
||||
|
||||
reference = p_from.reference;
|
||||
if (reference)
|
||||
reference->reference();
|
||||
}
|
||||
|
||||
void ref_pointer(T *p_ref) {
|
||||
|
||||
ERR_FAIL_COND(!p_ref);
|
||||
|
||||
if (p_ref->init_ref())
|
||||
reference = p_ref;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool operator<(const Ref<T> &p_r) const {
|
||||
|
||||
return reference < p_r.reference;
|
||||
}
|
||||
inline bool operator==(const Ref<T> &p_r) const {
|
||||
|
||||
return reference == p_r.reference;
|
||||
}
|
||||
inline bool operator!=(const Ref<T> &p_r) const {
|
||||
|
||||
return reference != p_r.reference;
|
||||
}
|
||||
|
||||
inline T *operator->() {
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline T *operator*() {
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline const T *operator->() const {
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline const T *ptr() const {
|
||||
|
||||
return reference;
|
||||
}
|
||||
inline T *ptr() {
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline const T *operator*() const {
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
operator Variant() const {
|
||||
// Note: the C API handles the cases where the object is a Reference,
|
||||
// so the Variant will be correctly constructed with a RefPtr engine-side
|
||||
return Variant((Object *)reference);
|
||||
}
|
||||
|
||||
void operator=(const Ref &p_from) {
|
||||
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
void operator=(const Ref<T_Other> &p_from) {
|
||||
|
||||
// TODO We need a safe cast
|
||||
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
|
||||
if (!refb) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
Ref r;
|
||||
//r.reference = Object::cast_to<T>(refb);
|
||||
r.reference = (T *)refb;
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
void operator=(const Variant &p_variant) {
|
||||
|
||||
// TODO We need a safe cast
|
||||
Reference *refb = (Reference *)T::___get_from_variant(p_variant);
|
||||
if (!refb) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
Ref r;
|
||||
// TODO We need a safe cast
|
||||
//r.reference = Object::cast_to<T>(refb);
|
||||
r.reference = (T *)refb;
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
Ref(const Ref &p_from) {
|
||||
|
||||
reference = nullptr;
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
Ref(const Ref<T_Other> &p_from) {
|
||||
|
||||
reference = nullptr;
|
||||
// TODO We need a safe cast
|
||||
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
|
||||
if (!refb) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
Ref r;
|
||||
// TODO We need a safe cast
|
||||
//r.reference = Object::cast_to<T>(refb);
|
||||
r.reference = (T *)refb;
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
Ref(T *p_reference) {
|
||||
|
||||
if (p_reference)
|
||||
ref_pointer(p_reference);
|
||||
else
|
||||
reference = nullptr;
|
||||
}
|
||||
|
||||
Ref(const Variant &p_variant) {
|
||||
|
||||
reference = nullptr;
|
||||
// TODO We need a safe cast
|
||||
Reference *refb = (Reference *)T::___get_from_variant(p_variant);
|
||||
if (!refb) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
Ref r;
|
||||
// TODO We need a safe cast
|
||||
//r.reference = Object::cast_to<T>(refb);
|
||||
r.reference = (T *)refb;
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
inline bool is_valid() const { return reference != nullptr; }
|
||||
inline bool is_null() const { return reference == nullptr; }
|
||||
|
||||
void unref() {
|
||||
//TODO this should be moved to mutexes, since this engine does not really
|
||||
// do a lot of referencing on references and stuff
|
||||
// mutexes will avoid more crashes?
|
||||
|
||||
if (reference && reference->unreference()) {
|
||||
|
||||
//memdelete(reference);
|
||||
reference->free();
|
||||
}
|
||||
reference = nullptr;
|
||||
}
|
||||
|
||||
void instance() {
|
||||
//ref(memnew(T));
|
||||
ref(T::_new());
|
||||
}
|
||||
|
||||
Ref() {
|
||||
|
||||
reference = nullptr;
|
||||
}
|
||||
|
||||
~Ref() {
|
||||
|
||||
unref();
|
||||
}
|
||||
|
||||
// Used exclusively in the bindings to recreate the Ref Godot encapsulates in return values,
|
||||
// without adding to the refcount.
|
||||
inline static Ref<T> __internal_constructor(Object *obj) {
|
||||
Ref<T> r;
|
||||
r.reference = (T *)obj;
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif
|
||||
142
include/core/String.hpp
Normal file
142
include/core/String.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
#include <gdnative/string.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class NodePath;
|
||||
class Variant;
|
||||
class PoolByteArray;
|
||||
class PoolIntArray;
|
||||
class PoolRealArray;
|
||||
class PoolStringArray;
|
||||
class String;
|
||||
|
||||
class CharString {
|
||||
|
||||
friend class String;
|
||||
|
||||
godot_char_string _char_string;
|
||||
|
||||
public:
|
||||
~CharString();
|
||||
|
||||
int length() const;
|
||||
const char *get_data() const;
|
||||
};
|
||||
|
||||
class String {
|
||||
godot_string _godot_string;
|
||||
|
||||
public:
|
||||
String();
|
||||
String(const char *contents);
|
||||
String(const wchar_t *contents);
|
||||
String(const wchar_t c);
|
||||
String(const String &other);
|
||||
|
||||
~String();
|
||||
|
||||
static String num(double p_num, int p_decimals = -1);
|
||||
static String num_scientific(double p_num);
|
||||
static String num_real(double p_num);
|
||||
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
|
||||
static String chr(godot_char_type p_char);
|
||||
static String md5(const uint8_t *p_md5);
|
||||
static String hex_encode_buffer(const uint8_t *p_buffer, int p_len);
|
||||
|
||||
wchar_t &operator[](const int idx);
|
||||
wchar_t operator[](const int idx) const;
|
||||
|
||||
void operator=(const String &s);
|
||||
bool operator==(const String &s) const;
|
||||
bool operator!=(const String &s) const;
|
||||
String operator+(const String &s) const;
|
||||
void operator+=(const String &s);
|
||||
void operator+=(const wchar_t c);
|
||||
bool operator<(const String &s) const;
|
||||
bool operator<=(const String &s) const;
|
||||
bool operator>(const String &s) const;
|
||||
bool operator>=(const String &s) const;
|
||||
|
||||
operator NodePath() const;
|
||||
|
||||
int length() const;
|
||||
const wchar_t *unicode_str() const;
|
||||
char *alloc_c_string() const;
|
||||
CharString utf8() const;
|
||||
CharString ascii(bool p_extended = false) const;
|
||||
|
||||
bool begins_with(String &s) const;
|
||||
bool begins_with_char_array(const char *p_char_array) const;
|
||||
PoolStringArray bigrams() const;
|
||||
String c_escape() const;
|
||||
String c_unescape() const;
|
||||
String capitalize() const;
|
||||
bool empty() const;
|
||||
bool ends_with(String &text) const;
|
||||
void erase(int position, int chars);
|
||||
int find(String what, int from = 0) const;
|
||||
int find_last(String what) const;
|
||||
int findn(String what, int from = 0) const;
|
||||
String format(Variant values) const;
|
||||
String format(Variant values, String placeholder) const;
|
||||
String get_base_dir() const;
|
||||
String get_basename() const;
|
||||
String get_extension() const;
|
||||
String get_file() const;
|
||||
int hash() const;
|
||||
int hex_to_int() const;
|
||||
String insert(int position, String what) const;
|
||||
bool is_abs_path() const;
|
||||
bool is_rel_path() const;
|
||||
bool is_subsequence_of(String text) const;
|
||||
bool is_subsequence_ofi(String text) const;
|
||||
bool is_valid_float() const;
|
||||
bool is_valid_html_color() const;
|
||||
bool is_valid_identifier() const;
|
||||
bool is_valid_integer() const;
|
||||
bool is_valid_ip_address() const;
|
||||
String json_escape() const;
|
||||
String left(int position) const;
|
||||
bool match(String expr) const;
|
||||
bool matchn(String expr) const;
|
||||
PoolByteArray md5_buffer() const;
|
||||
String md5_text() const;
|
||||
int ord_at(int at) const;
|
||||
String pad_decimals(int digits) const;
|
||||
String pad_zeros(int digits) const;
|
||||
String percent_decode() const;
|
||||
String percent_encode() const;
|
||||
String plus_file(String file) const;
|
||||
String replace(String what, String forwhat) const;
|
||||
String replacen(String what, String forwhat) const;
|
||||
int rfind(String what, int from = -1) const;
|
||||
int rfindn(String what, int from = -1) const;
|
||||
String right(int position) const;
|
||||
PoolByteArray sha256_buffer() const;
|
||||
String sha256_text() const;
|
||||
float similarity(String text) const;
|
||||
PoolStringArray split(String divisor, bool allow_empty = true) const;
|
||||
PoolIntArray split_ints(String divisor, bool allow_empty = true) const;
|
||||
PoolRealArray split_floats(String divisor, bool allow_empty = true) const;
|
||||
String strip_edges(bool left = true, bool right = true) const;
|
||||
String substr(int from, int len) const;
|
||||
float to_float() const;
|
||||
int64_t to_int() const;
|
||||
String to_lower() const;
|
||||
String to_upper() const;
|
||||
String xml_escape() const;
|
||||
String xml_unescape() const;
|
||||
signed char casecmp_to(String p_str) const;
|
||||
signed char nocasecmp_to(String p_str) const;
|
||||
signed char naturalnocasecmp_to(String p_str) const;
|
||||
};
|
||||
|
||||
String operator+(const char *a, const String &b);
|
||||
String operator+(const wchar_t *a, const String &b);
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // STRING_H
|
||||
19
include/core/TagDB.hpp
Normal file
19
include/core/TagDB.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef TAGDB_HPP
|
||||
#define TAGDB_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace _TagDB {
|
||||
|
||||
void register_type(size_t type_tag, size_t base_type_tag);
|
||||
bool is_type_known(size_t type_tag);
|
||||
void register_global_type(const char *name, size_t type_tag, size_t base_type_tag);
|
||||
bool is_type_compatible(size_t type_tag, size_t base_type_tag);
|
||||
|
||||
} // namespace _TagDB
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // TAGDB_HPP
|
||||
79
include/core/Transform.hpp
Normal file
79
include/core/Transform.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#ifndef TRANSFORM_H
|
||||
#define TRANSFORM_H
|
||||
|
||||
#include "Basis.hpp"
|
||||
|
||||
#include "AABB.hpp"
|
||||
#include "Plane.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Transform {
|
||||
public:
|
||||
Basis basis;
|
||||
Vector3 origin;
|
||||
|
||||
void invert();
|
||||
Transform inverse() const;
|
||||
|
||||
void affine_invert();
|
||||
Transform affine_inverse() const;
|
||||
|
||||
Transform rotated(const Vector3 &p_axis, real_t p_phi) const;
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_phi);
|
||||
void rotate_basis(const Vector3 &p_axis, real_t p_phi);
|
||||
|
||||
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up);
|
||||
Transform looking_at(const Vector3 &p_target, const Vector3 &p_up) const;
|
||||
|
||||
void scale(const Vector3 &p_scale);
|
||||
Transform scaled(const Vector3 &p_scale) const;
|
||||
void scale_basis(const Vector3 &p_scale);
|
||||
void translate(real_t p_tx, real_t p_ty, real_t p_tz);
|
||||
void translate(const Vector3 &p_translation);
|
||||
Transform translated(const Vector3 &p_translation) const;
|
||||
|
||||
inline const Basis &get_basis() const { return basis; }
|
||||
inline void set_basis(const Basis &p_basis) { basis = p_basis; }
|
||||
|
||||
inline const Vector3 &get_origin() const { return origin; }
|
||||
inline void set_origin(const Vector3 &p_origin) { origin = p_origin; }
|
||||
|
||||
void orthonormalize();
|
||||
Transform orthonormalized() const;
|
||||
|
||||
bool operator==(const Transform &p_transform) const;
|
||||
bool operator!=(const Transform &p_transform) const;
|
||||
|
||||
Vector3 xform(const Vector3 &p_vector) const;
|
||||
Vector3 xform_inv(const Vector3 &p_vector) const;
|
||||
|
||||
Plane xform(const Plane &p_plane) const;
|
||||
Plane xform_inv(const Plane &p_plane) const;
|
||||
|
||||
AABB xform(const AABB &p_aabb) const;
|
||||
AABB xform_inv(const AABB &p_aabb) const;
|
||||
|
||||
void operator*=(const Transform &p_transform);
|
||||
Transform operator*(const Transform &p_transform) const;
|
||||
|
||||
Transform interpolate_with(const Transform &p_transform, real_t p_c) const;
|
||||
|
||||
Transform inverse_xform(const Transform &t) const;
|
||||
|
||||
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz);
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) {
|
||||
set(xx, xy, xz, yx, yy, yz, zx, zy, zz, tx, ty, tz);
|
||||
}
|
||||
|
||||
Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3());
|
||||
inline Transform() {}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // TRANSFORM_H
|
||||
102
include/core/Transform2D.hpp
Normal file
102
include/core/Transform2D.hpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#ifndef TRANSFORM2D_H
|
||||
#define TRANSFORM2D_H
|
||||
|
||||
#include "Vector2.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
typedef Vector2 Size2;
|
||||
|
||||
struct Rect2;
|
||||
|
||||
struct Transform2D {
|
||||
// Warning #1: basis of Transform2D is stored differently from Basis. In terms of elements array, the basis matrix looks like "on paper":
|
||||
// M = (elements[0][0] elements[1][0])
|
||||
// (elements[0][1] elements[1][1])
|
||||
// This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as elements[i].
|
||||
// Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to elements[1][0] here.
|
||||
// This requires additional care when working with explicit indices.
|
||||
// See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading.
|
||||
|
||||
// Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down,
|
||||
// and angle is measure from +X to +Y in a clockwise-fashion.
|
||||
|
||||
Vector2 elements[3];
|
||||
|
||||
inline real_t tdotx(const Vector2 &v) const { return elements[0][0] * v.x + elements[1][0] * v.y; }
|
||||
inline real_t tdoty(const Vector2 &v) const { return elements[0][1] * v.x + elements[1][1] * v.y; }
|
||||
|
||||
inline const Vector2 &operator[](int p_idx) const { return elements[p_idx]; }
|
||||
inline Vector2 &operator[](int p_idx) { return elements[p_idx]; }
|
||||
|
||||
inline Vector2 get_axis(int p_axis) const {
|
||||
ERR_FAIL_INDEX_V(p_axis, 3, Vector2());
|
||||
return elements[p_axis];
|
||||
}
|
||||
inline void set_axis(int p_axis, const Vector2 &p_vec) {
|
||||
ERR_FAIL_INDEX(p_axis, 3);
|
||||
elements[p_axis] = p_vec;
|
||||
}
|
||||
|
||||
void invert();
|
||||
Transform2D inverse() const;
|
||||
|
||||
void affine_invert();
|
||||
Transform2D affine_inverse() const;
|
||||
|
||||
void set_rotation(real_t p_phi);
|
||||
real_t get_rotation() const;
|
||||
void set_rotation_and_scale(real_t p_phi, const Size2 &p_scale);
|
||||
void rotate(real_t p_phi);
|
||||
|
||||
void scale(const Size2 &p_scale);
|
||||
void scale_basis(const Size2 &p_scale);
|
||||
void translate(real_t p_tx, real_t p_ty);
|
||||
void translate(const Vector2 &p_translation);
|
||||
|
||||
real_t basis_determinant() const;
|
||||
|
||||
Size2 get_scale() const;
|
||||
|
||||
inline const Vector2 &get_origin() const { return elements[2]; }
|
||||
inline void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; }
|
||||
|
||||
Transform2D scaled(const Size2 &p_scale) const;
|
||||
Transform2D basis_scaled(const Size2 &p_scale) const;
|
||||
Transform2D translated(const Vector2 &p_offset) const;
|
||||
Transform2D rotated(real_t p_phi) const;
|
||||
|
||||
Transform2D untranslated() const;
|
||||
|
||||
void orthonormalize();
|
||||
Transform2D orthonormalized() const;
|
||||
|
||||
bool operator==(const Transform2D &p_transform) const;
|
||||
bool operator!=(const Transform2D &p_transform) const;
|
||||
|
||||
void operator*=(const Transform2D &p_transform);
|
||||
Transform2D operator*(const Transform2D &p_transform) const;
|
||||
|
||||
Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const;
|
||||
|
||||
Vector2 basis_xform(const Vector2 &p_vec) const;
|
||||
Vector2 basis_xform_inv(const Vector2 &p_vec) const;
|
||||
Vector2 xform(const Vector2 &p_vec) const;
|
||||
Vector2 xform_inv(const Vector2 &p_vec) const;
|
||||
Rect2 xform(const Rect2 &p_vec) const;
|
||||
Rect2 xform_inv(const Rect2 &p_vec) const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy);
|
||||
|
||||
Transform2D(real_t p_rot, const Vector2 &p_pos);
|
||||
inline Transform2D() {
|
||||
elements[0][0] = 1.0;
|
||||
elements[1][1] = 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // TRANSFORM2D_H
|
||||
268
include/core/Variant.hpp
Normal file
268
include/core/Variant.hpp
Normal file
@@ -0,0 +1,268 @@
|
||||
#ifndef VARIANT_H
|
||||
#define VARIANT_H
|
||||
|
||||
#include <gdnative/variant.h>
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "AABB.hpp"
|
||||
#include "Basis.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "NodePath.hpp"
|
||||
#include "Plane.hpp"
|
||||
#include "PoolArrays.hpp"
|
||||
#include "Quat.hpp"
|
||||
#include "RID.hpp"
|
||||
#include "Rect2.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Transform.hpp"
|
||||
#include "Transform2D.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "Vector3.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Dictionary;
|
||||
|
||||
class Array;
|
||||
|
||||
class Variant {
|
||||
godot_variant _godot_variant;
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
|
||||
NIL,
|
||||
|
||||
// atomic types
|
||||
BOOL,
|
||||
INT,
|
||||
REAL,
|
||||
STRING,
|
||||
|
||||
// math types
|
||||
|
||||
VECTOR2, // 5
|
||||
RECT2,
|
||||
VECTOR3,
|
||||
TRANSFORM2D,
|
||||
PLANE,
|
||||
QUAT, // 10
|
||||
RECT3, //sorry naming convention fail :( not like it's used often
|
||||
BASIS,
|
||||
TRANSFORM,
|
||||
|
||||
// misc types
|
||||
COLOR,
|
||||
NODE_PATH, // 15
|
||||
_RID,
|
||||
OBJECT,
|
||||
DICTIONARY,
|
||||
ARRAY,
|
||||
|
||||
// arrays
|
||||
POOL_BYTE_ARRAY, // 20
|
||||
POOL_INT_ARRAY,
|
||||
POOL_REAL_ARRAY,
|
||||
POOL_STRING_ARRAY,
|
||||
POOL_VECTOR2_ARRAY,
|
||||
POOL_VECTOR3_ARRAY, // 25
|
||||
POOL_COLOR_ARRAY,
|
||||
|
||||
VARIANT_MAX
|
||||
|
||||
};
|
||||
|
||||
enum Operator {
|
||||
|
||||
//comparation
|
||||
OP_EQUAL,
|
||||
OP_NOT_EQUAL,
|
||||
OP_LESS,
|
||||
OP_LESS_EQUAL,
|
||||
OP_GREATER,
|
||||
OP_GREATER_EQUAL,
|
||||
|
||||
//mathematic
|
||||
OP_ADD,
|
||||
OP_SUBSTRACT,
|
||||
OP_MULTIPLY,
|
||||
OP_DIVIDE,
|
||||
OP_NEGATE,
|
||||
OP_POSITIVE,
|
||||
OP_MODULE,
|
||||
OP_STRING_CONCAT,
|
||||
|
||||
//bitwise
|
||||
OP_SHIFT_LEFT,
|
||||
OP_SHIFT_RIGHT,
|
||||
OP_BIT_AND,
|
||||
OP_BIT_OR,
|
||||
OP_BIT_XOR,
|
||||
OP_BIT_NEGATE,
|
||||
|
||||
//logic
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
OP_XOR,
|
||||
OP_NOT,
|
||||
|
||||
//containment
|
||||
OP_IN,
|
||||
OP_MAX
|
||||
|
||||
};
|
||||
|
||||
Variant();
|
||||
|
||||
Variant(const Variant &v);
|
||||
|
||||
Variant(bool p_bool);
|
||||
|
||||
Variant(signed int p_int);
|
||||
|
||||
Variant(unsigned int p_int);
|
||||
|
||||
Variant(signed short p_short);
|
||||
|
||||
inline Variant(unsigned short p_short) :
|
||||
Variant((unsigned int)p_short) {}
|
||||
|
||||
inline Variant(signed char p_char) :
|
||||
Variant((signed int)p_char) {}
|
||||
|
||||
inline Variant(unsigned char p_char) :
|
||||
Variant((unsigned int)p_char) {}
|
||||
Variant(int64_t p_char);
|
||||
|
||||
Variant(uint64_t p_char);
|
||||
|
||||
Variant(float p_float);
|
||||
|
||||
Variant(double p_double);
|
||||
|
||||
Variant(const String &p_string);
|
||||
|
||||
Variant(const char *const p_cstring);
|
||||
|
||||
Variant(const wchar_t *p_wstring);
|
||||
|
||||
Variant(const Vector2 &p_vector2);
|
||||
|
||||
Variant(const Rect2 &p_rect2);
|
||||
|
||||
Variant(const Vector3 &p_vector3);
|
||||
|
||||
Variant(const Plane &p_plane);
|
||||
|
||||
Variant(const AABB &p_aabb);
|
||||
|
||||
Variant(const Quat &p_quat);
|
||||
|
||||
Variant(const Basis &p_transform);
|
||||
|
||||
Variant(const Transform2D &p_transform);
|
||||
|
||||
Variant(const Transform &p_transform);
|
||||
|
||||
Variant(const Color &p_color);
|
||||
|
||||
Variant(const NodePath &p_path);
|
||||
|
||||
Variant(const RID &p_rid);
|
||||
|
||||
Variant(const Object *p_object);
|
||||
|
||||
Variant(const Dictionary &p_dictionary);
|
||||
|
||||
Variant(const Array &p_array);
|
||||
|
||||
Variant(const PoolByteArray &p_raw_array);
|
||||
|
||||
Variant(const PoolIntArray &p_int_array);
|
||||
|
||||
Variant(const PoolRealArray &p_real_array);
|
||||
|
||||
Variant(const PoolStringArray &p_string_array);
|
||||
|
||||
Variant(const PoolVector2Array &p_vector2_array);
|
||||
|
||||
Variant(const PoolVector3Array &p_vector3_array);
|
||||
|
||||
Variant(const PoolColorArray &p_color_array);
|
||||
|
||||
Variant &operator=(const Variant &v);
|
||||
|
||||
operator bool() const;
|
||||
operator signed int() const;
|
||||
operator unsigned int() const;
|
||||
operator signed short() const;
|
||||
operator unsigned short() const;
|
||||
operator signed char() const;
|
||||
operator unsigned char() const;
|
||||
operator int64_t() const;
|
||||
operator uint64_t() const;
|
||||
|
||||
operator wchar_t() const;
|
||||
|
||||
operator float() const;
|
||||
|
||||
operator double() const;
|
||||
operator String() const;
|
||||
operator Vector2() const;
|
||||
operator Rect2() const;
|
||||
operator Vector3() const;
|
||||
operator Plane() const;
|
||||
operator AABB() const;
|
||||
operator Quat() const;
|
||||
operator Basis() const;
|
||||
operator Transform() const;
|
||||
operator Transform2D() const;
|
||||
|
||||
operator Color() const;
|
||||
|
||||
operator NodePath() const;
|
||||
operator RID() const;
|
||||
operator godot_object *() const;
|
||||
|
||||
operator Dictionary() const;
|
||||
operator Array() const;
|
||||
|
||||
operator PoolByteArray() const;
|
||||
operator PoolIntArray() const;
|
||||
operator PoolRealArray() const;
|
||||
operator PoolStringArray() const;
|
||||
operator PoolVector2Array() const;
|
||||
operator PoolVector3Array() const;
|
||||
operator PoolColorArray() const;
|
||||
|
||||
Type get_type() const;
|
||||
|
||||
Variant call(const String &method, const Variant **args, const int arg_count);
|
||||
|
||||
bool has_method(const String &method);
|
||||
|
||||
bool operator==(const Variant &b) const;
|
||||
|
||||
bool operator!=(const Variant &b) const;
|
||||
|
||||
bool operator<(const Variant &b) const;
|
||||
|
||||
bool operator<=(const Variant &b) const;
|
||||
|
||||
bool operator>(const Variant &b) const;
|
||||
|
||||
bool operator>=(const Variant &b) const;
|
||||
|
||||
bool hash_compare(const Variant &b) const;
|
||||
|
||||
bool booleanize() const;
|
||||
|
||||
~Variant();
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // VARIANT_H
|
||||
126
include/core/Vector2.hpp
Normal file
126
include/core/Vector2.hpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef VECTOR2_H
|
||||
#define VECTOR2_H
|
||||
|
||||
#include <gdnative/vector2.h>
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
struct Vector2 {
|
||||
|
||||
union {
|
||||
real_t x;
|
||||
real_t width;
|
||||
};
|
||||
union {
|
||||
real_t y;
|
||||
real_t height;
|
||||
};
|
||||
|
||||
inline real_t &operator[](int p_idx) {
|
||||
return p_idx ? y : x;
|
||||
}
|
||||
inline const real_t &operator[](int p_idx) const {
|
||||
return p_idx ? y : x;
|
||||
}
|
||||
|
||||
Vector2 operator+(const Vector2 &p_v) const;
|
||||
|
||||
void operator+=(const Vector2 &p_v);
|
||||
|
||||
Vector2 operator-(const Vector2 &p_v) const;
|
||||
|
||||
void operator-=(const Vector2 &p_v);
|
||||
|
||||
Vector2 operator*(const Vector2 &p_v1) const;
|
||||
|
||||
Vector2 operator*(const real_t &rvalue) const;
|
||||
|
||||
void operator*=(const real_t &rvalue);
|
||||
|
||||
inline void operator*=(const Vector2 &rvalue) { *this = *this * rvalue; }
|
||||
|
||||
Vector2 operator/(const Vector2 &p_v1) const;
|
||||
|
||||
Vector2 operator/(const real_t &rvalue) const;
|
||||
|
||||
void operator/=(const real_t &rvalue);
|
||||
|
||||
Vector2 operator-() const;
|
||||
|
||||
bool operator==(const Vector2 &p_vec2) const;
|
||||
|
||||
bool operator!=(const Vector2 &p_vec2) const;
|
||||
|
||||
inline bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
|
||||
inline bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); }
|
||||
|
||||
void normalize();
|
||||
|
||||
Vector2 normalized() const;
|
||||
|
||||
real_t length() const;
|
||||
real_t length_squared() const;
|
||||
|
||||
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;
|
||||
real_t angle_to_point(const Vector2 &p_vector2) const;
|
||||
|
||||
real_t dot(const Vector2 &p_other) const;
|
||||
|
||||
real_t cross(const Vector2 &p_other) const;
|
||||
Vector2 cross(real_t p_other) const;
|
||||
|
||||
Vector2 project(const Vector2 &p_vec) const;
|
||||
|
||||
Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const;
|
||||
|
||||
Vector2 clamped(real_t p_len) const;
|
||||
|
||||
static Vector2 linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t);
|
||||
|
||||
Vector2 linear_interpolate(const Vector2 &p_b, real_t p_t) const;
|
||||
Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const;
|
||||
|
||||
Vector2 slide(const Vector2 &p_vec) const;
|
||||
|
||||
Vector2 reflect(const Vector2 &p_vec) const;
|
||||
|
||||
real_t angle() const;
|
||||
|
||||
void set_rotation(real_t p_radians);
|
||||
|
||||
Vector2 abs() const;
|
||||
Vector2 rotated(real_t p_by) const;
|
||||
|
||||
Vector2 tangent() const;
|
||||
|
||||
Vector2 floor() const;
|
||||
|
||||
Vector2 snapped(const Vector2 &p_by) const;
|
||||
inline real_t aspect() const { return width / height; }
|
||||
|
||||
operator String() const;
|
||||
|
||||
inline Vector2(real_t p_x, real_t p_y) {
|
||||
x = p_x;
|
||||
y = p_y;
|
||||
}
|
||||
inline Vector2() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
};
|
||||
|
||||
inline Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) {
|
||||
return p_vec * p_scalar;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // VECTOR2_H
|
||||
138
include/core/Vector3.hpp
Normal file
138
include/core/Vector3.hpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#ifndef VECTOR3_H
|
||||
#define VECTOR3_H
|
||||
|
||||
#include "Defs.hpp"
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Basis;
|
||||
|
||||
struct Vector3 {
|
||||
|
||||
enum Axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
real_t x;
|
||||
real_t y;
|
||||
real_t z;
|
||||
};
|
||||
|
||||
real_t coord[3];
|
||||
};
|
||||
|
||||
Vector3(real_t x, real_t y, real_t z);
|
||||
|
||||
Vector3();
|
||||
|
||||
const real_t &operator[](int p_axis) const;
|
||||
|
||||
real_t &operator[](int p_axis);
|
||||
|
||||
Vector3 &operator+=(const Vector3 &p_v);
|
||||
|
||||
Vector3 operator+(const Vector3 &p_v) const;
|
||||
|
||||
Vector3 &operator-=(const Vector3 &p_v);
|
||||
|
||||
Vector3 operator-(const Vector3 &p_v) const;
|
||||
|
||||
Vector3 &operator*=(const Vector3 &p_v);
|
||||
|
||||
Vector3 operator*(const Vector3 &p_v) const;
|
||||
|
||||
Vector3 &operator/=(const Vector3 &p_v);
|
||||
|
||||
Vector3 operator/(const Vector3 &p_v) const;
|
||||
|
||||
Vector3 &operator*=(real_t p_scalar);
|
||||
|
||||
Vector3 operator*(real_t p_scalar) const;
|
||||
|
||||
Vector3 &operator/=(real_t p_scalar);
|
||||
|
||||
Vector3 operator/(real_t p_scalar) const;
|
||||
|
||||
Vector3 operator-() const;
|
||||
|
||||
bool operator==(const Vector3 &p_v) const;
|
||||
|
||||
bool operator!=(const Vector3 &p_v) const;
|
||||
|
||||
bool operator<(const Vector3 &p_v) const;
|
||||
|
||||
bool operator<=(const Vector3 &p_v) const;
|
||||
|
||||
Vector3 abs() const;
|
||||
|
||||
Vector3 ceil() const;
|
||||
|
||||
Vector3 cross(const Vector3 &b) const;
|
||||
|
||||
Vector3 linear_interpolate(const Vector3 &p_b, real_t p_t) const;
|
||||
|
||||
Vector3 cubic_interpolate(const Vector3 &b, const Vector3 &pre_a, const Vector3 &post_b, const real_t t) const;
|
||||
|
||||
Vector3 bounce(const Vector3 &p_normal) const;
|
||||
|
||||
real_t length() const;
|
||||
|
||||
real_t length_squared() const;
|
||||
|
||||
real_t distance_squared_to(const Vector3 &b) const;
|
||||
|
||||
real_t distance_to(const Vector3 &b) const;
|
||||
|
||||
real_t dot(const Vector3 &b) const;
|
||||
|
||||
real_t angle_to(const Vector3 &b) const;
|
||||
|
||||
Vector3 floor() const;
|
||||
|
||||
Vector3 inverse() const;
|
||||
|
||||
bool is_normalized() const;
|
||||
|
||||
Basis outer(const Vector3 &b) const;
|
||||
|
||||
int max_axis() const;
|
||||
|
||||
int min_axis() const;
|
||||
|
||||
void normalize();
|
||||
|
||||
Vector3 normalized() const;
|
||||
|
||||
Vector3 reflect(const Vector3 &by) const;
|
||||
|
||||
Vector3 rotated(const Vector3 &axis, const real_t phi) const;
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_phi);
|
||||
|
||||
Vector3 slide(const Vector3 &by) const;
|
||||
|
||||
void snap(real_t p_val);
|
||||
|
||||
Vector3 snapped(const float by);
|
||||
|
||||
operator String() const;
|
||||
};
|
||||
|
||||
inline Vector3 operator*(real_t p_scalar, const Vector3 &p_vec) {
|
||||
return p_vec * p_scalar;
|
||||
}
|
||||
|
||||
inline Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) {
|
||||
|
||||
return p_a.cross(p_b);
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // VECTOR3_H
|
||||
16
include/core/Wrapped.hpp
Normal file
16
include/core/Wrapped.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef WRAPPED_HPP
|
||||
#define WRAPPED_HPP
|
||||
|
||||
#include <gdnative/gdnative.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class _Wrapped {
|
||||
public:
|
||||
godot_object *_owner;
|
||||
size_t _type_tag;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // WRAPPED_HPP
|
||||
2
include/gen/.gitignore
vendored
Normal file
2
include/gen/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -1,62 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* editor_plugin_registration.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
|
||||
#define GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
|
||||
|
||||
#include <godot_cpp/templates/vector.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class EditorPlugin;
|
||||
class StringName;
|
||||
|
||||
class EditorPlugins {
|
||||
private:
|
||||
static Vector<StringName> plugin_classes;
|
||||
|
||||
public:
|
||||
static void add_plugin_class(const StringName &p_class_name);
|
||||
static void remove_plugin_class(const StringName &p_class_name);
|
||||
static void deinitialize(GDExtensionInitializationLevel p_level);
|
||||
|
||||
template <class T>
|
||||
static void add_by_type() {
|
||||
add_plugin_class(T::get_class_static());
|
||||
}
|
||||
template <class T>
|
||||
static void remove_by_type() {
|
||||
remove_plugin_class(T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
|
||||
@@ -1,284 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* ref.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_REF_HPP
|
||||
#define GODOT_REF_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <godot_cpp/classes/object.hpp>
|
||||
#include <godot_cpp/classes/ref_counted.hpp>
|
||||
#include <godot_cpp/core/binder_common.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
// Helper class for RefCounted objects, same as Godot one.
|
||||
|
||||
class RefCounted;
|
||||
|
||||
template <class T>
|
||||
class Ref {
|
||||
T *reference = nullptr;
|
||||
|
||||
void ref(const Ref &p_from) {
|
||||
if (p_from.reference == reference) {
|
||||
return;
|
||||
}
|
||||
|
||||
unref();
|
||||
|
||||
reference = p_from.reference;
|
||||
if (reference) {
|
||||
reference->reference();
|
||||
}
|
||||
}
|
||||
|
||||
void ref_pointer(T *p_ref) {
|
||||
ERR_FAIL_NULL(p_ref);
|
||||
|
||||
if (p_ref->init_ref()) {
|
||||
reference = p_ref;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
|
||||
return reference == p_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ bool operator!=(const T *p_ptr) const {
|
||||
return reference != p_ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator<(const Ref<T> &p_r) const {
|
||||
return reference < p_r.reference;
|
||||
}
|
||||
_FORCE_INLINE_ bool operator==(const Ref<T> &p_r) const {
|
||||
return reference == p_r.reference;
|
||||
}
|
||||
_FORCE_INLINE_ bool operator!=(const Ref<T> &p_r) const {
|
||||
return reference != p_r.reference;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *operator*() const {
|
||||
return reference;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *operator->() const {
|
||||
return reference;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *ptr() const {
|
||||
return reference;
|
||||
}
|
||||
|
||||
operator Variant() const {
|
||||
return Variant(reference);
|
||||
}
|
||||
|
||||
void operator=(const Ref &p_from) {
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
void operator=(const Ref<T_Other> &p_from) {
|
||||
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
|
||||
if (!refb) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
|
||||
Ref r;
|
||||
r.reference = Object::cast_to<T>(refb);
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
void operator=(const Variant &p_variant) {
|
||||
// Needs testing, Variant has a cast to Object * here.
|
||||
|
||||
// Object *object = p_variant.get_validated_object();
|
||||
Object *object = p_variant;
|
||||
|
||||
if (object == reference) {
|
||||
return;
|
||||
}
|
||||
|
||||
unref();
|
||||
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
T *r = Object::cast_to<T>(object);
|
||||
if (r && r->reference()) {
|
||||
reference = r;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
void reference_ptr(T_Other *p_ptr) {
|
||||
if (reference == p_ptr) {
|
||||
return;
|
||||
}
|
||||
unref();
|
||||
|
||||
T *r = Object::cast_to<T>(p_ptr);
|
||||
if (r) {
|
||||
ref_pointer(r);
|
||||
}
|
||||
}
|
||||
|
||||
Ref(const Ref &p_from) {
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
Ref(const Ref<T_Other> &p_from) {
|
||||
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
|
||||
if (!refb) {
|
||||
unref();
|
||||
return;
|
||||
}
|
||||
|
||||
Ref r;
|
||||
r.reference = Object::cast_to<T>(refb);
|
||||
ref(r);
|
||||
r.reference = nullptr;
|
||||
}
|
||||
|
||||
Ref(T *p_reference) {
|
||||
if (p_reference) {
|
||||
ref_pointer(p_reference);
|
||||
}
|
||||
}
|
||||
|
||||
Ref(const Variant &p_variant) {
|
||||
// Needs testing, Variant has a cast to Object * here.
|
||||
|
||||
// Object *object = p_variant.get_validated_object();
|
||||
Object *object = p_variant;
|
||||
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
T *r = Object::cast_to<T>(object);
|
||||
if (r && r->reference()) {
|
||||
reference = r;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_valid() const { return reference != nullptr; }
|
||||
inline bool is_null() const { return reference == nullptr; }
|
||||
|
||||
void unref() {
|
||||
if (reference && reference->unreference()) {
|
||||
memdelete(reference);
|
||||
}
|
||||
reference = nullptr;
|
||||
}
|
||||
|
||||
void instantiate() {
|
||||
ref(memnew(T()));
|
||||
}
|
||||
|
||||
Ref() {}
|
||||
|
||||
~Ref() {
|
||||
unref();
|
||||
}
|
||||
|
||||
// Used exclusively in the bindings to recreate the Ref Godot encapsulates in return values,
|
||||
// without adding to the refcount.
|
||||
inline static Ref<T> _gde_internal_constructor(Object *obj) {
|
||||
Ref<T> r;
|
||||
r.reference = (T *)obj;
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg<Ref<T>> {
|
||||
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
|
||||
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
|
||||
ERR_FAIL_NULL_V(p_ptr, Ref<T>());
|
||||
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
|
||||
}
|
||||
|
||||
typedef Ref<T> EncodeT;
|
||||
|
||||
_FORCE_INLINE_ static void encode(Ref<T> p_val, void *p_ptr) {
|
||||
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
|
||||
ERR_FAIL_NULL(ref);
|
||||
|
||||
// This code assumes that p_ptr points to an unset Ref<T> variable on the Godot side
|
||||
// so we only set it if we have an object to set.
|
||||
if (p_val.is_valid()) {
|
||||
godot::internal::gdextension_interface_ref_set_object(ref, p_val->_owner);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg<const Ref<T> &> {
|
||||
typedef Ref<T> EncodeT;
|
||||
|
||||
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
|
||||
GDExtensionRefPtr ref = const_cast<GDExtensionRefPtr>(p_ptr);
|
||||
ERR_FAIL_NULL_V(p_ptr, Ref<T>());
|
||||
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
|
||||
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
|
||||
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_REF_HPP
|
||||
@@ -1,431 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* wrapped.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_WRAPPED_HPP
|
||||
#define GODOT_WRAPPED_HPP
|
||||
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
|
||||
#include <godot_cpp/core/property_info.hpp>
|
||||
|
||||
#include <godot_cpp/templates/list.hpp>
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class ClassDB;
|
||||
|
||||
typedef void GodotObject;
|
||||
|
||||
// Base for all engine classes, to contain the pointer to the engine instance.
|
||||
class Wrapped {
|
||||
friend class GDExtensionBinding;
|
||||
friend void postinitialize_handler(Wrapped *);
|
||||
|
||||
protected:
|
||||
virtual const StringName *_get_extension_class_name() const; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
|
||||
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const = 0;
|
||||
|
||||
void _notification(int p_what) {}
|
||||
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
|
||||
bool _get(const StringName &p_name, Variant &r_property) const { return false; }
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const {}
|
||||
bool _property_can_revert(const StringName &p_name) const { return false; }
|
||||
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }
|
||||
String _to_string() const { return "[" + String(get_class_static()) + ":" + itos(get_instance_id()) + "]"; }
|
||||
|
||||
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) {}
|
||||
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 void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) {}
|
||||
|
||||
::godot::List<::godot::PropertyInfo> plist_owned;
|
||||
GDExtensionPropertyInfo *plist = nullptr;
|
||||
uint32_t plist_size = 0;
|
||||
|
||||
void _postinitialize();
|
||||
|
||||
Wrapped(const StringName p_godot_class);
|
||||
Wrapped(GodotObject *p_godot_object);
|
||||
virtual ~Wrapped() {}
|
||||
|
||||
public:
|
||||
static StringName &get_class_static() {
|
||||
static StringName string_name = StringName("Wrapped");
|
||||
return string_name;
|
||||
}
|
||||
|
||||
uint64_t get_instance_id() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Must be public but you should not touch this.
|
||||
GodotObject *_owner = nullptr;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
typedef void (*EngineClassRegistrationCallback)();
|
||||
void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback);
|
||||
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks);
|
||||
void register_engine_classes();
|
||||
|
||||
template <class T>
|
||||
struct EngineClassRegistration {
|
||||
EngineClassRegistration() {
|
||||
add_engine_class_registration_callback(&EngineClassRegistration<T>::callback);
|
||||
}
|
||||
|
||||
static void callback() {
|
||||
register_engine_class(T::get_class_static(), &T::_gde_binding_callbacks);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#define GDCLASS(m_class, m_inherits) \
|
||||
private: \
|
||||
void operator=(const m_class &p_rval) {} \
|
||||
friend class ::godot::ClassDB; \
|
||||
\
|
||||
protected: \
|
||||
virtual const ::godot::StringName *_get_extension_class_name() const override { \
|
||||
static ::godot::StringName string_name = get_class_static(); \
|
||||
return &string_name; \
|
||||
} \
|
||||
\
|
||||
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
|
||||
return &_gde_binding_callbacks; \
|
||||
} \
|
||||
\
|
||||
static void (*_get_bind_methods())() { \
|
||||
return &m_class::_bind_methods; \
|
||||
} \
|
||||
\
|
||||
static void (::godot::Wrapped::*_get_notification())(int) { \
|
||||
return (void(::godot::Wrapped::*)(int)) & m_class::_notification; \
|
||||
} \
|
||||
\
|
||||
static bool (::godot::Wrapped::*_get_set())(const ::godot::StringName &p_name, const ::godot::Variant &p_property) { \
|
||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, const ::godot::Variant &p_property)) & m_class::_set; \
|
||||
} \
|
||||
\
|
||||
static bool (::godot::Wrapped::*_get_get())(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const { \
|
||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const) & m_class::_get; \
|
||||
} \
|
||||
\
|
||||
static void (::godot::Wrapped::*_get_get_property_list())(::godot::List<::godot::PropertyInfo> * p_list) const { \
|
||||
return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list; \
|
||||
} \
|
||||
\
|
||||
static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
|
||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name) const) & m_class::_property_can_revert; \
|
||||
} \
|
||||
\
|
||||
static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) const { \
|
||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &) const) & m_class::_property_get_revert; \
|
||||
} \
|
||||
\
|
||||
static ::godot::String (::godot::Wrapped::*_get_to_string())() const { \
|
||||
return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \
|
||||
} \
|
||||
\
|
||||
template <class T, class B> \
|
||||
static void register_virtuals() { \
|
||||
m_inherits::register_virtuals<T, B>(); \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
typedef m_class self_type; \
|
||||
\
|
||||
static void initialize_class() { \
|
||||
static bool initialized = false; \
|
||||
if (initialized) { \
|
||||
return; \
|
||||
} \
|
||||
m_inherits::initialize_class(); \
|
||||
if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
|
||||
_bind_methods(); \
|
||||
m_inherits::register_virtuals<m_class, m_inherits>(); \
|
||||
} \
|
||||
initialized = true; \
|
||||
} \
|
||||
\
|
||||
static ::godot::StringName &get_class_static() { \
|
||||
static ::godot::StringName string_name = ::godot::StringName(#m_class); \
|
||||
return string_name; \
|
||||
} \
|
||||
\
|
||||
static ::godot::StringName &get_parent_class_static() { \
|
||||
return m_inherits::get_class_static(); \
|
||||
} \
|
||||
\
|
||||
static GDExtensionObjectPtr create(void *data) { \
|
||||
m_class *new_object = memnew(m_class); \
|
||||
return new_object->_owner; \
|
||||
} \
|
||||
\
|
||||
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \
|
||||
if (p_instance && m_class::_get_notification()) { \
|
||||
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
return cls->_notification(p_what); \
|
||||
} \
|
||||
m_inherits::notification_bind(p_instance, p_what); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { \
|
||||
if (p_instance && m_class::_get_set()) { \
|
||||
if (m_class::_get_set() != m_inherits::_get_set()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
return cls->_set(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<const ::godot::Variant *>(p_value)); \
|
||||
} \
|
||||
return m_inherits::set_bind(p_instance, p_name, p_value); \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
|
||||
if (p_instance && m_class::_get_get()) { \
|
||||
if (m_class::_get_get() != m_inherits::_get_get()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
return cls->_get(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \
|
||||
} \
|
||||
return m_inherits::get_bind(p_instance, p_name, r_ret); \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \
|
||||
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); \
|
||||
} \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
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(); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { \
|
||||
if (p_instance && m_class::_get_property_can_revert()) { \
|
||||
if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
return cls->_property_can_revert(*reinterpret_cast<const ::godot::StringName *>(p_name)); \
|
||||
} \
|
||||
return m_inherits::property_can_revert_bind(p_instance, p_name); \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
|
||||
if (p_instance && m_class::_get_property_get_revert()) { \
|
||||
if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
return cls->_property_get_revert(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \
|
||||
} \
|
||||
return m_inherits::property_get_revert_bind(p_instance, p_name, r_ret); \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) { \
|
||||
if (p_instance && m_class::_get_to_string()) { \
|
||||
if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
*reinterpret_cast<::godot::String *>(r_out) = cls->_to_string(); \
|
||||
*r_is_valid = true; \
|
||||
return; \
|
||||
} \
|
||||
m_inherits::to_string_bind(p_instance, r_is_valid, r_out); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
|
||||
if (ptr) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(ptr); \
|
||||
cls->~m_class(); \
|
||||
::godot::Memory::free_static(cls); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
|
||||
} \
|
||||
\
|
||||
static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
|
||||
_gde_binding_create_callback, \
|
||||
_gde_binding_free_callback, \
|
||||
_gde_binding_reference_callback, \
|
||||
}; \
|
||||
\
|
||||
private:
|
||||
|
||||
// Don't use this for your classes, use GDCLASS() instead.
|
||||
#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \
|
||||
private: \
|
||||
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
|
||||
void operator=(const m_class &p_rval) {} \
|
||||
\
|
||||
protected: \
|
||||
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
|
||||
return &_gde_binding_callbacks; \
|
||||
} \
|
||||
\
|
||||
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
|
||||
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
|
||||
\
|
||||
static void (*_get_bind_methods())() { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static void (Wrapped::*_get_notification())(int) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static bool (Wrapped::*_get_set())(const ::godot::StringName &p_name, const Variant &p_property) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static bool (Wrapped::*_get_get())(const ::godot::StringName &p_name, Variant &r_ret) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static inline bool has_get_property_list() { \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static void (Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static String (Wrapped::*_get_to_string())() const { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
typedef m_class self_type; \
|
||||
\
|
||||
static void initialize_class() {} \
|
||||
\
|
||||
static ::godot::StringName &get_class_static() { \
|
||||
static ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
|
||||
return string_name; \
|
||||
} \
|
||||
\
|
||||
static ::godot::StringName &get_parent_class_static() { \
|
||||
return m_inherits::get_class_static(); \
|
||||
} \
|
||||
\
|
||||
static GDExtensionObjectPtr create(void *data) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
|
||||
} \
|
||||
\
|
||||
static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
|
||||
/* Do not call memnew here, we don't want the post-initializer to be called */ \
|
||||
return new ("") m_class((GodotObject *)p_instance); \
|
||||
} \
|
||||
static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
|
||||
/* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \
|
||||
reinterpret_cast<m_class *>(p_binding)->~m_class(); \
|
||||
Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
|
||||
} \
|
||||
static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
|
||||
return true; \
|
||||
} \
|
||||
static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
|
||||
_gde_binding_create_callback, \
|
||||
_gde_binding_free_callback, \
|
||||
_gde_binding_reference_callback, \
|
||||
}; \
|
||||
m_class() : m_class(#m_alias_for) {} \
|
||||
\
|
||||
private:
|
||||
|
||||
// Don't use this for your classes, use GDCLASS() instead.
|
||||
#define GDEXTENSION_CLASS(m_class, m_inherits) GDEXTENSION_CLASS_ALIAS(m_class, m_class, m_inherits)
|
||||
|
||||
#endif // GODOT_WRAPPED_HPP
|
||||
@@ -1,606 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* binder_common.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_BINDER_COMMON_HPP
|
||||
#define GODOT_BINDER_COMMON_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <godot_cpp/core/method_ptrcall.hpp>
|
||||
#include <godot_cpp/core/type_info.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace godot {
|
||||
|
||||
#define VARIANT_ENUM_CAST(m_enum) \
|
||||
namespace godot { \
|
||||
MAKE_ENUM_TYPE_INFO(m_enum) \
|
||||
template <> \
|
||||
struct VariantCaster<m_enum> { \
|
||||
static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
|
||||
return (m_enum)p_variant.operator int64_t(); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<m_enum> { \
|
||||
_FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
|
||||
return m_enum(*reinterpret_cast<const int64_t *>(p_ptr)); \
|
||||
} \
|
||||
typedef int64_t EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_enum p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<int64_t *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define VARIANT_BITFIELD_CAST(m_enum) \
|
||||
namespace godot { \
|
||||
MAKE_BITFIELD_TYPE_INFO(m_enum) \
|
||||
template <> \
|
||||
struct VariantCaster<BitField<m_enum>> { \
|
||||
static _FORCE_INLINE_ BitField<m_enum> cast(const Variant &p_variant) { \
|
||||
return BitField<m_enum>(p_variant.operator int64_t()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<BitField<m_enum>> { \
|
||||
_FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) { \
|
||||
return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr)); \
|
||||
} \
|
||||
typedef int64_t EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(BitField<m_enum> p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<int64_t *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct VariantCaster {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of<Object, TStripped>::value) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantCaster<T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of<Object, TStripped>::value) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantCaster<const T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of<Object, TStripped>::value) {
|
||||
return Object::cast_to<TStripped>(p_variant);
|
||||
} else {
|
||||
return p_variant;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantObjectClassChecker {
|
||||
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
if constexpr (std::is_base_of<Object, TStripped>::value) {
|
||||
Object *obj = p_variant;
|
||||
return Object::cast_to<TStripped>(p_variant) || !obj;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Ref;
|
||||
|
||||
template <typename T>
|
||||
struct VariantObjectClassChecker<const Ref<T> &> {
|
||||
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
|
||||
Object *obj = p_variant;
|
||||
const Ref<T> node = p_variant;
|
||||
return node.ptr() || !obj;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantCasterAndValidate {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
|
||||
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
|
||||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantCasterAndValidate<T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
|
||||
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
|
||||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantCasterAndValidate<const T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
|
||||
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
|
||||
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
|
||||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument = p_arg_idx;
|
||||
r_error.expected = argtype;
|
||||
}
|
||||
|
||||
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... P, size_t... Is>
|
||||
void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
|
||||
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
|
||||
}
|
||||
|
||||
template <class T, class... P, size_t... Is>
|
||||
void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
|
||||
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
|
||||
}
|
||||
|
||||
template <class T, class R, class... P, size_t... Is>
|
||||
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
|
||||
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
|
||||
}
|
||||
|
||||
template <class T, class R, class... P, size_t... Is>
|
||||
void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
|
||||
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
|
||||
}
|
||||
|
||||
template <class T, class... P>
|
||||
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
|
||||
call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class T, class... P>
|
||||
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
|
||||
call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class T, class R, class... P>
|
||||
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
|
||||
call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class T, class R, class... P>
|
||||
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret) {
|
||||
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class T, class... P, size_t... Is>
|
||||
void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = GDEXTENSION_CALL_OK;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
(p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
(void)(p_args); // Avoid warning.
|
||||
}
|
||||
|
||||
template <class T, class... P, size_t... Is>
|
||||
void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = GDEXTENSION_CALL_OK;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
(p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
(void)(p_args); // Avoid warning.
|
||||
}
|
||||
|
||||
template <class T, class R, class... P, size_t... Is>
|
||||
void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = GDEXTENSION_CALL_OK;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T, class R, class... P, size_t... Is>
|
||||
void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = GDEXTENSION_CALL_OK;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
(void)p_args;
|
||||
}
|
||||
|
||||
template <class T, class... P>
|
||||
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.argument = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = (int32_t)default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.argument = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class T, class... P>
|
||||
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.argument = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = (int32_t)default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.argument = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_argsc_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class T, class R, class... P>
|
||||
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.argument = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = (int32_t)default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.argument = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_ret_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class T, class R, class... P>
|
||||
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.argument = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = (int32_t)default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.argument = (int32_t)sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_retc_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
// GCC raises "parameter 'p_args' set but not used" when P = {},
|
||||
// it's not clever enough to treat other P values as making this branch valid.
|
||||
#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
|
||||
#endif
|
||||
|
||||
template <class Q>
|
||||
void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) {
|
||||
if (p_arg == index) {
|
||||
type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
GDExtensionVariantType call_get_argument_type(int p_arg) {
|
||||
GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_type_helper<P>(p_arg, index, type), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index; // Suppress GCC warning.
|
||||
return type;
|
||||
}
|
||||
|
||||
template <class Q>
|
||||
void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
|
||||
if (p_arg == index) {
|
||||
info = GetTypeInfo<Q>::get_class_info();
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_type_info_helper<P>(p_arg, index, info), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index; // Suppress GCC warning.
|
||||
}
|
||||
|
||||
template <class Q>
|
||||
void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) {
|
||||
if (p_arg == index) {
|
||||
md = GetTypeInfo<Q>::METADATA;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
|
||||
GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
using expand_type = int[];
|
||||
expand_type a{ 0, (call_get_argument_metadata_helper<P>(p_arg, index, md), 0)... };
|
||||
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
|
||||
(void)index;
|
||||
return md;
|
||||
}
|
||||
|
||||
template <class... P, size_t... Is>
|
||||
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = GDEXTENSION_CALL_OK;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
(p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
(p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.argument = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.argument = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class... P, size_t... Is>
|
||||
void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
|
||||
p_method(PtrToArg<P>::convert(p_args[Is])...);
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args) {
|
||||
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class R, class... P, size_t... Is>
|
||||
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
|
||||
r_error.error = GDEXTENSION_CALL_OK;
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
r_ret = (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
|
||||
#else
|
||||
r_ret = (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class R, class... P>
|
||||
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((size_t)p_argcount > sizeof...(P)) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||
r_error.argument = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
|
||||
|
||||
int32_t dvs = default_values.size();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (missing > dvs) {
|
||||
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
r_error.argument = sizeof...(P);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
|
||||
std::array<const Variant *, sizeof...(P)> argsp;
|
||||
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
|
||||
if (i < p_argcount) {
|
||||
args[i] = Variant(p_args[i]);
|
||||
} else {
|
||||
args[i] = default_values[i - p_argcount + (dvs - missing)];
|
||||
}
|
||||
argsp[i] = &args[i];
|
||||
}
|
||||
|
||||
call_with_variant_args_static_ret(p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
template <class R, class... P, size_t... Is>
|
||||
void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
|
||||
PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
|
||||
}
|
||||
|
||||
template <class R, class... P>
|
||||
void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
|
||||
call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#include <godot_cpp/classes/global_constants_binds.hpp>
|
||||
#include <godot_cpp/variant/builtin_binds.hpp>
|
||||
|
||||
#endif // GODOT_BINDER_COMMON_HPP
|
||||
@@ -1,80 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* builtin_ptrcall.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_BUILTIN_PTRCALL_HPP
|
||||
#define GODOT_BUILTIN_PTRCALL_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class... Args>
|
||||
void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) {
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
constructor(base, call_args.data());
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
|
||||
T ret;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
method(base, call_args.data(), &ret, sizeof...(Args));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void _call_builtin_method_ptr_no_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
method(base, call_args.data(), nullptr, sizeof...(Args));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) {
|
||||
T ret;
|
||||
op(left, right, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) {
|
||||
T ret;
|
||||
getter(base, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_BUILTIN_PTRCALL_HPP
|
||||
@@ -1,293 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* class_db.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_CLASS_DB_HPP
|
||||
#define GODOT_CLASS_DB_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/method_bind.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
|
||||
#include <godot_cpp/classes/class_db_singleton.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// Needed to use StringName as key in `std::unordered_map`
|
||||
template <>
|
||||
struct std::hash<godot::StringName> {
|
||||
std::size_t operator()(godot::StringName const &s) const noexcept {
|
||||
return s.hash();
|
||||
}
|
||||
};
|
||||
|
||||
namespace godot {
|
||||
|
||||
#define DEFVAL(m_defval) (m_defval)
|
||||
|
||||
struct MethodDefinition {
|
||||
StringName name;
|
||||
std::list<StringName> args;
|
||||
MethodDefinition() {}
|
||||
MethodDefinition(StringName p_name) :
|
||||
name(p_name) {}
|
||||
};
|
||||
|
||||
MethodDefinition D_METHOD(StringName p_name);
|
||||
MethodDefinition D_METHOD(StringName p_name, StringName p_arg1);
|
||||
template <typename... Args>
|
||||
MethodDefinition D_METHOD(StringName p_name, StringName p_arg1, Args... args) {
|
||||
MethodDefinition md = D_METHOD(p_name, args...);
|
||||
md.args.push_front(p_arg1);
|
||||
return md;
|
||||
}
|
||||
|
||||
class ClassDB {
|
||||
static GDExtensionInitializationLevel current_level;
|
||||
|
||||
friend class godot::GDExtensionBinding;
|
||||
|
||||
public:
|
||||
struct PropertySetGet {
|
||||
int index;
|
||||
StringName setter;
|
||||
StringName getter;
|
||||
MethodBind *_setptr;
|
||||
MethodBind *_getptr;
|
||||
Variant::Type type;
|
||||
};
|
||||
|
||||
struct ClassInfo {
|
||||
StringName name;
|
||||
StringName parent_name;
|
||||
GDExtensionInitializationLevel level = GDEXTENSION_INITIALIZATION_SCENE;
|
||||
std::unordered_map<StringName, MethodBind *> method_map;
|
||||
std::set<StringName> signal_names;
|
||||
std::unordered_map<StringName, GDExtensionClassCallVirtual> virtual_methods;
|
||||
std::set<StringName> property_names;
|
||||
std::set<StringName> constant_names;
|
||||
// Pointer to the parent custom class, if any. Will be null if the parent class is a Godot class.
|
||||
ClassInfo *parent_ptr = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
// This may only contain custom classes, not Godot classes
|
||||
static std::unordered_map<StringName, ClassInfo> classes;
|
||||
static std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks;
|
||||
// Used to remember the custom class registration order.
|
||||
static std::vector<StringName> class_register_order;
|
||||
|
||||
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount);
|
||||
static void initialize_class(const ClassInfo &cl);
|
||||
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
|
||||
|
||||
template <class T, bool is_abstract>
|
||||
static void _register_class(bool p_virtual = false);
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
static void register_class(bool p_virtual = false);
|
||||
template <class T>
|
||||
static void register_abstract_class();
|
||||
|
||||
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
|
||||
instance_binding_callbacks[p_name] = p_callbacks;
|
||||
}
|
||||
|
||||
template <class N, class M, typename... VarArgs>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
|
||||
|
||||
template <class N, class M, typename... VarArgs>
|
||||
static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
|
||||
|
||||
template <class M>
|
||||
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);
|
||||
|
||||
static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
|
||||
static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix);
|
||||
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
|
||||
static void add_signal(const StringName &p_class, const MethodInfo &p_signal);
|
||||
static void bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield = false);
|
||||
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call);
|
||||
|
||||
static MethodBind *get_method(const StringName &p_class, const StringName &p_method);
|
||||
|
||||
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name);
|
||||
static const GDExtensionInstanceBindingCallbacks *get_instance_binding_callbacks(const StringName &p_class);
|
||||
|
||||
static void initialize(GDExtensionInitializationLevel p_level);
|
||||
static void deinitialize(GDExtensionInitializationLevel p_level);
|
||||
|
||||
CLASSDB_SINGLETON_FORWARD_METHODS;
|
||||
};
|
||||
|
||||
#define BIND_CONSTANT(m_constant) \
|
||||
godot::ClassDB::bind_integer_constant(get_class_static(), "", #m_constant, m_constant);
|
||||
|
||||
#define BIND_ENUM_CONSTANT(m_constant) \
|
||||
godot::ClassDB::bind_integer_constant(get_class_static(), godot::_gde_constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
|
||||
|
||||
#define BIND_BITFIELD_FLAG(m_constant) \
|
||||
godot::ClassDB::bind_integer_constant(get_class_static(), godot::_gde_constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
|
||||
|
||||
#define BIND_VIRTUAL_METHOD(m_class, m_method) \
|
||||
{ \
|
||||
auto _call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \
|
||||
call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
|
||||
}; \
|
||||
godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method); \
|
||||
}
|
||||
|
||||
template <class T, bool is_abstract>
|
||||
void ClassDB::_register_class(bool p_virtual) {
|
||||
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
|
||||
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
|
||||
|
||||
// Register this class within our plugin
|
||||
ClassInfo cl;
|
||||
cl.name = T::get_class_static();
|
||||
cl.parent_name = T::get_parent_class_static();
|
||||
cl.level = current_level;
|
||||
std::unordered_map<StringName, ClassInfo>::iterator parent_it = classes.find(cl.parent_name);
|
||||
if (parent_it != classes.end()) {
|
||||
// Assign parent if it is also a custom class
|
||||
cl.parent_ptr = &parent_it->second;
|
||||
}
|
||||
classes[cl.name] = cl;
|
||||
class_register_order.push_back(cl.name);
|
||||
|
||||
// Register this class with Godot
|
||||
GDExtensionClassCreationInfo class_info = {
|
||||
p_virtual, // GDExtensionBool is_virtual;
|
||||
is_abstract, // GDExtensionBool is_abstract;
|
||||
T::set_bind, // GDExtensionClassSet set_func;
|
||||
T::get_bind, // GDExtensionClassGet get_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::notification_bind, // GDExtensionClassNotification notification_func;
|
||||
T::to_string_bind, // GDExtensionClassToString to_string_func;
|
||||
nullptr, // GDExtensionClassReference reference_func;
|
||||
nullptr, // GDExtensionClassUnreference unreference_func;
|
||||
T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
|
||||
T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
|
||||
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
|
||||
nullptr, // GDExtensionClassGetRID get_rid;
|
||||
(void *)&T::get_class_static(), // void *class_userdata;
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
// now register our class within ClassDB within Godot
|
||||
initialize_class(classes[cl.name]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ClassDB::register_class(bool p_virtual) {
|
||||
ClassDB::_register_class<T, false>(p_virtual);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ClassDB::register_abstract_class() {
|
||||
ClassDB::_register_class<T, true>();
|
||||
}
|
||||
|
||||
template <class N, class M, typename... VarArgs>
|
||||
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
|
||||
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
|
||||
const Variant *argptrs[sizeof...(p_args) + 1];
|
||||
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
|
||||
argptrs[i] = &args[i];
|
||||
}
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
|
||||
}
|
||||
|
||||
template <class N, class M, typename... VarArgs>
|
||||
MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args) {
|
||||
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
|
||||
const Variant *argptrs[sizeof...(p_args) + 1];
|
||||
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
|
||||
argptrs[i] = &args[i];
|
||||
}
|
||||
MethodBind *bind = create_static_method_bind(p_method);
|
||||
bind->set_instance_class(p_class);
|
||||
return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
|
||||
}
|
||||
|
||||
template <class M>
|
||||
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) {
|
||||
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
|
||||
ERR_FAIL_NULL_V(bind, nullptr);
|
||||
|
||||
bind->set_name(p_name);
|
||||
bind->set_default_arguments(p_default_args);
|
||||
|
||||
StringName instance_type = bind->get_instance_class();
|
||||
|
||||
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(instance_type);
|
||||
if (type_it == classes.end()) {
|
||||
memdelete(bind);
|
||||
ERR_FAIL_V_MSG(nullptr, String("Class '{0}' doesn't exist.").format(Array::make(instance_type)));
|
||||
}
|
||||
|
||||
ClassInfo &type = type_it->second;
|
||||
|
||||
if (type.method_map.find(p_name) != type.method_map.end()) {
|
||||
memdelete(bind);
|
||||
ERR_FAIL_V_MSG(nullptr, String("Binding duplicate method: {0}::{1}.").format(Array::make(instance_type, p_method)));
|
||||
}
|
||||
|
||||
// register our method bind within our plugin
|
||||
type.method_map[p_name] = bind;
|
||||
|
||||
// and register with godot
|
||||
bind_method_godot(type.name, bind);
|
||||
|
||||
return bind;
|
||||
}
|
||||
|
||||
#define GDREGISTER_CLASS(m_class) ClassDB::register_class<m_class>();
|
||||
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
|
||||
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_CLASS_DB_HPP
|
||||
@@ -1,130 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* defs.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_DEFS_HPP
|
||||
#define GODOT_DEFS_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#if !defined(GDE_EXPORT)
|
||||
#if defined(_WIN32)
|
||||
#define GDE_EXPORT __declspec(dllexport)
|
||||
#elif defined(__GNUC__)
|
||||
#define GDE_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define GDE_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Turn argument to string constant:
|
||||
// https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing
|
||||
#ifndef _STR
|
||||
#define _STR(m_x) #m_x
|
||||
#define _MKSTR(m_x) _STR(m_x)
|
||||
#endif
|
||||
|
||||
// Should always inline no matter what.
|
||||
#ifndef _ALWAYS_INLINE_
|
||||
#if defined(__GNUC__)
|
||||
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
|
||||
#elif defined(_MSC_VER)
|
||||
#define _ALWAYS_INLINE_ __forceinline
|
||||
#else
|
||||
#define _ALWAYS_INLINE_ inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Should always inline, except in debug builds because it makes debugging harder.
|
||||
#ifndef _FORCE_INLINE_
|
||||
#ifdef DISABLE_FORCED_INLINE
|
||||
#define _FORCE_INLINE_ inline
|
||||
#else
|
||||
#define _FORCE_INLINE_ _ALWAYS_INLINE_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _NO_DISCARD_
|
||||
#define _NO_DISCARD_ [[nodiscard]]
|
||||
#endif
|
||||
|
||||
// Windows badly defines a lot of stuff we'll never use. Undefine it.
|
||||
#ifdef _WIN32
|
||||
#undef min // override standard definition
|
||||
#undef max // override standard definition
|
||||
#undef ERROR // override (really stupid) wingdi.h standard definition
|
||||
#undef DELETE // override (another really stupid) winnt.h standard definition
|
||||
#undef MessageBox // override winuser.h standard definition
|
||||
#undef MIN // override standard definition
|
||||
#undef MAX // override standard definition
|
||||
#undef CLAMP // override standard definition
|
||||
#undef Error
|
||||
#undef OK
|
||||
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) x
|
||||
#define unlikely(x) x
|
||||
#endif
|
||||
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
typedef double real_t;
|
||||
#else
|
||||
typedef float real_t;
|
||||
#endif
|
||||
|
||||
// Generic swap template.
|
||||
#ifndef SWAP
|
||||
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
|
||||
template <class T>
|
||||
inline void __swap_tmpl(T &x, T &y) {
|
||||
T aux = x;
|
||||
x = y;
|
||||
y = aux;
|
||||
}
|
||||
#endif // SWAP
|
||||
|
||||
// Home-made index sequence trick, so it can be used everywhere without the costly include of std::tuple.
|
||||
// https://stackoverflow.com/questions/15014096/c-index-of-type-during-variadic-template-expansion
|
||||
template <size_t... Is>
|
||||
struct IndexSequence {};
|
||||
|
||||
template <size_t N, size_t... Is>
|
||||
struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {};
|
||||
|
||||
template <size_t... Is>
|
||||
struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
|
||||
|
||||
#endif // GODOT_DEFS_HPP
|
||||
@@ -1,97 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* engine_ptrcall.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_ENGINE_PTRCALL_HPP
|
||||
#define GODOT_ENGINE_PTRCALL_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <godot_cpp/core/binder_common.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class O, class... Args>
|
||||
O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
|
||||
GodotObject *ret = nullptr;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
|
||||
if (ret == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
|
||||
}
|
||||
|
||||
template <class R, class... Args>
|
||||
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
|
||||
R ret;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr);
|
||||
}
|
||||
|
||||
template <class R, class... Args>
|
||||
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
|
||||
R ret;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
func(&ret, mb_args.data(), mb_args.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, void *instance, const Args &...args) {
|
||||
GodotObject *ret = nullptr;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
func(&ret, mb_args.data(), mb_args.size());
|
||||
return (Object *)internal::get_object_instance_binding(ret);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &...args) {
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
func(nullptr, mb_args.data(), mb_args.size());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_ENGINE_PTRCALL_HPP
|
||||
@@ -1,806 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* error_macros.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_ERROR_MACROS_HPP
|
||||
#define GODOT_ERROR_MACROS_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, bool p_is_warning = false);
|
||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool p_fatal = false);
|
||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool p_fatal = false);
|
||||
void _err_flush_stdout();
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define FUNCTION_STR __FUNCTION__
|
||||
#else
|
||||
#define FUNCTION_STR __FUNCTION__
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/**
|
||||
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
|
||||
*/
|
||||
#define GENERATE_TRAP() __debugbreak()
|
||||
#else
|
||||
/**
|
||||
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
|
||||
*/
|
||||
#define GENERATE_TRAP() __builtin_trap()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Error macros.
|
||||
* WARNING: These macros work in the opposite way to assert().
|
||||
*
|
||||
* Unlike exceptions and asserts, these macros try to maintain consistency and stability.
|
||||
* In most cases, bugs and/or invalid data are not fatal. They should never allow a perfectly
|
||||
* running application to fail or crash.
|
||||
* Always try to return processable data, so the engine can keep running well.
|
||||
* Use the _MSG versions to print a meaningful message to help with debugging.
|
||||
*
|
||||
* The `((void)0)` no-op statement is used as a trick to force us to put a semicolon after
|
||||
* those macros, making them look like proper statements.
|
||||
* The if wrappers are used to ensure that the macro replacement does not trigger unexpected
|
||||
* issues when expanded e.g. after an `if (cond) ERR_FAIL();` without braces.
|
||||
*/
|
||||
|
||||
// Index out of bounds error macros.
|
||||
// These macros should be used instead of `ERR_FAIL_COND` for bounds checking.
|
||||
|
||||
// Integer index out of bounds error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
|
||||
* If not, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Unsigned integer index out of bounds error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures an unsigned integer index `m_index` is less than `m_size`.
|
||||
* If not, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
|
||||
if (unlikely((m_index) >= (m_size))) { \
|
||||
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Null reference error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_NULL_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_NULL(m_param) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, prints `m_msg` and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_NULL_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V(m_param, m_retval) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures a pointer `m_param` is not null.
|
||||
* If it is null, prints `m_msg` and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
|
||||
if (unlikely(m_param == nullptr)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
* If checking for null use ERR_FAIL_NULL_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_COND(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current function returns.
|
||||
*
|
||||
* If checking for null use ERR_FAIL_NULL_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
|
||||
*/
|
||||
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V(m_cond, m_retval) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current function returns `m_retval`.
|
||||
*
|
||||
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
|
||||
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_CONTINUE_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current loop continues.
|
||||
*/
|
||||
#define ERR_CONTINUE(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current loop continues.
|
||||
*/
|
||||
#define ERR_CONTINUE_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_CONTINUE_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \
|
||||
continue; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_BREAK_MSG`.
|
||||
* Only use this macro if there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the current loop breaks.
|
||||
*/
|
||||
#define ERR_BREAK(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the current loop breaks.
|
||||
*/
|
||||
#define ERR_BREAK_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_BREAK_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \
|
||||
break; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, the application crashes.
|
||||
*/
|
||||
#define CRASH_COND(m_cond) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
|
||||
*
|
||||
* Ensures `m_cond` is false.
|
||||
* If `m_cond` is true, prints `m_msg` and the application crashes.
|
||||
*/
|
||||
#define CRASH_COND_MSG(m_cond, m_msg) \
|
||||
if (unlikely(m_cond)) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Generic error macros.
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* The current function returns.
|
||||
*/
|
||||
#define ERR_FAIL() \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`, and the current function returns.
|
||||
*/
|
||||
#define ERR_FAIL_MSG(m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_EDMSG(m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required, and
|
||||
* there is no sensible error message.
|
||||
*
|
||||
* The current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_V(m_retval) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_V_MSG`.
|
||||
* Only use this macro if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`, and the current function returns `m_retval`.
|
||||
*/
|
||||
#define ERR_FAIL_V_MSG(m_retval, m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_FAIL_V_MSG` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \
|
||||
return m_retval; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
|
||||
* Only use this macro at the start of a function that has not been implemented yet, or
|
||||
* if more complex error detection or recovery is required.
|
||||
*
|
||||
* Prints `m_msg`.
|
||||
*/
|
||||
#define ERR_PRINT(m_msg) \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
|
||||
|
||||
/**
|
||||
* Same as `ERR_PRINT` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_PRINT_ED(m_msg) \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
|
||||
|
||||
/**
|
||||
* Prints `m_msg` once during the application lifetime.
|
||||
*/
|
||||
#define ERR_PRINT_ONCE(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `ERR_PRINT_ONCE` but also notifies the editor.
|
||||
*/
|
||||
#define ERR_PRINT_ONCE_ED(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Print warning message macros.
|
||||
|
||||
/**
|
||||
* Prints `m_msg`.
|
||||
*
|
||||
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
|
||||
*/
|
||||
#define WARN_PRINT(m_msg) \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, true)
|
||||
|
||||
/**
|
||||
* Same as `WARN_PRINT` but also notifies the editor.
|
||||
*/
|
||||
#define WARN_PRINT_ED(m_msg) \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, true)
|
||||
|
||||
/**
|
||||
* Prints `m_msg` once during the application lifetime.
|
||||
*
|
||||
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
|
||||
*/
|
||||
#define WARN_PRINT_ONCE(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, true); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Same as `WARN_PRINT_ONCE` but also notifies the editor.
|
||||
*/
|
||||
#define WARN_PRINT_ONCE_ED(m_msg) \
|
||||
if (true) { \
|
||||
static bool first_print = true; \
|
||||
if (first_print) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, true); \
|
||||
first_print = false; \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
// Print deprecated warning message macros.
|
||||
|
||||
/**
|
||||
* Warns that the current function is deprecated.
|
||||
*/
|
||||
#define WARN_DEPRECATED \
|
||||
if (true) { \
|
||||
static std::atomic<bool> warning_shown; \
|
||||
if (!warning_shown.load()) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, true); \
|
||||
warning_shown.store(true); \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Warns that the current function is deprecated and prints `m_msg`.
|
||||
*/
|
||||
#define WARN_DEPRECATED_MSG(m_msg) \
|
||||
if (true) { \
|
||||
static std::atomic<bool> warning_shown; \
|
||||
if (!warning_shown.load()) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, true); \
|
||||
warning_shown.store(true); \
|
||||
} \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Do not use.
|
||||
* If the application should never reach this point use CRASH_NOW_MSG(m_msg) to explain why.
|
||||
*
|
||||
* The application crashes.
|
||||
*/
|
||||
#define CRASH_NOW() \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* Only use if the application should never reach this point.
|
||||
*
|
||||
* Prints `m_msg`, and then the application crashes.
|
||||
*/
|
||||
#define CRASH_NOW_MSG(m_msg) \
|
||||
if (true) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
/**
|
||||
* This should be a 'free' assert for program flow and should not be needed in any releases,
|
||||
* only used in dev builds.
|
||||
*/
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define DEV_ASSERT(m_cond) \
|
||||
if (unlikely(!(m_cond))) { \
|
||||
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
|
||||
::godot::_err_flush_stdout(); \
|
||||
GENERATE_TRAP(); \
|
||||
} else \
|
||||
((void)0)
|
||||
#else
|
||||
#define DEV_ASSERT(m_cond)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gives an error message when a method bind is invalid (likely the hash changed).
|
||||
* Avoids crashing the application in this case. It's not free, so it's debug only.
|
||||
*/
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define CHECK_METHOD_BIND_RET(m_mb, m_ret) \
|
||||
if (unlikely(!m_mb)) { \
|
||||
ERR_PRINT_ONCE("Method bind was not found. Likely the engine method changed to an incompatible version."); \
|
||||
return m_ret; \
|
||||
} else \
|
||||
((void)0)
|
||||
|
||||
#define CHECK_METHOD_BIND(m_mb) \
|
||||
if (unlikely(!m_mb)) { \
|
||||
ERR_PRINT_ONCE("Method bind was not found. Likely the engine method changed to an incompatible version."); \
|
||||
return; \
|
||||
} else \
|
||||
((void)0)
|
||||
#else
|
||||
#define CHECK_METHOD_BIND_RET(m_mb, m_ret)
|
||||
#define CHECK_METHOD_BIND(m_mb)
|
||||
#endif
|
||||
|
||||
#endif // GODOT_ERROR_MACROS_HPP
|
||||
@@ -1,811 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* math.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_MATH_HPP
|
||||
#define GODOT_MATH_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace godot {
|
||||
|
||||
#define Math_SQRT12 0.7071067811865475244008443621048490
|
||||
#define Math_SQRT2 1.4142135623730950488016887242
|
||||
#define Math_LN2 0.6931471805599453094172321215
|
||||
#define Math_PI 3.1415926535897932384626433833
|
||||
#define Math_TAU 6.2831853071795864769252867666
|
||||
#define Math_E 2.7182818284590452353602874714
|
||||
#define Math_INF INFINITY
|
||||
#define Math_NAN NAN
|
||||
|
||||
// Make room for our constexpr's below by overriding potential system-specific macros.
|
||||
#undef ABS
|
||||
#undef SIGN
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#undef CLAMP
|
||||
|
||||
// Generic ABS function, for math uses please use Math::abs.
|
||||
template <typename T>
|
||||
constexpr T ABS(T m_v) {
|
||||
return m_v < 0 ? -m_v : m_v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr const T SIGN(const T m_v) {
|
||||
return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f);
|
||||
}
|
||||
|
||||
template <typename T, typename T2>
|
||||
constexpr auto MIN(const T m_a, const T2 m_b) {
|
||||
return m_a < m_b ? m_a : m_b;
|
||||
}
|
||||
|
||||
template <typename T, typename T2>
|
||||
constexpr auto MAX(const T m_a, const T2 m_b) {
|
||||
return m_a > m_b ? m_a : m_b;
|
||||
}
|
||||
|
||||
template <typename T, typename T2, typename T3>
|
||||
constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
|
||||
return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a);
|
||||
}
|
||||
|
||||
// Generic swap template.
|
||||
#ifndef SWAP
|
||||
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
|
||||
template <class T>
|
||||
inline void __swap_tmpl(T &x, T &y) {
|
||||
T aux = x;
|
||||
x = y;
|
||||
y = aux;
|
||||
}
|
||||
#endif // SWAP
|
||||
|
||||
/* Functions to handle powers of 2 and shifting. */
|
||||
|
||||
// Function to find the next power of 2 to an integer.
|
||||
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
|
||||
if (x == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
--x;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
|
||||
return ++x;
|
||||
}
|
||||
|
||||
// Function to find the previous power of 2 to an integer.
|
||||
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return x - (x >> 1);
|
||||
}
|
||||
|
||||
// Function to find the closest power of 2 to an integer.
|
||||
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
|
||||
unsigned int nx = next_power_of_2(x);
|
||||
unsigned int px = previous_power_of_2(x);
|
||||
return (nx - x) > (x - px) ? px : nx;
|
||||
}
|
||||
|
||||
// Get a shift value from a power of 2.
|
||||
static inline int get_shift_from_power_of_2(unsigned int p_bits) {
|
||||
for (unsigned int i = 0; i < 32; i++) {
|
||||
if (p_bits == (unsigned int)(1 << i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
|
||||
--x;
|
||||
|
||||
// The number of operations on x is the base two logarithm
|
||||
// of the number of bits in the type. Add three to account
|
||||
// for sizeof(T) being in bytes.
|
||||
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
|
||||
|
||||
// If the compiler is smart, it unrolls this loop.
|
||||
// If it's dumb, this is a bit slow.
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
x |= x >> (1 << i);
|
||||
}
|
||||
|
||||
return ++x;
|
||||
}
|
||||
|
||||
// Function to find the nearest (bigger) power of 2 to an integer.
|
||||
static inline unsigned int nearest_shift(unsigned int p_number) {
|
||||
for (int i = 30; i >= 0; i--) {
|
||||
if (p_number & (1 << i)) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// constexpr function to find the floored log2 of a number
|
||||
template <typename T>
|
||||
constexpr T floor_log2(T x) {
|
||||
return x < 2 ? x : 1 + floor_log2(x >> 1);
|
||||
}
|
||||
|
||||
// Get the number of bits needed to represent the number.
|
||||
// IE, if you pass in 8, you will get 4.
|
||||
// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1).
|
||||
template <typename T>
|
||||
constexpr T get_num_bits(T x) {
|
||||
return floor_log2(x);
|
||||
}
|
||||
|
||||
// Swap 16, 32 and 64 bits value for endianness.
|
||||
#if defined(__GNUC__)
|
||||
#define BSWAP16(x) __builtin_bswap16(x)
|
||||
#define BSWAP32(x) __builtin_bswap32(x)
|
||||
#define BSWAP64(x) __builtin_bswap64(x)
|
||||
#else
|
||||
static inline uint16_t BSWAP16(uint16_t x) {
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
static inline uint32_t BSWAP32(uint32_t x) {
|
||||
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
|
||||
}
|
||||
|
||||
static inline uint64_t BSWAP64(uint64_t x) {
|
||||
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
|
||||
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
|
||||
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Math {
|
||||
|
||||
// This epsilon should match the one used by Godot for consistency.
|
||||
// Using `f` when `real_t` is float.
|
||||
#define CMP_EPSILON 0.00001f
|
||||
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
|
||||
|
||||
// This epsilon is for values related to a unit size (scalar or vector len).
|
||||
#ifdef PRECISE_MATH_CHECKS
|
||||
#define UNIT_EPSILON 0.00001
|
||||
#else
|
||||
// Tolerate some more floating point error normally.
|
||||
#define UNIT_EPSILON 0.001
|
||||
#endif
|
||||
|
||||
// Functions reproduced as in Godot's source code `math_funcs.h`.
|
||||
// Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
|
||||
|
||||
inline double fmod(double p_x, double p_y) {
|
||||
return ::fmod(p_x, p_y);
|
||||
}
|
||||
inline float fmod(float p_x, float p_y) {
|
||||
return ::fmodf(p_x, p_y);
|
||||
}
|
||||
|
||||
inline double fposmod(double p_x, double p_y) {
|
||||
double value = Math::fmod(p_x, p_y);
|
||||
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
|
||||
value += p_y;
|
||||
}
|
||||
value += 0.0;
|
||||
return value;
|
||||
}
|
||||
inline float fposmod(float p_x, float p_y) {
|
||||
float value = Math::fmod(p_x, p_y);
|
||||
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
|
||||
value += p_y;
|
||||
}
|
||||
value += 0.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline float fposmodp(float p_x, float p_y) {
|
||||
float value = Math::fmod(p_x, p_y);
|
||||
if (value < 0) {
|
||||
value += p_y;
|
||||
}
|
||||
value += 0.0f;
|
||||
return value;
|
||||
}
|
||||
inline double fposmodp(double p_x, double p_y) {
|
||||
double value = Math::fmod(p_x, p_y);
|
||||
if (value < 0) {
|
||||
value += p_y;
|
||||
}
|
||||
value += 0.0;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline int64_t posmod(int64_t p_x, int64_t p_y) {
|
||||
int64_t value = p_x % p_y;
|
||||
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
|
||||
value += p_y;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
inline double floor(double p_x) {
|
||||
return ::floor(p_x);
|
||||
}
|
||||
inline float floor(float p_x) {
|
||||
return ::floorf(p_x);
|
||||
}
|
||||
|
||||
inline double ceil(double p_x) {
|
||||
return ::ceil(p_x);
|
||||
}
|
||||
inline float ceil(float p_x) {
|
||||
return ::ceilf(p_x);
|
||||
}
|
||||
|
||||
inline double exp(double p_x) {
|
||||
return ::exp(p_x);
|
||||
}
|
||||
inline float exp(float p_x) {
|
||||
return ::expf(p_x);
|
||||
}
|
||||
|
||||
inline double sin(double p_x) {
|
||||
return ::sin(p_x);
|
||||
}
|
||||
inline float sin(float p_x) {
|
||||
return ::sinf(p_x);
|
||||
}
|
||||
|
||||
inline double cos(double p_x) {
|
||||
return ::cos(p_x);
|
||||
}
|
||||
inline float cos(float p_x) {
|
||||
return ::cosf(p_x);
|
||||
}
|
||||
|
||||
inline double tan(double p_x) {
|
||||
return ::tan(p_x);
|
||||
}
|
||||
inline float tan(float p_x) {
|
||||
return ::tanf(p_x);
|
||||
}
|
||||
|
||||
inline double sinh(double p_x) {
|
||||
return ::sinh(p_x);
|
||||
}
|
||||
inline float sinh(float p_x) {
|
||||
return ::sinhf(p_x);
|
||||
}
|
||||
|
||||
inline float sinc(float p_x) {
|
||||
return p_x == 0 ? 1 : ::sin(p_x) / p_x;
|
||||
}
|
||||
inline double sinc(double p_x) {
|
||||
return p_x == 0 ? 1 : ::sin(p_x) / p_x;
|
||||
}
|
||||
|
||||
inline float sincn(float p_x) {
|
||||
return (float)sinc(Math_PI * p_x);
|
||||
}
|
||||
inline double sincn(double p_x) {
|
||||
return sinc(Math_PI * p_x);
|
||||
}
|
||||
|
||||
inline double cosh(double p_x) {
|
||||
return ::cosh(p_x);
|
||||
}
|
||||
inline float cosh(float p_x) {
|
||||
return ::coshf(p_x);
|
||||
}
|
||||
|
||||
inline double tanh(double p_x) {
|
||||
return ::tanh(p_x);
|
||||
}
|
||||
inline float tanh(float p_x) {
|
||||
return ::tanhf(p_x);
|
||||
}
|
||||
|
||||
inline double asin(double p_x) {
|
||||
return ::asin(p_x);
|
||||
}
|
||||
inline float asin(float p_x) {
|
||||
return ::asinf(p_x);
|
||||
}
|
||||
|
||||
inline double acos(double p_x) {
|
||||
return ::acos(p_x);
|
||||
}
|
||||
inline float acos(float p_x) {
|
||||
return ::acosf(p_x);
|
||||
}
|
||||
|
||||
inline double atan(double p_x) {
|
||||
return ::atan(p_x);
|
||||
}
|
||||
inline float atan(float p_x) {
|
||||
return ::atanf(p_x);
|
||||
}
|
||||
|
||||
inline double atan2(double p_y, double p_x) {
|
||||
return ::atan2(p_y, p_x);
|
||||
}
|
||||
inline float atan2(float p_y, float p_x) {
|
||||
return ::atan2f(p_y, p_x);
|
||||
}
|
||||
|
||||
inline double sqrt(double p_x) {
|
||||
return ::sqrt(p_x);
|
||||
}
|
||||
inline float sqrt(float p_x) {
|
||||
return ::sqrtf(p_x);
|
||||
}
|
||||
|
||||
inline double pow(double p_x, double p_y) {
|
||||
return ::pow(p_x, p_y);
|
||||
}
|
||||
inline float pow(float p_x, float p_y) {
|
||||
return ::powf(p_x, p_y);
|
||||
}
|
||||
|
||||
inline double log(double p_x) {
|
||||
return ::log(p_x);
|
||||
}
|
||||
inline float log(float p_x) {
|
||||
return ::logf(p_x);
|
||||
}
|
||||
|
||||
inline float lerp(float minv, float maxv, float t) {
|
||||
return minv + t * (maxv - minv);
|
||||
}
|
||||
inline double lerp(double minv, double maxv, double t) {
|
||||
return minv + t * (maxv - minv);
|
||||
}
|
||||
|
||||
inline double lerp_angle(double p_from, double p_to, double p_weight) {
|
||||
double difference = fmod(p_to - p_from, Math_TAU);
|
||||
double distance = fmod(2.0 * difference, Math_TAU) - difference;
|
||||
return p_from + distance * p_weight;
|
||||
}
|
||||
inline float lerp_angle(float p_from, float p_to, float p_weight) {
|
||||
float difference = fmod(p_to - p_from, (float)Math_TAU);
|
||||
float distance = fmod(2.0f * difference, (float)Math_TAU) - difference;
|
||||
return p_from + distance * p_weight;
|
||||
}
|
||||
|
||||
inline double cubic_interpolate(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
|
||||
return 0.5 *
|
||||
((p_from * 2.0) +
|
||||
(-p_pre + p_to) * p_weight +
|
||||
(2.0 * p_pre - 5.0 * p_from + 4.0 * p_to - p_post) * (p_weight * p_weight) +
|
||||
(-p_pre + 3.0 * p_from - 3.0 * p_to + p_post) * (p_weight * p_weight * p_weight));
|
||||
}
|
||||
|
||||
inline float cubic_interpolate(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
|
||||
return 0.5f *
|
||||
((p_from * 2.0f) +
|
||||
(-p_pre + p_to) * p_weight +
|
||||
(2.0f * p_pre - 5.0f * p_from + 4.0f * p_to - p_post) * (p_weight * p_weight) +
|
||||
(-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight));
|
||||
}
|
||||
|
||||
inline double cubic_interpolate_angle(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
|
||||
double from_rot = fmod(p_from, Math_TAU);
|
||||
|
||||
double pre_diff = fmod(p_pre - from_rot, Math_TAU);
|
||||
double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
|
||||
|
||||
double to_diff = fmod(p_to - from_rot, Math_TAU);
|
||||
double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
|
||||
|
||||
double post_diff = fmod(p_post - to_rot, Math_TAU);
|
||||
double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
|
||||
}
|
||||
|
||||
inline float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
|
||||
float from_rot = fmod(p_from, (float)Math_TAU);
|
||||
|
||||
float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
|
||||
float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
|
||||
|
||||
float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
|
||||
float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
|
||||
|
||||
float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
|
||||
float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
|
||||
}
|
||||
|
||||
inline double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
|
||||
double p_to_t, double p_pre_t, double p_post_t) {
|
||||
/* Barry-Goldman method */
|
||||
double t = Math::lerp(0.0, p_to_t, p_weight);
|
||||
double a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0 : (t - p_pre_t) / -p_pre_t);
|
||||
double a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5 : t / p_to_t);
|
||||
double a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0 : (t - p_to_t) / (p_post_t - p_to_t));
|
||||
double b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0 : (t - p_pre_t) / (p_to_t - p_pre_t));
|
||||
double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t);
|
||||
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t);
|
||||
}
|
||||
|
||||
inline float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
|
||||
float p_to_t, float p_pre_t, float p_post_t) {
|
||||
/* Barry-Goldman method */
|
||||
float t = Math::lerp(0.0f, p_to_t, p_weight);
|
||||
float a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0f : (t - p_pre_t) / -p_pre_t);
|
||||
float a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5f : t / p_to_t);
|
||||
float a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0f : (t - p_to_t) / (p_post_t - p_to_t));
|
||||
float b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0f : (t - p_pre_t) / (p_to_t - p_pre_t));
|
||||
float b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0f : t / p_post_t);
|
||||
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t);
|
||||
}
|
||||
|
||||
inline double cubic_interpolate_angle_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
|
||||
double p_to_t, double p_pre_t, double p_post_t) {
|
||||
double from_rot = fmod(p_from, Math_TAU);
|
||||
|
||||
double pre_diff = fmod(p_pre - from_rot, Math_TAU);
|
||||
double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
|
||||
|
||||
double to_diff = fmod(p_to - from_rot, Math_TAU);
|
||||
double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
|
||||
|
||||
double post_diff = fmod(p_post - to_rot, Math_TAU);
|
||||
double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
|
||||
}
|
||||
|
||||
inline float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
|
||||
float p_to_t, float p_pre_t, float p_post_t) {
|
||||
float from_rot = fmod(p_from, (float)Math_TAU);
|
||||
|
||||
float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
|
||||
float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
|
||||
|
||||
float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
|
||||
float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
|
||||
|
||||
float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
|
||||
float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
|
||||
}
|
||||
|
||||
inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
|
||||
/* Formula from Wikipedia article on Bezier curves. */
|
||||
double omt = (1.0 - p_t);
|
||||
double omt2 = omt * omt;
|
||||
double omt3 = omt2 * omt;
|
||||
double t2 = p_t * p_t;
|
||||
double t3 = t2 * p_t;
|
||||
|
||||
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
|
||||
}
|
||||
|
||||
inline float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
|
||||
/* Formula from Wikipedia article on Bezier curves. */
|
||||
float omt = (1.0f - p_t);
|
||||
float omt2 = omt * omt;
|
||||
float omt3 = omt2 * omt;
|
||||
float t2 = p_t * p_t;
|
||||
float t3 = t2 * p_t;
|
||||
|
||||
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T clamp(T x, T minv, T maxv) {
|
||||
if (x < minv) {
|
||||
return minv;
|
||||
}
|
||||
if (x > maxv) {
|
||||
return maxv;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T min(T a, T b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T max(T a, T b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T sign(T x) {
|
||||
return static_cast<T>(SIGN(x));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T abs(T x) {
|
||||
return std::abs(x);
|
||||
}
|
||||
|
||||
inline double deg_to_rad(double p_y) {
|
||||
return p_y * Math_PI / 180.0;
|
||||
}
|
||||
inline float deg_to_rad(float p_y) {
|
||||
return p_y * static_cast<float>(Math_PI) / 180.f;
|
||||
}
|
||||
|
||||
inline double rad_to_deg(double p_y) {
|
||||
return p_y * 180.0 / Math_PI;
|
||||
}
|
||||
inline float rad_to_deg(float p_y) {
|
||||
return p_y * 180.f / static_cast<float>(Math_PI);
|
||||
}
|
||||
|
||||
inline double inverse_lerp(double p_from, double p_to, double p_value) {
|
||||
return (p_value - p_from) / (p_to - p_from);
|
||||
}
|
||||
inline float inverse_lerp(float p_from, float p_to, float p_value) {
|
||||
return (p_value - p_from) / (p_to - p_from);
|
||||
}
|
||||
|
||||
inline double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
|
||||
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
|
||||
}
|
||||
inline float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
|
||||
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
|
||||
}
|
||||
|
||||
inline bool is_nan(float p_val) {
|
||||
return std::isnan(p_val);
|
||||
}
|
||||
|
||||
inline bool is_nan(double p_val) {
|
||||
return std::isnan(p_val);
|
||||
}
|
||||
|
||||
inline bool is_inf(float p_val) {
|
||||
return std::isinf(p_val);
|
||||
}
|
||||
|
||||
inline bool is_inf(double p_val) {
|
||||
return std::isinf(p_val);
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(float a, float b) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
float tolerance = (float)CMP_EPSILON * abs(a);
|
||||
if (tolerance < (float)CMP_EPSILON) {
|
||||
tolerance = (float)CMP_EPSILON;
|
||||
}
|
||||
return abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(float a, float b, float tolerance) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
return abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_zero_approx(float s) {
|
||||
return abs(s) < (float)CMP_EPSILON;
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(double a, double b) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
double tolerance = CMP_EPSILON * abs(a);
|
||||
if (tolerance < CMP_EPSILON) {
|
||||
tolerance = CMP_EPSILON;
|
||||
}
|
||||
return abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_equal_approx(double a, double b, double tolerance) {
|
||||
// Check for exact equality first, required to handle "infinity" values.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
// Then check for approximate equality.
|
||||
return abs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
inline bool is_zero_approx(double s) {
|
||||
return abs(s) < CMP_EPSILON;
|
||||
}
|
||||
|
||||
inline float absf(float g) {
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
|
||||
u.f = g;
|
||||
u.i &= 2147483647u;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
inline double absd(double g) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = g;
|
||||
u.i &= (uint64_t)9223372036854775807ull;
|
||||
return u.d;
|
||||
}
|
||||
|
||||
inline double smoothstep(double p_from, double p_to, double p_weight) {
|
||||
if (is_equal_approx(static_cast<real_t>(p_from), static_cast<real_t>(p_to))) {
|
||||
return p_from;
|
||||
}
|
||||
double x = clamp((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
|
||||
return x * x * (3.0 - 2.0 * x);
|
||||
}
|
||||
inline float smoothstep(float p_from, float p_to, float p_weight) {
|
||||
if (is_equal_approx(p_from, p_to)) {
|
||||
return p_from;
|
||||
}
|
||||
float x = clamp((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
|
||||
return x * x * (3.0f - 2.0f * x);
|
||||
}
|
||||
|
||||
inline double move_toward(double p_from, double p_to, double p_delta) {
|
||||
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
|
||||
}
|
||||
|
||||
inline float move_toward(float p_from, float p_to, float p_delta) {
|
||||
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
|
||||
}
|
||||
|
||||
inline double linear2db(double p_linear) {
|
||||
return log(p_linear) * 8.6858896380650365530225783783321;
|
||||
}
|
||||
inline float linear2db(float p_linear) {
|
||||
return log(p_linear) * 8.6858896380650365530225783783321f;
|
||||
}
|
||||
|
||||
inline double db2linear(double p_db) {
|
||||
return exp(p_db * 0.11512925464970228420089957273422);
|
||||
}
|
||||
inline float db2linear(float p_db) {
|
||||
return exp(p_db * 0.11512925464970228420089957273422f);
|
||||
}
|
||||
|
||||
inline double round(double p_val) {
|
||||
return (p_val >= 0) ? floor(p_val + 0.5) : -floor(-p_val + 0.5);
|
||||
}
|
||||
inline float round(float p_val) {
|
||||
return (p_val >= 0) ? floor(p_val + 0.5f) : -floor(-p_val + 0.5f);
|
||||
}
|
||||
|
||||
inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
|
||||
int64_t range = max - min;
|
||||
return range == 0 ? min : min + ((((value - min) % range) + range) % range);
|
||||
}
|
||||
|
||||
inline float wrapf(real_t value, real_t min, real_t max) {
|
||||
const real_t range = max - min;
|
||||
return is_zero_approx(range) ? min : value - (range * floor((value - min) / range));
|
||||
}
|
||||
|
||||
inline float fract(float value) {
|
||||
return value - floor(value);
|
||||
}
|
||||
|
||||
inline double fract(double value) {
|
||||
return value - floor(value);
|
||||
}
|
||||
|
||||
inline float pingpong(float value, float length) {
|
||||
return (length != 0.0f) ? abs(fract((value - length) / (length * 2.0f)) * length * 2.0f - length) : 0.0f;
|
||||
}
|
||||
|
||||
inline double pingpong(double value, double length) {
|
||||
return (length != 0.0) ? abs(fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0;
|
||||
}
|
||||
|
||||
// This function should be as fast as possible and rounding mode should not matter.
|
||||
inline int fast_ftoi(float a) {
|
||||
static int b;
|
||||
|
||||
#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0603) || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // windows 8 phone?
|
||||
b = (int)((a > 0.0) ? (a + 0.5) : (a - 0.5));
|
||||
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1800
|
||||
__asm fld a __asm fistp b
|
||||
/*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
|
||||
// use AT&T inline assembly style, document that
|
||||
// we use memory as output (=m) and input (m)
|
||||
__asm__ __volatile__ (
|
||||
"flds %1 \n\t"
|
||||
"fistpl %0 \n\t"
|
||||
: "=m" (b)
|
||||
: "m" (a));*/
|
||||
|
||||
#else
|
||||
b = lrintf(a); // assuming everything but msvc 2012 or earlier has lrint
|
||||
#endif
|
||||
return b;
|
||||
}
|
||||
|
||||
inline double snapped(double p_value, double p_step) {
|
||||
if (p_step != 0) {
|
||||
p_value = Math::floor(p_value / p_step + 0.5) * p_step;
|
||||
}
|
||||
return p_value;
|
||||
}
|
||||
|
||||
inline float snap_scalar(float p_offset, float p_step, float p_target) {
|
||||
return p_step != 0 ? Math::snapped(p_target - p_offset, p_step) + p_offset : p_target;
|
||||
}
|
||||
|
||||
inline float snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) {
|
||||
if (p_step != 0) {
|
||||
float a = Math::snapped(p_target - p_offset, p_step + p_separation) + p_offset;
|
||||
float b = a;
|
||||
if (p_target >= 0) {
|
||||
b -= p_separation;
|
||||
} else {
|
||||
b += p_step;
|
||||
}
|
||||
return (Math::abs(p_target - a) < Math::abs(p_target - b)) ? a : b;
|
||||
}
|
||||
return p_target;
|
||||
}
|
||||
|
||||
} // namespace Math
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_MATH_HPP
|
||||
@@ -1,194 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* memory.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_MEMORY_HPP
|
||||
#define GODOT_MEMORY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef PAD_ALIGN
|
||||
#define PAD_ALIGN 16 //must always be greater than this at much
|
||||
#endif
|
||||
|
||||
void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
|
||||
void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
|
||||
void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
|
||||
|
||||
_ALWAYS_INLINE_ void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description) {
|
||||
return p_pointer;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291).
|
||||
// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete.
|
||||
void operator delete(void *p_mem, const char *p_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 {
|
||||
|
||||
class Wrapped;
|
||||
|
||||
class Memory {
|
||||
Memory();
|
||||
|
||||
public:
|
||||
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
|
||||
static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
|
||||
static void free_static(void *p_ptr, bool p_pad_align = false);
|
||||
};
|
||||
|
||||
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
|
||||
|
||||
template <class T>
|
||||
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
|
||||
postinitialize_handler(p_obj);
|
||||
return p_obj;
|
||||
}
|
||||
|
||||
#define memalloc(m_size) ::godot::Memory::alloc_static(m_size)
|
||||
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
|
||||
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
|
||||
|
||||
#define memnew(m_class) ::godot::_post_initialize(new ("") m_class)
|
||||
|
||||
#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new (m_allocator::alloc) m_class)
|
||||
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new (m_placement, sizeof(m_class), "") m_class)
|
||||
|
||||
// Generic comparator used in Map, List, etc.
|
||||
template <class T>
|
||||
struct Comparator {
|
||||
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) {
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
p_class->~T();
|
||||
}
|
||||
|
||||
Memory::free_static(p_class);
|
||||
}
|
||||
|
||||
template <class T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
|
||||
void memdelete(T *p_class) {
|
||||
godot::internal::gdextension_interface_object_destroy(p_class->_owner);
|
||||
}
|
||||
|
||||
template <class T, class A>
|
||||
void memdelete_allocator(T *p_class) {
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
p_class->~T();
|
||||
}
|
||||
|
||||
A::free(p_class);
|
||||
}
|
||||
|
||||
class DefaultAllocator {
|
||||
public:
|
||||
_ALWAYS_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory); }
|
||||
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DefaultTypedAllocator {
|
||||
public:
|
||||
template <class... Args>
|
||||
_ALWAYS_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
|
||||
_ALWAYS_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
|
||||
};
|
||||
|
||||
#define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
|
||||
|
||||
template <typename T>
|
||||
T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
|
||||
if (p_elements == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
/** overloading operator new[] cannot be done , because it may not return the real allocated address (it may pad the 'element count' before the actual array). Because of that, it must be done by hand. This is the
|
||||
same strategy used by std::vector, and the Vector class, so it should be safe.*/
|
||||
|
||||
size_t len = sizeof(T) * p_elements;
|
||||
uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true);
|
||||
T *failptr = nullptr; // Get rid of a warning.
|
||||
ERR_FAIL_NULL_V(mem, failptr);
|
||||
*(mem - 1) = p_elements;
|
||||
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
T *elems = (T *)mem;
|
||||
|
||||
/* call operator new */
|
||||
for (size_t i = 0; i < p_elements; i++) {
|
||||
new (&elems[i], sizeof(T), p_descr) T;
|
||||
}
|
||||
}
|
||||
|
||||
return (T *)mem;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void memdelete_arr(T *p_class) {
|
||||
uint64_t *ptr = (uint64_t *)p_class;
|
||||
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
uint64_t elem_count = *(ptr - 1);
|
||||
|
||||
for (uint64_t i = 0; i < elem_count; i++) {
|
||||
p_class[i].~T();
|
||||
}
|
||||
}
|
||||
|
||||
Memory::free_static(ptr, true);
|
||||
}
|
||||
|
||||
struct _GlobalNil {
|
||||
int color = 1;
|
||||
_GlobalNil *right;
|
||||
_GlobalNil *left;
|
||||
_GlobalNil *parent;
|
||||
|
||||
_GlobalNil();
|
||||
};
|
||||
|
||||
struct _GlobalNilClass {
|
||||
static _GlobalNil _nil;
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_MEMORY_HPP
|
||||
@@ -1,733 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* method_bind.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_METHOD_BIND_HPP
|
||||
#define GODOT_METHOD_BIND_HPP
|
||||
|
||||
#include <godot_cpp/core/binder_common.hpp>
|
||||
#include <godot_cpp/core/type_info.hpp>
|
||||
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class MethodBind {
|
||||
StringName name;
|
||||
StringName instance_class;
|
||||
int argument_count = 0;
|
||||
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
|
||||
|
||||
bool _static = false;
|
||||
bool _is_const = false;
|
||||
bool _has_return = false;
|
||||
bool _vararg = false;
|
||||
|
||||
std::vector<StringName> argument_names;
|
||||
GDExtensionVariantType *argument_types = nullptr;
|
||||
std::vector<Variant> default_arguments;
|
||||
|
||||
protected:
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const = 0;
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const = 0;
|
||||
void generate_argument_types(int p_count);
|
||||
void set_const(bool p_const);
|
||||
void set_return(bool p_return);
|
||||
void set_static(bool p_static);
|
||||
void set_vararg(bool p_vararg);
|
||||
void set_argument_count(int p_count);
|
||||
|
||||
public:
|
||||
StringName get_name() const;
|
||||
void set_name(const StringName &p_name);
|
||||
_FORCE_INLINE_ int get_default_argument_count() const { return (int)default_arguments.size(); }
|
||||
_FORCE_INLINE_ const std::vector<Variant> &get_default_arguments() const { return default_arguments; }
|
||||
_FORCE_INLINE_ Variant has_default_argument(int p_arg) const {
|
||||
const int num_default_args = (int)(default_arguments.size());
|
||||
const int idx = p_arg - (argument_count - num_default_args);
|
||||
|
||||
if (idx < 0 || idx >= num_default_args) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ Variant get_default_argument(int p_arg) const {
|
||||
const int num_default_args = (int)(default_arguments.size());
|
||||
const int idx = p_arg - (argument_count - num_default_args);
|
||||
|
||||
if (idx < 0 || idx >= num_default_args) {
|
||||
return Variant();
|
||||
} else {
|
||||
return default_arguments[idx];
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
|
||||
_FORCE_INLINE_ void set_instance_class(StringName p_class) { instance_class = p_class; }
|
||||
|
||||
_FORCE_INLINE_ int get_argument_count() const { return argument_count; }
|
||||
_FORCE_INLINE_ bool is_const() const { return _is_const; }
|
||||
_FORCE_INLINE_ bool is_static() const { return _static; }
|
||||
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
|
||||
_FORCE_INLINE_ bool has_return() const { return _has_return; }
|
||||
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDEXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDEXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDEXTENSION_METHOD_FLAG_STATIC : 0); }
|
||||
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
|
||||
void set_argument_names(const std::vector<StringName> &p_names);
|
||||
std::vector<StringName> get_argument_names() const;
|
||||
void set_default_arguments(const std::vector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
|
||||
|
||||
_FORCE_INLINE_ GDExtensionVariantType get_argument_type(int p_argument) const {
|
||||
ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, GDEXTENSION_VARIANT_TYPE_NIL);
|
||||
return argument_types[p_argument + 1];
|
||||
}
|
||||
|
||||
PropertyInfo get_argument_info(int p_argument) const;
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
|
||||
|
||||
std::vector<PropertyInfo> get_arguments_info_list() const {
|
||||
std::vector<PropertyInfo> vec;
|
||||
// First element is return value
|
||||
vec.reserve(argument_count + 1);
|
||||
for (int i = 0; i < argument_count + 1; i++) {
|
||||
vec.push_back(get_argument_info(i - 1));
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
std::vector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
|
||||
std::vector<GDExtensionClassMethodArgumentMetadata> vec;
|
||||
// First element is return value
|
||||
vec.reserve(argument_count + 1);
|
||||
for (int i = 0; i < argument_count; i++) {
|
||||
vec.push_back(get_argument_metadata(i - 1));
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const = 0;
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const = 0;
|
||||
|
||||
static void bind_call(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
|
||||
static void bind_ptrcall(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return);
|
||||
|
||||
virtual ~MethodBind();
|
||||
};
|
||||
|
||||
template <class Derived, class T, class R, bool should_returns>
|
||||
class MethodBindVarArgBase : public MethodBind {
|
||||
protected:
|
||||
R(T::*method)
|
||||
(const Variant **, GDExtensionInt, GDExtensionCallError &);
|
||||
std::vector<PropertyInfo> arguments;
|
||||
|
||||
public:
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg < 0) {
|
||||
return _gen_return_type_info();
|
||||
} else if ((size_t)(p_arg) < arguments.size()) {
|
||||
return arguments[p_arg];
|
||||
} else {
|
||||
return make_property_info(Variant::Type::NIL, "vararg", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
}
|
||||
}
|
||||
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
return static_cast<GDExtensionVariantType>(gen_argument_type_info(p_arg).type);
|
||||
}
|
||||
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int) const {
|
||||
return GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
}
|
||||
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const {
|
||||
ERR_FAIL(); // Can't call.
|
||||
}
|
||||
|
||||
MethodBindVarArgBase(
|
||||
R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
|
||||
const MethodInfo &p_method_info,
|
||||
bool p_return_nil_is_variant) :
|
||||
method(p_method) {
|
||||
set_vararg(true);
|
||||
set_const(true);
|
||||
set_argument_count(p_method_info.arguments.size());
|
||||
if (p_method_info.arguments.size()) {
|
||||
arguments = p_method_info.arguments;
|
||||
|
||||
std::vector<StringName> names;
|
||||
names.reserve(p_method_info.arguments.size());
|
||||
for (size_t i = 0; i < p_method_info.arguments.size(); i++) {
|
||||
names.push_back(p_method_info.arguments[i].name);
|
||||
}
|
||||
set_argument_names(names);
|
||||
}
|
||||
|
||||
generate_argument_types((int)p_method_info.arguments.size());
|
||||
set_return(should_returns);
|
||||
}
|
||||
|
||||
~MethodBindVarArgBase() {}
|
||||
|
||||
private:
|
||||
PropertyInfo _gen_return_type_info() const {
|
||||
return reinterpret_cast<const Derived *>(this)->_gen_return_type_info_impl();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
|
||||
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
|
||||
|
||||
public:
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
(static_cast<T *>(p_instance)->*MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>::method)((const Variant **)p_args, p_argument_count, r_error);
|
||||
return {};
|
||||
}
|
||||
|
||||
MethodBindVarArgT(
|
||||
void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
|
||||
const MethodInfo &p_method_info,
|
||||
bool p_return_nil_is_variant) :
|
||||
MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>(p_method, p_method_info, p_return_nil_is_variant) {
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyInfo _gen_return_type_info_impl() const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
|
||||
MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant));
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class T, class R>
|
||||
class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
|
||||
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
|
||||
|
||||
public:
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
return (static_cast<T *>(p_instance)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)((const Variant **)p_args, p_argument_count, r_error);
|
||||
}
|
||||
|
||||
MethodBindVarArgTR(
|
||||
R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
|
||||
const MethodInfo &p_info,
|
||||
bool p_return_nil_is_variant) :
|
||||
MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>(p_method, p_info, p_return_nil_is_variant) {
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyInfo _gen_return_type_info_impl() const {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class R>
|
||||
MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
|
||||
MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant));
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
#ifndef TYPED_METHOD_BIND
|
||||
class _gde_UnexistingClass;
|
||||
#define MB_T _gde_UnexistingClass
|
||||
#else
|
||||
#define MB_T T
|
||||
#endif
|
||||
|
||||
// No return, not const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <class T, class... P>
|
||||
#else
|
||||
template <class... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindT : public MethodBind {
|
||||
void (MB_T::*method)(P...);
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
PropertyInfo pi;
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
} else {
|
||||
pi = PropertyInfo();
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
|
||||
return call_get_argument_metadata<P...>(p_argument);
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_variant_args_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, r_error, get_default_arguments());
|
||||
#else
|
||||
call_with_variant_args_dv(reinterpret_cast<MB_T *>(p_instance), method, p_args, p_argument_count, r_error, get_default_arguments());
|
||||
#endif
|
||||
return Variant();
|
||||
}
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_ptr_args<T, P...>(static_cast<T *>(p_instance), method, p_args, nullptr);
|
||||
#else
|
||||
call_with_ptr_args<MB_T, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, nullptr);
|
||||
#endif // TYPED_METHOD_BIND
|
||||
}
|
||||
|
||||
MethodBindT(void (MB_T::*p_method)(P...)) {
|
||||
method = p_method;
|
||||
generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... P>
|
||||
MethodBind *create_method_bind(void (T::*p_method)(P...)) {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
MethodBind *a = memnew((MethodBindT<T, P...>)(p_method));
|
||||
#else
|
||||
MethodBind *a = memnew((MethodBindT<P...>)(reinterpret_cast<void (MB_T::*)(P...)>(p_method)));
|
||||
#endif // TYPED_METHOD_BIND
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
// No return, const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <class T, class... P>
|
||||
#else
|
||||
template <class... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTC : public MethodBind {
|
||||
void (MB_T::*method)(P...) const;
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
PropertyInfo pi;
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
} else {
|
||||
pi = PropertyInfo();
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
|
||||
return call_get_argument_metadata<P...>(p_argument);
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_variant_argsc_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, r_error, get_default_arguments());
|
||||
#else
|
||||
call_with_variant_argsc_dv(reinterpret_cast<MB_T *>(p_instance), method, p_args, p_argument_count, r_error, get_default_arguments());
|
||||
#endif
|
||||
return Variant();
|
||||
}
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_ptr_args<T, P...>(static_cast<T *>(p_instance), method, p_args, nullptr);
|
||||
#else
|
||||
call_with_ptr_args<MB_T, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, nullptr);
|
||||
#endif // TYPED_METHOD_BIND
|
||||
}
|
||||
|
||||
MethodBindTC(void (MB_T::*p_method)(P...) const) {
|
||||
method = p_method;
|
||||
generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... P>
|
||||
MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method));
|
||||
#else
|
||||
MethodBind *a = memnew((MethodBindTC<P...>)(reinterpret_cast<void (MB_T::*)(P...) const>(p_method)));
|
||||
#endif // TYPED_METHOD_BIND
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
// Return, not const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <class T, class R, class... P>
|
||||
#else
|
||||
template <class R, class... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTR : public MethodBind {
|
||||
R(MB_T::*method)
|
||||
(P...);
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
PropertyInfo pi;
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
return pi;
|
||||
} else {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
|
||||
if (p_argument >= 0) {
|
||||
return call_get_argument_metadata<P...>(p_argument);
|
||||
} else {
|
||||
return GetTypeInfo<R>::METADATA;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
Variant ret;
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_variant_args_ret_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, ret, r_error, get_default_arguments());
|
||||
#else
|
||||
call_with_variant_args_ret_dv((MB_T *)p_instance, method, p_args, p_argument_count, ret, r_error, get_default_arguments());
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_ptr_args<T, R, P...>(static_cast<T *>(p_instance), method, p_args, r_ret);
|
||||
#else
|
||||
call_with_ptr_args<MB_T, R, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, r_ret);
|
||||
#endif // TYPED_METHOD_BIND
|
||||
}
|
||||
|
||||
MethodBindTR(R (MB_T::*p_method)(P...)) {
|
||||
method = p_method;
|
||||
generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_return(true);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class R, class... P>
|
||||
MethodBind *create_method_bind(R (T::*p_method)(P...)) {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method));
|
||||
#else
|
||||
MethodBind *a = memnew((MethodBindTR<R, P...>)(reinterpret_cast<R (MB_T::*)(P...)>(p_method)));
|
||||
#endif // TYPED_METHOD_BIND
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
// Return, const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <class T, class R, class... P>
|
||||
#else
|
||||
template <class R, class... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTRC : public MethodBind {
|
||||
R(MB_T::*method)
|
||||
(P...) const;
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
PropertyInfo pi;
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
return pi;
|
||||
} else {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
|
||||
if (p_argument >= 0) {
|
||||
return call_get_argument_metadata<P...>(p_argument);
|
||||
} else {
|
||||
return GetTypeInfo<R>::METADATA;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
|
||||
Variant ret;
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_variant_args_retc_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, ret, r_error, get_default_arguments());
|
||||
#else
|
||||
call_with_variant_args_retc_dv((MB_T *)p_instance, method, p_args, p_argument_count, ret, r_error, get_default_arguments());
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
call_with_ptr_args<T, R, P...>(static_cast<T *>(p_instance), method, p_args, r_ret);
|
||||
#else
|
||||
call_with_ptr_args<MB_T, R, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, r_ret);
|
||||
#endif // TYPED_METHOD_BIND
|
||||
}
|
||||
|
||||
MethodBindTRC(R (MB_T::*p_method)(P...) const) {
|
||||
method = p_method;
|
||||
generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_return(true);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class R, class... P>
|
||||
MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method));
|
||||
#else
|
||||
MethodBind *a = memnew((MethodBindTRC<R, P...>)(reinterpret_cast<R (MB_T::*)(P...) const>(p_method)));
|
||||
#endif // TYPED_METHOD_BIND
|
||||
a->set_instance_class(T::get_class_static());
|
||||
return a;
|
||||
}
|
||||
|
||||
// STATIC BINDS
|
||||
|
||||
// no return
|
||||
|
||||
template <class... P>
|
||||
class MethodBindTS : public MethodBind {
|
||||
void (*function)(P...);
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
PropertyInfo pi;
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
} else {
|
||||
pi = PropertyInfo();
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const {
|
||||
return call_get_argument_metadata<P...>(p_arg);
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_object, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionCallError &r_error) const {
|
||||
(void)p_object; // unused
|
||||
call_with_variant_args_static_dv(function, p_args, p_arg_count, r_error, get_default_arguments());
|
||||
return Variant();
|
||||
}
|
||||
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
(void)p_object;
|
||||
(void)r_ret;
|
||||
call_with_ptr_args_static_method(function, p_args);
|
||||
}
|
||||
|
||||
MethodBindTS(void (*p_function)(P...)) {
|
||||
function = p_function;
|
||||
generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_static(true);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... P>
|
||||
MethodBind *create_static_method_bind(void (*p_method)(P...)) {
|
||||
MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
|
||||
return a;
|
||||
}
|
||||
|
||||
// return
|
||||
|
||||
template <class R, class... P>
|
||||
class MethodBindTRS : public MethodBind {
|
||||
R(*function)
|
||||
(P...);
|
||||
|
||||
protected:
|
||||
// GCC raises warnings in the case P = {} as the comparison is always false...
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
return call_get_argument_type<P...>(p_arg);
|
||||
} else {
|
||||
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
PropertyInfo pi;
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
return pi;
|
||||
} else {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const {
|
||||
if (p_arg >= 0) {
|
||||
return call_get_argument_metadata<P...>(p_arg);
|
||||
} else {
|
||||
return GetTypeInfo<R>::METADATA;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_object, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionCallError &r_error) const {
|
||||
Variant ret;
|
||||
call_with_variant_args_static_ret_dv(function, p_args, p_arg_count, ret, r_error, get_default_arguments());
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
|
||||
(void)p_object;
|
||||
call_with_ptr_args_static_method_ret(function, p_args, r_ret);
|
||||
}
|
||||
|
||||
MethodBindTRS(R (*p_function)(P...)) {
|
||||
function = p_function;
|
||||
generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_static(true);
|
||||
set_return(true);
|
||||
}
|
||||
};
|
||||
|
||||
template <class R, class... P>
|
||||
MethodBind *create_static_method_bind(R (*p_method)(P...)) {
|
||||
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
|
||||
return a;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_METHOD_BIND_HPP
|
||||
@@ -1,237 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* method_ptrcall.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_METHOD_PTRCALL_HPP
|
||||
#define GODOT_METHOD_PTRCALL_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg {};
|
||||
|
||||
#define MAKE_PTRARG(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAKE_PTRARGCONV(m_type, m_conv) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
|
||||
} \
|
||||
typedef m_conv EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_conv *>(p_ptr) = static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
_FORCE_INLINE_ static m_conv encode_arg(m_type p_val) { \
|
||||
return static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
|
||||
} \
|
||||
typedef m_conv EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_conv *>(p_ptr) = static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
_FORCE_INLINE_ static m_conv encode_arg(m_type p_val) { \
|
||||
return static_cast<m_conv>(p_val); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAKE_PTRARG_BY_REFERENCE(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct PtrToArg<const m_type &> { \
|
||||
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
|
||||
return *reinterpret_cast<const m_type *>(p_ptr); \
|
||||
} \
|
||||
typedef m_type EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_PTRARGCONV(bool, uint8_t);
|
||||
// Integer types.
|
||||
MAKE_PTRARGCONV(uint8_t, int64_t);
|
||||
MAKE_PTRARGCONV(int8_t, int64_t);
|
||||
MAKE_PTRARGCONV(uint16_t, int64_t);
|
||||
MAKE_PTRARGCONV(int16_t, int64_t);
|
||||
MAKE_PTRARGCONV(uint32_t, int64_t);
|
||||
MAKE_PTRARGCONV(int32_t, int64_t);
|
||||
MAKE_PTRARG(int64_t);
|
||||
MAKE_PTRARG(uint64_t);
|
||||
// Float types
|
||||
MAKE_PTRARGCONV(float, double);
|
||||
MAKE_PTRARG(double);
|
||||
|
||||
MAKE_PTRARG(String);
|
||||
MAKE_PTRARG(Vector2);
|
||||
MAKE_PTRARG(Vector2i);
|
||||
MAKE_PTRARG(Rect2);
|
||||
MAKE_PTRARG(Rect2i);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector3);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector3i);
|
||||
MAKE_PTRARG(Transform2D);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector4);
|
||||
MAKE_PTRARG_BY_REFERENCE(Vector4i);
|
||||
MAKE_PTRARG_BY_REFERENCE(Plane);
|
||||
MAKE_PTRARG(Quaternion);
|
||||
MAKE_PTRARG_BY_REFERENCE(AABB);
|
||||
MAKE_PTRARG_BY_REFERENCE(Basis);
|
||||
MAKE_PTRARG_BY_REFERENCE(Transform3D);
|
||||
MAKE_PTRARG_BY_REFERENCE(Projection);
|
||||
MAKE_PTRARG_BY_REFERENCE(Color);
|
||||
MAKE_PTRARG(StringName);
|
||||
MAKE_PTRARG(NodePath);
|
||||
MAKE_PTRARG(RID);
|
||||
// Object doesn't need this.
|
||||
MAKE_PTRARG(Callable);
|
||||
MAKE_PTRARG(Signal);
|
||||
MAKE_PTRARG(Dictionary);
|
||||
MAKE_PTRARG(Array);
|
||||
MAKE_PTRARG(PackedByteArray);
|
||||
MAKE_PTRARG(PackedInt32Array);
|
||||
MAKE_PTRARG(PackedInt64Array);
|
||||
MAKE_PTRARG(PackedFloat32Array);
|
||||
MAKE_PTRARG(PackedFloat64Array);
|
||||
MAKE_PTRARG(PackedStringArray);
|
||||
MAKE_PTRARG(PackedVector2Array);
|
||||
MAKE_PTRARG(PackedVector3Array);
|
||||
MAKE_PTRARG(PackedColorArray);
|
||||
MAKE_PTRARG_BY_REFERENCE(Variant);
|
||||
|
||||
// This is for Object.
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg<T *> {
|
||||
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
|
||||
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
|
||||
return reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
|
||||
}
|
||||
typedef Object *EncodeT;
|
||||
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
|
||||
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg<const T *> {
|
||||
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
|
||||
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
|
||||
return reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
|
||||
}
|
||||
typedef const Object *EncodeT;
|
||||
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
|
||||
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Pointers.
|
||||
#define GDVIRTUAL_NATIVE_PTR(m_type) \
|
||||
template <> \
|
||||
struct PtrToArg<m_type *> { \
|
||||
_FORCE_INLINE_ static m_type *convert(const void *p_ptr) { \
|
||||
return (m_type *)(*(void **)p_ptr); \
|
||||
} \
|
||||
typedef m_type *EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(m_type *p_var, void *p_ptr) { \
|
||||
*reinterpret_cast<m_type **>(p_ptr) = p_var; \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct PtrToArg<const m_type *> { \
|
||||
_FORCE_INLINE_ static const m_type *convert(const void *p_ptr) { \
|
||||
return (const m_type *)(*(const void **)p_ptr); \
|
||||
} \
|
||||
typedef const m_type *EncodeT; \
|
||||
_FORCE_INLINE_ static void encode(const m_type *p_var, void *p_ptr) { \
|
||||
*reinterpret_cast<const m_type **>(p_ptr) = p_var; \
|
||||
} \
|
||||
}
|
||||
|
||||
GDVIRTUAL_NATIVE_PTR(void);
|
||||
GDVIRTUAL_NATIVE_PTR(bool);
|
||||
GDVIRTUAL_NATIVE_PTR(char);
|
||||
GDVIRTUAL_NATIVE_PTR(char16_t);
|
||||
GDVIRTUAL_NATIVE_PTR(char32_t);
|
||||
GDVIRTUAL_NATIVE_PTR(wchar_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint8_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint8_t *);
|
||||
GDVIRTUAL_NATIVE_PTR(int8_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint16_t);
|
||||
GDVIRTUAL_NATIVE_PTR(int16_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint32_t);
|
||||
GDVIRTUAL_NATIVE_PTR(int32_t);
|
||||
GDVIRTUAL_NATIVE_PTR(int64_t);
|
||||
GDVIRTUAL_NATIVE_PTR(uint64_t);
|
||||
GDVIRTUAL_NATIVE_PTR(float);
|
||||
GDVIRTUAL_NATIVE_PTR(double);
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_METHOD_PTRCALL_HPP
|
||||
@@ -1,59 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* mutex_lock.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_MUTEX_LOCK_HPP
|
||||
#define GODOT_MUTEX_LOCK_HPP
|
||||
|
||||
#include <godot_cpp/classes/mutex.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class MutexLock {
|
||||
const Mutex &mutex;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ explicit MutexLock(const Mutex &p_mutex) :
|
||||
mutex(p_mutex) {
|
||||
const_cast<Mutex *>(&mutex)->lock();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ ~MutexLock() {
|
||||
const_cast<Mutex *>(&mutex)->unlock();
|
||||
}
|
||||
};
|
||||
|
||||
#define _THREAD_SAFE_CLASS_ mutable Mutex _thread_safe_;
|
||||
#define _THREAD_SAFE_METHOD_ MutexLock _thread_safe_method_(_thread_safe_);
|
||||
#define _THREAD_SAFE_LOCK_ _thread_safe_.lock();
|
||||
#define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock();
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_MUTEX_LOCK_HPP
|
||||
@@ -1,169 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* object.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_OBJECT_HPP
|
||||
#define GODOT_OBJECT_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <godot_cpp/core/property_info.hpp>
|
||||
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <godot_cpp/classes/object.hpp>
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define ADD_SIGNAL(m_signal) godot::ClassDB::add_signal(get_class_static(), m_signal)
|
||||
#define ADD_GROUP(m_name, m_prefix) godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
|
||||
#define ADD_SUBGROUP(m_name, m_prefix) godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
|
||||
#define ADD_PROPERTY(m_property, m_setter, m_getter) godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter)
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
Object *get_object_instance_binding(GodotObject *);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
struct MethodInfo {
|
||||
StringName name;
|
||||
PropertyInfo return_val;
|
||||
uint32_t flags;
|
||||
int id = 0;
|
||||
std::vector<PropertyInfo> arguments;
|
||||
std::vector<Variant> default_arguments;
|
||||
|
||||
inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; }
|
||||
inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); }
|
||||
|
||||
operator Dictionary() const;
|
||||
|
||||
static MethodInfo from_dict(const Dictionary &p_dict);
|
||||
|
||||
MethodInfo();
|
||||
MethodInfo(StringName p_name);
|
||||
template <class... Args>
|
||||
MethodInfo(StringName p_name, const Args &...args);
|
||||
MethodInfo(Variant::Type ret);
|
||||
MethodInfo(Variant::Type ret, StringName p_name);
|
||||
template <class... Args>
|
||||
MethodInfo(Variant::Type ret, StringName p_name, const Args &...args);
|
||||
MethodInfo(const PropertyInfo &p_ret, StringName p_name);
|
||||
template <class... Args>
|
||||
MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...);
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
|
||||
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
|
||||
arguments = { args... };
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) :
|
||||
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
|
||||
return_val.type = ret;
|
||||
arguments = { args... };
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) :
|
||||
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
|
||||
arguments = { args... };
|
||||
}
|
||||
|
||||
class ObjectID {
|
||||
uint64_t id = 0;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
|
||||
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
|
||||
_FORCE_INLINE_ bool is_null() const { return id == 0; }
|
||||
_FORCE_INLINE_ operator uint64_t() const { return id; }
|
||||
_FORCE_INLINE_ operator int64_t() const { return id; }
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
|
||||
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
|
||||
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
|
||||
|
||||
_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
|
||||
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
|
||||
|
||||
_FORCE_INLINE_ ObjectID() {}
|
||||
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
|
||||
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
|
||||
};
|
||||
|
||||
class ObjectDB {
|
||||
public:
|
||||
static Object *get_instance(uint64_t p_object_id) {
|
||||
GDExtensionObjectPtr obj = internal::gdextension_interface_object_get_instance_from_id(p_object_id);
|
||||
if (obj == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return internal::get_object_instance_binding(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T *Object::cast_to(Object *p_object) {
|
||||
if (p_object == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
StringName class_name = T::get_class_static();
|
||||
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
|
||||
if (casted == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return dynamic_cast<T *>(internal::get_object_instance_binding(casted));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T *Object::cast_to(const Object *p_object) {
|
||||
if (p_object == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
StringName class_name = T::get_class_static();
|
||||
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
|
||||
if (casted == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return dynamic_cast<const T *>(internal::get_object_instance_binding(casted));
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_OBJECT_HPP
|
||||
@@ -1,75 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* property_info.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_PROPERTY_INFO_HPP
|
||||
#define GODOT_PROPERTY_INFO_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct PropertyInfo {
|
||||
Variant::Type type = Variant::NIL;
|
||||
StringName name;
|
||||
StringName class_name;
|
||||
uint32_t hint = 0;
|
||||
String hint_string;
|
||||
uint32_t usage = 7;
|
||||
|
||||
PropertyInfo() = default;
|
||||
|
||||
PropertyInfo(Variant::Type p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
|
||||
type(p_type),
|
||||
name(p_name),
|
||||
hint(p_hint),
|
||||
hint_string(p_hint_string),
|
||||
usage(p_usage) {
|
||||
if (hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
||||
class_name = hint_string;
|
||||
} else {
|
||||
class_name = p_class_name;
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo(GDExtensionVariantType p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
|
||||
PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_PROPERTY_INFO_HPP
|
||||
@@ -1,402 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* type_info.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_TYPE_INFO_HPP
|
||||
#define GODOT_TYPE_INFO_HPP
|
||||
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/variant/typed_array.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <bool C, typename T = void>
|
||||
struct EnableIf {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct EnableIf<false, T> {
|
||||
};
|
||||
|
||||
template <typename, typename>
|
||||
struct TypesAreSame {
|
||||
static bool const value = false;
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
struct TypesAreSame<A, A> {
|
||||
static bool const value = true;
|
||||
};
|
||||
|
||||
template <typename B, typename D>
|
||||
struct TypeInherits {
|
||||
static D *get_d();
|
||||
|
||||
static char (&test(B *))[1];
|
||||
static char (&test(...))[2];
|
||||
|
||||
static bool const value = sizeof(test(get_d())) == sizeof(char) &&
|
||||
!TypesAreSame<B volatile const, void volatile const>::value;
|
||||
};
|
||||
|
||||
static PropertyInfo make_property_info(Variant::Type p_type, const StringName &p_name, uint32_t p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") {
|
||||
PropertyInfo info;
|
||||
info.type = p_type;
|
||||
info.name = p_name;
|
||||
info.hint = p_hint;
|
||||
info.hint_string = p_hint_string;
|
||||
info.usage = p_usage;
|
||||
if (p_hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
||||
info.class_name = p_hint_string;
|
||||
} else {
|
||||
info.class_name = p_class_name;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
// If the compiler fails because it's trying to instantiate the primary 'GetTypeInfo' template
|
||||
// instead of one of the specializations, it's most likely because the type 'T' is not supported.
|
||||
// If 'T' is a class that inherits 'Object', make sure it can see the actual class declaration
|
||||
// instead of a forward declaration. You can always forward declare 'T' in a header file, and then
|
||||
// include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated.
|
||||
|
||||
template <class T, typename = void>
|
||||
struct GetTypeInfo;
|
||||
|
||||
#define MAKE_TYPE_INFO(m_type, m_var_type) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_type> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const m_type &> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_type> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = m_metadata; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const m_type &> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = m_metadata; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
|
||||
} \
|
||||
};
|
||||
|
||||
MAKE_TYPE_INFO(bool, GDEXTENSION_VARIANT_TYPE_BOOL)
|
||||
MAKE_TYPE_INFO_WITH_META(uint8_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8)
|
||||
MAKE_TYPE_INFO_WITH_META(int8_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8)
|
||||
MAKE_TYPE_INFO_WITH_META(uint16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16)
|
||||
MAKE_TYPE_INFO_WITH_META(int16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16)
|
||||
MAKE_TYPE_INFO_WITH_META(uint32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32)
|
||||
MAKE_TYPE_INFO_WITH_META(int32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32)
|
||||
MAKE_TYPE_INFO_WITH_META(uint64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64)
|
||||
MAKE_TYPE_INFO_WITH_META(int64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64)
|
||||
MAKE_TYPE_INFO(char16_t, GDEXTENSION_VARIANT_TYPE_INT)
|
||||
MAKE_TYPE_INFO(char32_t, GDEXTENSION_VARIANT_TYPE_INT)
|
||||
MAKE_TYPE_INFO_WITH_META(float, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT)
|
||||
MAKE_TYPE_INFO_WITH_META(double, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE)
|
||||
|
||||
MAKE_TYPE_INFO(String, GDEXTENSION_VARIANT_TYPE_STRING)
|
||||
MAKE_TYPE_INFO(Vector2, GDEXTENSION_VARIANT_TYPE_VECTOR2)
|
||||
MAKE_TYPE_INFO(Vector2i, GDEXTENSION_VARIANT_TYPE_VECTOR2I)
|
||||
MAKE_TYPE_INFO(Rect2, GDEXTENSION_VARIANT_TYPE_RECT2)
|
||||
MAKE_TYPE_INFO(Rect2i, GDEXTENSION_VARIANT_TYPE_RECT2I)
|
||||
MAKE_TYPE_INFO(Vector3, GDEXTENSION_VARIANT_TYPE_VECTOR3)
|
||||
MAKE_TYPE_INFO(Vector3i, GDEXTENSION_VARIANT_TYPE_VECTOR3I)
|
||||
MAKE_TYPE_INFO(Transform2D, GDEXTENSION_VARIANT_TYPE_TRANSFORM2D)
|
||||
MAKE_TYPE_INFO(Vector4, GDEXTENSION_VARIANT_TYPE_VECTOR4)
|
||||
MAKE_TYPE_INFO(Vector4i, GDEXTENSION_VARIANT_TYPE_VECTOR4I)
|
||||
MAKE_TYPE_INFO(Plane, GDEXTENSION_VARIANT_TYPE_PLANE)
|
||||
MAKE_TYPE_INFO(Quaternion, GDEXTENSION_VARIANT_TYPE_QUATERNION)
|
||||
MAKE_TYPE_INFO(AABB, GDEXTENSION_VARIANT_TYPE_AABB)
|
||||
MAKE_TYPE_INFO(Basis, GDEXTENSION_VARIANT_TYPE_BASIS)
|
||||
MAKE_TYPE_INFO(Transform3D, GDEXTENSION_VARIANT_TYPE_TRANSFORM3D)
|
||||
MAKE_TYPE_INFO(Projection, GDEXTENSION_VARIANT_TYPE_PROJECTION)
|
||||
MAKE_TYPE_INFO(Color, GDEXTENSION_VARIANT_TYPE_COLOR)
|
||||
MAKE_TYPE_INFO(StringName, GDEXTENSION_VARIANT_TYPE_STRING_NAME)
|
||||
MAKE_TYPE_INFO(NodePath, GDEXTENSION_VARIANT_TYPE_NODE_PATH)
|
||||
MAKE_TYPE_INFO(RID, GDEXTENSION_VARIANT_TYPE_RID)
|
||||
MAKE_TYPE_INFO(Callable, GDEXTENSION_VARIANT_TYPE_CALLABLE)
|
||||
MAKE_TYPE_INFO(Signal, GDEXTENSION_VARIANT_TYPE_SIGNAL)
|
||||
MAKE_TYPE_INFO(Dictionary, GDEXTENSION_VARIANT_TYPE_DICTIONARY)
|
||||
MAKE_TYPE_INFO(Array, GDEXTENSION_VARIANT_TYPE_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedByteArray, GDEXTENSION_VARIANT_TYPE_PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedInt32Array, GDEXTENSION_VARIANT_TYPE_PACKED_INT32_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedInt64Array, GDEXTENSION_VARIANT_TYPE_PACKED_INT64_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedFloat32Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedFloat64Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedStringArray, GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedVector2Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedVector3Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPE_INFO(PackedColorArray, GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY)
|
||||
|
||||
// For variant.
|
||||
template <>
|
||||
struct GetTypeInfo<Variant> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::NIL, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GetTypeInfo<const Variant &> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::NIL, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
|
||||
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
|
||||
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) {
|
||||
PackedStringArray parts = p_qualified_name.split("::", false);
|
||||
if (parts.size() <= 2) {
|
||||
return String(".").join(parts);
|
||||
}
|
||||
// Contains namespace. We only want the class and enum names.
|
||||
return parts[parts.size() - 2] + "." + parts[parts.size() - 1];
|
||||
}
|
||||
|
||||
#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_impl> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, \
|
||||
enum_qualified_name_to_class_info_name(#m_enum)); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_ENUM_TYPE_INFO(m_enum) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &) \
|
||||
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
|
||||
|
||||
template <typename T>
|
||||
inline StringName _gde_constant_get_enum_name(T param, StringName p_constant) {
|
||||
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
|
||||
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's enum: " + String(p_constant)).utf8().get_data());
|
||||
}
|
||||
return GetTypeInfo<T>::get_class_info().class_name;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class BitField {
|
||||
int64_t value = 0;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
|
||||
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
|
||||
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; }
|
||||
_FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; }
|
||||
_FORCE_INLINE_ operator int64_t() const { return value; }
|
||||
_FORCE_INLINE_ operator Variant() const { return value; }
|
||||
};
|
||||
|
||||
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
|
||||
template <> \
|
||||
struct GetTypeInfo<m_impl> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
|
||||
enum_qualified_name_to_class_info_name(#m_enum)); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<BitField<m_impl>> { \
|
||||
static const Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
|
||||
enum_qualified_name_to_class_info_name(#m_enum)); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define MAKE_BITFIELD_TYPE_INFO(m_enum) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum const) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum &) \
|
||||
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &)
|
||||
|
||||
template <typename T>
|
||||
inline StringName _gde_constant_get_bitfield_name(T param, StringName p_constant) {
|
||||
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
|
||||
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's bitfield: " + String(p_constant)).utf8().get_data());
|
||||
}
|
||||
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg<TypedArray<T>> {
|
||||
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
|
||||
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
|
||||
}
|
||||
typedef Array EncodeT;
|
||||
_FORCE_INLINE_ static void encode(TypedArray<T> p_val, void *p_ptr) {
|
||||
*reinterpret_cast<Array *>(p_ptr) = p_val;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg<const TypedArray<T> &> {
|
||||
typedef Array EncodeT;
|
||||
_FORCE_INLINE_ static TypedArray<T>
|
||||
convert(const void *p_ptr) {
|
||||
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<TypedArray<T>> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<const TypedArray<T> &> {
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
|
||||
}
|
||||
};
|
||||
|
||||
#define MAKE_TYPED_ARRAY_INFO(m_type, m_variant_type) \
|
||||
template <> \
|
||||
struct GetTypeInfo<TypedArray<m_type>> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type).utf8().get_data()); \
|
||||
} \
|
||||
}; \
|
||||
template <> \
|
||||
struct GetTypeInfo<const TypedArray<m_type> &> { \
|
||||
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY; \
|
||||
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
|
||||
static inline PropertyInfo get_class_info() { \
|
||||
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type).utf8().get_data()); \
|
||||
} \
|
||||
};
|
||||
|
||||
MAKE_TYPED_ARRAY_INFO(bool, Variant::BOOL)
|
||||
MAKE_TYPED_ARRAY_INFO(uint8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(uint64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(int64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY_INFO(float, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY_INFO(double, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY_INFO(String, Variant::STRING)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector2, Variant::VECTOR2)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector2i, Variant::VECTOR2I)
|
||||
MAKE_TYPED_ARRAY_INFO(Rect2, Variant::RECT2)
|
||||
MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
|
||||
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
|
||||
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
|
||||
MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
|
||||
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
|
||||
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
|
||||
MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
|
||||
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
|
||||
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
|
||||
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
|
||||
MAKE_TYPED_ARRAY_INFO(RID, Variant::RID)
|
||||
MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
|
||||
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
|
||||
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
|
||||
MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
|
||||
/*
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<uint8_t>, Variant::PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<int32_t>, Variant::PACKED_INT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<int64_t>, Variant::PACKED_INT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<float>, Variant::PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<double>, Variant::PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<String>, Variant::PACKED_STRING_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
|
||||
*/
|
||||
|
||||
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_TYPE_INFO_HPP
|
||||
@@ -1,224 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* godot.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_GODOT_HPP
|
||||
#define GODOT_GODOT_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
||||
namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
extern "C" GDExtensionInterfaceGetProcAddress gdextension_interface_get_proc_address;
|
||||
extern "C" GDExtensionClassLibraryPtr library;
|
||||
extern "C" void *token;
|
||||
|
||||
extern "C" GDExtensionGodotVersion godot_version;
|
||||
|
||||
// All of the GDExtension interface functions.
|
||||
extern "C" GDExtensionInterfaceGetGodotVersion gdextension_interface_get_godot_version;
|
||||
extern "C" GDExtensionInterfaceMemAlloc gdextension_interface_mem_alloc;
|
||||
extern "C" GDExtensionInterfaceMemRealloc gdextension_interface_mem_realloc;
|
||||
extern "C" GDExtensionInterfaceMemFree gdextension_interface_mem_free;
|
||||
extern "C" GDExtensionInterfacePrintError gdextension_interface_print_error;
|
||||
extern "C" GDExtensionInterfacePrintErrorWithMessage gdextension_interface_print_error_with_message;
|
||||
extern "C" GDExtensionInterfacePrintWarning gdextension_interface_print_warning;
|
||||
extern "C" GDExtensionInterfacePrintWarningWithMessage gdextension_interface_print_warning_with_message;
|
||||
extern "C" GDExtensionInterfacePrintScriptError gdextension_interface_print_script_error;
|
||||
extern "C" GDExtensionInterfacePrintScriptErrorWithMessage gdextension_interface_print_script_error_with_message;
|
||||
extern "C" GDExtensionInterfaceGetNativeStructSize gdextension_interface_get_native_struct_size;
|
||||
extern "C" GDExtensionInterfaceVariantNewCopy gdextension_interface_variant_new_copy;
|
||||
extern "C" GDExtensionInterfaceVariantNewNil gdextension_interface_variant_new_nil;
|
||||
extern "C" GDExtensionInterfaceVariantDestroy gdextension_interface_variant_destroy;
|
||||
extern "C" GDExtensionInterfaceVariantCall gdextension_interface_variant_call;
|
||||
extern "C" GDExtensionInterfaceVariantCallStatic gdextension_interface_variant_call_static;
|
||||
extern "C" GDExtensionInterfaceVariantEvaluate gdextension_interface_variant_evaluate;
|
||||
extern "C" GDExtensionInterfaceVariantSet gdextension_interface_variant_set;
|
||||
extern "C" GDExtensionInterfaceVariantSetNamed gdextension_interface_variant_set_named;
|
||||
extern "C" GDExtensionInterfaceVariantSetKeyed gdextension_interface_variant_set_keyed;
|
||||
extern "C" GDExtensionInterfaceVariantSetIndexed gdextension_interface_variant_set_indexed;
|
||||
extern "C" GDExtensionInterfaceVariantGet gdextension_interface_variant_get;
|
||||
extern "C" GDExtensionInterfaceVariantGetNamed gdextension_interface_variant_get_named;
|
||||
extern "C" GDExtensionInterfaceVariantGetKeyed gdextension_interface_variant_get_keyed;
|
||||
extern "C" GDExtensionInterfaceVariantGetIndexed gdextension_interface_variant_get_indexed;
|
||||
extern "C" GDExtensionInterfaceVariantIterInit gdextension_interface_variant_iter_init;
|
||||
extern "C" GDExtensionInterfaceVariantIterNext gdextension_interface_variant_iter_next;
|
||||
extern "C" GDExtensionInterfaceVariantIterGet gdextension_interface_variant_iter_get;
|
||||
extern "C" GDExtensionInterfaceVariantHash gdextension_interface_variant_hash;
|
||||
extern "C" GDExtensionInterfaceVariantRecursiveHash gdextension_interface_variant_recursive_hash;
|
||||
extern "C" GDExtensionInterfaceVariantHashCompare gdextension_interface_variant_hash_compare;
|
||||
extern "C" GDExtensionInterfaceVariantBooleanize gdextension_interface_variant_booleanize;
|
||||
extern "C" GDExtensionInterfaceVariantDuplicate gdextension_interface_variant_duplicate;
|
||||
extern "C" GDExtensionInterfaceVariantStringify gdextension_interface_variant_stringify;
|
||||
extern "C" GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_type;
|
||||
extern "C" GDExtensionInterfaceVariantHasMethod gdextension_interface_variant_has_method;
|
||||
extern "C" GDExtensionInterfaceVariantHasMember gdextension_interface_variant_has_member;
|
||||
extern "C" GDExtensionInterfaceVariantHasKey gdextension_interface_variant_has_key;
|
||||
extern "C" GDExtensionInterfaceVariantGetTypeName gdextension_interface_variant_get_type_name;
|
||||
extern "C" GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert;
|
||||
extern "C" GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict;
|
||||
extern "C" GDExtensionInterfaceGetVariantFromTypeConstructor gdextension_interface_get_variant_from_type_constructor;
|
||||
extern "C" GDExtensionInterfaceGetVariantToTypeConstructor gdextension_interface_get_variant_to_type_constructor;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrOperatorEvaluator gdextension_interface_variant_get_ptr_operator_evaluator;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrBuiltinMethod gdextension_interface_variant_get_ptr_builtin_method;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrConstructor gdextension_interface_variant_get_ptr_constructor;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrDestructor gdextension_interface_variant_get_ptr_destructor;
|
||||
extern "C" GDExtensionInterfaceVariantConstruct gdextension_interface_variant_construct;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrSetter gdextension_interface_variant_get_ptr_setter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrGetter gdextension_interface_variant_get_ptr_getter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrIndexedSetter gdextension_interface_variant_get_ptr_indexed_setter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrIndexedGetter gdextension_interface_variant_get_ptr_indexed_getter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrKeyedSetter gdextension_interface_variant_get_ptr_keyed_setter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrKeyedGetter gdextension_interface_variant_get_ptr_keyed_getter;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrKeyedChecker gdextension_interface_variant_get_ptr_keyed_checker;
|
||||
extern "C" GDExtensionInterfaceVariantGetConstantValue gdextension_interface_variant_get_constant_value;
|
||||
extern "C" GDExtensionInterfaceVariantGetPtrUtilityFunction gdextension_interface_variant_get_ptr_utility_function;
|
||||
extern "C" GDExtensionInterfaceStringNewWithLatin1Chars gdextension_interface_string_new_with_latin1_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf8Chars gdextension_interface_string_new_with_utf8_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf16Chars gdextension_interface_string_new_with_utf16_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf32Chars gdextension_interface_string_new_with_utf32_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithWideChars gdextension_interface_string_new_with_wide_chars;
|
||||
extern "C" GDExtensionInterfaceStringNewWithLatin1CharsAndLen gdextension_interface_string_new_with_latin1_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen gdextension_interface_string_new_with_utf8_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen gdextension_interface_string_new_with_utf16_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringNewWithUtf32CharsAndLen gdextension_interface_string_new_with_utf32_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringNewWithWideCharsAndLen gdextension_interface_string_new_with_wide_chars_and_len;
|
||||
extern "C" GDExtensionInterfaceStringToLatin1Chars gdextension_interface_string_to_latin1_chars;
|
||||
extern "C" GDExtensionInterfaceStringToUtf8Chars gdextension_interface_string_to_utf8_chars;
|
||||
extern "C" GDExtensionInterfaceStringToUtf16Chars gdextension_interface_string_to_utf16_chars;
|
||||
extern "C" GDExtensionInterfaceStringToUtf32Chars gdextension_interface_string_to_utf32_chars;
|
||||
extern "C" GDExtensionInterfaceStringToWideChars gdextension_interface_string_to_wide_chars;
|
||||
extern "C" GDExtensionInterfaceStringOperatorIndex gdextension_interface_string_operator_index;
|
||||
extern "C" GDExtensionInterfaceStringOperatorIndexConst gdextension_interface_string_operator_index_const;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqString gdextension_interface_string_operator_plus_eq_string;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqChar gdextension_interface_string_operator_plus_eq_char;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqCstr gdextension_interface_string_operator_plus_eq_cstr;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqWcstr gdextension_interface_string_operator_plus_eq_wcstr;
|
||||
extern "C" GDExtensionInterfaceStringOperatorPlusEqC32str gdextension_interface_string_operator_plus_eq_c32str;
|
||||
extern "C" GDExtensionInterfaceXmlParserOpenBuffer gdextension_interface_xml_parser_open_buffer;
|
||||
extern "C" GDExtensionInterfaceFileAccessStoreBuffer gdextension_interface_file_access_store_buffer;
|
||||
extern "C" GDExtensionInterfaceFileAccessGetBuffer gdextension_interface_file_access_get_buffer;
|
||||
extern "C" GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask gdextension_interface_worker_thread_pool_add_native_group_task;
|
||||
extern "C" GDExtensionInterfaceWorkerThreadPoolAddNativeTask gdextension_interface_worker_thread_pool_add_native_task;
|
||||
extern "C" GDExtensionInterfacePackedByteArrayOperatorIndex gdextension_interface_packed_byte_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedByteArrayOperatorIndexConst gdextension_interface_packed_byte_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedColorArrayOperatorIndex gdextension_interface_packed_color_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedColorArrayOperatorIndexConst gdextension_interface_packed_color_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedFloat32ArrayOperatorIndex gdextension_interface_packed_float32_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst gdextension_interface_packed_float32_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedFloat64ArrayOperatorIndex gdextension_interface_packed_float64_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst gdextension_interface_packed_float64_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedInt32ArrayOperatorIndex gdextension_interface_packed_int32_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedInt32ArrayOperatorIndexConst gdextension_interface_packed_int32_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedInt64ArrayOperatorIndex gdextension_interface_packed_int64_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedInt64ArrayOperatorIndexConst gdextension_interface_packed_int64_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedStringArrayOperatorIndex gdextension_interface_packed_string_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedStringArrayOperatorIndexConst gdextension_interface_packed_string_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndex gdextension_interface_packed_vector2_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndexConst gdextension_interface_packed_vector2_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndex gdextension_interface_packed_vector3_array_operator_index;
|
||||
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndexConst gdextension_interface_packed_vector3_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index;
|
||||
extern "C" GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const;
|
||||
extern "C" GDExtensionInterfaceArrayRef gdextension_interface_array_ref;
|
||||
extern "C" GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed;
|
||||
extern "C" GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index;
|
||||
extern "C" GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const;
|
||||
extern "C" GDExtensionInterfaceObjectMethodBindCall gdextension_interface_object_method_bind_call;
|
||||
extern "C" GDExtensionInterfaceObjectMethodBindPtrcall gdextension_interface_object_method_bind_ptrcall;
|
||||
extern "C" GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy;
|
||||
extern "C" GDExtensionInterfaceGlobalGetSingleton gdextension_interface_global_get_singleton;
|
||||
extern "C" GDExtensionInterfaceObjectGetInstanceBinding gdextension_interface_object_get_instance_binding;
|
||||
extern "C" GDExtensionInterfaceObjectSetInstanceBinding gdextension_interface_object_set_instance_binding;
|
||||
extern "C" GDExtensionInterfaceObjectSetInstance gdextension_interface_object_set_instance;
|
||||
extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_name;
|
||||
extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to;
|
||||
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
|
||||
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
|
||||
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
|
||||
extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object;
|
||||
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" GDExtensionInterfaceClassdbRegisterExtensionClass gdextension_interface_classdb_register_extension_class;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup gdextension_interface_classdb_register_extension_class_property_group;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup gdextension_interface_classdb_register_extension_class_property_subgroup;
|
||||
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassSignal gdextension_interface_classdb_register_extension_class_signal;
|
||||
extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classdb_unregister_extension_class;
|
||||
extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path;
|
||||
extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin;
|
||||
extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
enum ModuleInitializationLevel {
|
||||
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
|
||||
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
|
||||
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
|
||||
MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
|
||||
};
|
||||
|
||||
class GDExtensionBinding {
|
||||
public:
|
||||
using Callback = void (*)(ModuleInitializationLevel p_level);
|
||||
|
||||
static Callback init_callback;
|
||||
static Callback terminate_callback;
|
||||
static GDExtensionInitializationLevel minimum_initialization_level;
|
||||
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
|
||||
|
||||
public:
|
||||
static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level);
|
||||
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
|
||||
|
||||
class InitObject {
|
||||
GDExtensionInterfaceGetProcAddress get_proc_address;
|
||||
GDExtensionClassLibraryPtr library;
|
||||
GDExtensionInitialization *initialization;
|
||||
|
||||
public:
|
||||
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
|
||||
|
||||
void register_initializer(Callback p_init) const;
|
||||
void register_terminator(Callback p_init) const;
|
||||
void set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const;
|
||||
|
||||
GDExtensionBool init() const;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_GODOT_HPP
|
||||
@@ -1,402 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* cowdata.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_COWDATA_HPP
|
||||
#define GODOT_COWDATA_HPP
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/math.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/safe_refcount.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
class Vector;
|
||||
|
||||
template <class T, class V>
|
||||
class VMap;
|
||||
|
||||
template <class T>
|
||||
class CharStringT;
|
||||
|
||||
// Silence a false positive warning (see GH-52119).
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wplacement-new"
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
class CowData {
|
||||
template <class TV>
|
||||
friend class Vector;
|
||||
|
||||
template <class TV, class VV>
|
||||
friend class VMap;
|
||||
|
||||
template <class TS>
|
||||
friend class CharStringT;
|
||||
|
||||
private:
|
||||
mutable T *_ptr = nullptr;
|
||||
|
||||
// internal helpers
|
||||
|
||||
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
|
||||
if (!_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t *_get_size() const {
|
||||
if (!_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<uint32_t *>(_ptr) - 1;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *_get_data() const {
|
||||
if (!_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<T *>(_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const {
|
||||
return next_power_of_2(p_elements * sizeof(T));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
|
||||
if (unlikely(p_elements == 0)) {
|
||||
*out = 0;
|
||||
return true;
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
size_t o;
|
||||
size_t p;
|
||||
if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) {
|
||||
*out = 0;
|
||||
return false;
|
||||
}
|
||||
*out = next_power_of_2(o);
|
||||
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
|
||||
return false; // No longer allocated here.
|
||||
}
|
||||
#else
|
||||
// Speed is more important than correctness here, do the operations unchecked
|
||||
// and hope for the best.
|
||||
*out = _get_alloc_size(p_elements);
|
||||
#endif
|
||||
return *out;
|
||||
}
|
||||
|
||||
void _unref(void *p_data);
|
||||
void _ref(const CowData *p_from);
|
||||
void _ref(const CowData &p_from);
|
||||
uint32_t _copy_on_write();
|
||||
|
||||
public:
|
||||
void operator=(const CowData<T> &p_from) { _ref(p_from); }
|
||||
|
||||
_FORCE_INLINE_ T *ptrw() {
|
||||
_copy_on_write();
|
||||
return (T *)_get_data();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const T *ptr() const {
|
||||
return _get_data();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int size() const {
|
||||
uint32_t *size = (uint32_t *)_get_size();
|
||||
if (size) {
|
||||
return *size;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void clear() { resize(0); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
|
||||
|
||||
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
|
||||
ERR_FAIL_INDEX(p_index, size());
|
||||
_copy_on_write();
|
||||
_get_data()[p_index] = p_elem;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T &get_m(int p_index) {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
_copy_on_write();
|
||||
return _get_data()[p_index];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const T &get(int p_index) const {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
|
||||
return _get_data()[p_index];
|
||||
}
|
||||
|
||||
Error resize(int p_size);
|
||||
|
||||
_FORCE_INLINE_ void remove_at(int p_index) {
|
||||
ERR_FAIL_INDEX(p_index, size());
|
||||
T *p = ptrw();
|
||||
int len = size();
|
||||
for (int i = p_index; i < len - 1; i++) {
|
||||
p[i] = p[i + 1];
|
||||
}
|
||||
|
||||
resize(len - 1);
|
||||
}
|
||||
|
||||
Error insert(int p_pos, const T &p_val) {
|
||||
ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER);
|
||||
resize(size() + 1);
|
||||
for (int i = (size() - 1); i > p_pos; i--) {
|
||||
set(i, get(i - 1));
|
||||
}
|
||||
set(p_pos, p_val);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int find(const T &p_val, int p_from = 0) const;
|
||||
|
||||
_FORCE_INLINE_ CowData() {}
|
||||
_FORCE_INLINE_ ~CowData();
|
||||
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void CowData<T>::_unref(void *p_data) {
|
||||
if (!p_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
SafeNumeric<uint32_t> *refc = _get_refcount();
|
||||
|
||||
if (refc->decrement() > 0) {
|
||||
return; // still in use
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
uint32_t *count = _get_size();
|
||||
T *data = (T *)(count + 1);
|
||||
|
||||
for (uint32_t i = 0; i < *count; ++i) {
|
||||
// call destructors
|
||||
data[i].~T();
|
||||
}
|
||||
}
|
||||
|
||||
// free mem
|
||||
Memory::free_static((uint8_t *)p_data, true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint32_t CowData<T>::_copy_on_write() {
|
||||
if (!_ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SafeNumeric<uint32_t> *refc = _get_refcount();
|
||||
|
||||
uint32_t rc = refc->get();
|
||||
if (unlikely(rc > 1)) {
|
||||
/* in use by more than me */
|
||||
uint32_t current_size = *_get_size();
|
||||
|
||||
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
|
||||
|
||||
new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount
|
||||
*(mem_new - 1) = current_size; // size
|
||||
|
||||
T *_data = (T *)(mem_new);
|
||||
|
||||
// initialize new elements
|
||||
if (std::is_trivially_copyable<T>::value) {
|
||||
memcpy(mem_new, _ptr, current_size * sizeof(T));
|
||||
|
||||
} else {
|
||||
for (uint32_t i = 0; i < current_size; i++) {
|
||||
memnew_placement(&_data[i], T(_get_data()[i]));
|
||||
}
|
||||
}
|
||||
|
||||
_unref(_ptr);
|
||||
_ptr = _data;
|
||||
|
||||
rc = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Error CowData<T>::resize(int p_size) {
|
||||
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
|
||||
|
||||
int current_size = size();
|
||||
|
||||
if (p_size == current_size) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (p_size == 0) {
|
||||
// wants to clean up
|
||||
_unref(_ptr);
|
||||
_ptr = nullptr;
|
||||
return OK;
|
||||
}
|
||||
|
||||
// possibly changing size, copy on write
|
||||
uint32_t rc = _copy_on_write();
|
||||
|
||||
size_t current_alloc_size = _get_alloc_size(current_size);
|
||||
size_t alloc_size;
|
||||
ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
|
||||
|
||||
if (p_size > current_size) {
|
||||
if (alloc_size != current_alloc_size) {
|
||||
if (current_size == 0) {
|
||||
// alloc from scratch
|
||||
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
|
||||
ERR_FAIL_NULL_V(ptr, ERR_OUT_OF_MEMORY);
|
||||
*(ptr - 1) = 0; // size, currently none
|
||||
new (ptr - 2) SafeNumeric<uint32_t>(1); // refcount
|
||||
|
||||
_ptr = (T *)ptr;
|
||||
|
||||
} else {
|
||||
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
|
||||
ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY);
|
||||
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
|
||||
|
||||
_ptr = (T *)(_ptrnew);
|
||||
}
|
||||
}
|
||||
|
||||
// construct the newly created elements
|
||||
|
||||
if (!std::is_trivially_constructible<T>::value) {
|
||||
T *elems = _get_data();
|
||||
|
||||
for (int i = *_get_size(); i < p_size; i++) {
|
||||
memnew_placement(&elems[i], T);
|
||||
}
|
||||
}
|
||||
|
||||
*_get_size() = p_size;
|
||||
|
||||
} else if (p_size < current_size) {
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
// deinitialize no longer needed elements
|
||||
for (uint32_t i = p_size; i < *_get_size(); i++) {
|
||||
T *t = &_get_data()[i];
|
||||
t->~T();
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc_size != current_alloc_size) {
|
||||
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
|
||||
ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY);
|
||||
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
|
||||
|
||||
_ptr = (T *)(_ptrnew);
|
||||
}
|
||||
|
||||
*_get_size() = p_size;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int CowData<T>::find(const T &p_val, int p_from) const {
|
||||
int ret = -1;
|
||||
|
||||
if (p_from < 0 || size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = p_from; i < size(); i++) {
|
||||
if (get(i) == p_val) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void CowData<T>::_ref(const CowData *p_from) {
|
||||
_ref(*p_from);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void CowData<T>::_ref(const CowData &p_from) {
|
||||
if (_ptr == p_from._ptr) {
|
||||
return; // self assign, do nothing.
|
||||
}
|
||||
|
||||
_unref(_ptr);
|
||||
_ptr = nullptr;
|
||||
|
||||
if (!p_from._ptr) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
if (p_from._get_refcount()->conditional_increment() > 0) { // could reference
|
||||
_ptr = p_from._ptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
CowData<T>::~CowData() {
|
||||
_unref(_ptr);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_COWDATA_HPP
|
||||
@@ -1,591 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* hash_map.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_HASH_MAP_HPP
|
||||
#define GODOT_HASH_MAP_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/hashfuncs.hpp>
|
||||
#include <godot_cpp/templates/pair.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
/**
|
||||
* A HashMap implementation that uses open addressing with Robin Hood hashing.
|
||||
* Robin Hood hashing swaps out entries that have a smaller probing distance
|
||||
* than the to-be-inserted entry, that evens out the average probing distance
|
||||
* and enables faster lookups. Backward shift deletion is employed to further
|
||||
* improve the performance and to avoid infinite loops in rare cases.
|
||||
*
|
||||
* Keys and values are stored in a double linked list by insertion order. This
|
||||
* has a slight performance overhead on lookup, which can be mostly compensated
|
||||
* using a paged allocator if required.
|
||||
*
|
||||
* The assignment operator copy the pairs from one map to the other.
|
||||
*/
|
||||
|
||||
template <class TKey, class TValue>
|
||||
struct HashMapElement {
|
||||
HashMapElement *next = nullptr;
|
||||
HashMapElement *prev = nullptr;
|
||||
KeyValue<TKey, TValue> data;
|
||||
HashMapElement() {}
|
||||
HashMapElement(const TKey &p_key, const TValue &p_value) :
|
||||
data(p_key, p_value) {}
|
||||
};
|
||||
|
||||
template <class TKey, class TValue,
|
||||
class Hasher = HashMapHasherDefault,
|
||||
class Comparator = HashMapComparatorDefault<TKey>,
|
||||
class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
|
||||
class HashMap {
|
||||
public:
|
||||
const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
|
||||
const float MAX_OCCUPANCY = 0.75;
|
||||
const uint32_t EMPTY_HASH = 0;
|
||||
|
||||
private:
|
||||
Allocator element_alloc;
|
||||
HashMapElement<TKey, TValue> **elements = nullptr;
|
||||
uint32_t *hashes = nullptr;
|
||||
HashMapElement<TKey, TValue> *head_element = nullptr;
|
||||
HashMapElement<TKey, TValue> *tail_element = nullptr;
|
||||
|
||||
uint32_t capacity_index = 0;
|
||||
uint32_t num_elements = 0;
|
||||
|
||||
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
|
||||
uint32_t hash = Hasher::hash(p_key);
|
||||
|
||||
if (unlikely(hash == EMPTY_HASH)) {
|
||||
hash = EMPTY_HASH + 1;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
|
||||
uint32_t original_pos = p_hash % p_capacity;
|
||||
return (p_pos - original_pos + p_capacity) % p_capacity;
|
||||
}
|
||||
|
||||
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
|
||||
if (elements == nullptr) {
|
||||
return false; // Failed lookups, no elements
|
||||
}
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t hash = _hash(p_key);
|
||||
uint32_t pos = hash % capacity;
|
||||
uint32_t distance = 0;
|
||||
|
||||
while (true) {
|
||||
if (hashes[pos] == EMPTY_HASH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hashes[pos] == hash && Comparator::compare(elements[pos]->data.key, p_key)) {
|
||||
r_pos = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
pos = (pos + 1) % capacity;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t hash = p_hash;
|
||||
HashMapElement<TKey, TValue> *value = p_value;
|
||||
uint32_t distance = 0;
|
||||
uint32_t pos = hash % capacity;
|
||||
|
||||
while (true) {
|
||||
if (hashes[pos] == EMPTY_HASH) {
|
||||
elements[pos] = value;
|
||||
hashes[pos] = hash;
|
||||
|
||||
num_elements++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Not an empty slot, let's check the probing length of the existing one.
|
||||
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
|
||||
if (existing_probe_len < distance) {
|
||||
SWAP(hash, hashes[pos]);
|
||||
SWAP(value, elements[pos]);
|
||||
distance = existing_probe_len;
|
||||
}
|
||||
|
||||
pos = (pos + 1) % capacity;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
void _resize_and_rehash(uint32_t p_new_capacity_index) {
|
||||
uint32_t old_capacity = hash_table_size_primes[capacity_index];
|
||||
|
||||
// Capacity can't be 0.
|
||||
capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
|
||||
HashMapElement<TKey, TValue> **old_elements = elements;
|
||||
uint32_t *old_hashes = hashes;
|
||||
|
||||
num_elements = 0;
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
elements = reinterpret_cast<HashMapElement<TKey, TValue> **>(Memory::alloc_static(sizeof(HashMapElement<TKey, TValue> *) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = 0;
|
||||
elements[i] = nullptr;
|
||||
}
|
||||
|
||||
if (old_capacity == 0) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < old_capacity; i++) {
|
||||
if (old_hashes[i] == EMPTY_HASH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_insert_with_hash(old_hashes[i], old_elements[i]);
|
||||
}
|
||||
|
||||
Memory::free_static(old_elements);
|
||||
Memory::free_static(old_hashes);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ HashMapElement<TKey, TValue> *_insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
if (unlikely(elements == nullptr)) {
|
||||
// Allocate on demand to save memory.
|
||||
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
elements = reinterpret_cast<HashMapElement<TKey, TValue> **>(Memory::alloc_static(sizeof(HashMapElement<TKey, TValue> *) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = EMPTY_HASH;
|
||||
elements[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
elements[pos]->data.value = p_value;
|
||||
return elements[pos];
|
||||
} else {
|
||||
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
|
||||
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, nullptr, "Hash table maximum capacity reached, aborting insertion.");
|
||||
_resize_and_rehash(capacity_index + 1);
|
||||
}
|
||||
|
||||
HashMapElement<TKey, TValue> *elem = element_alloc.new_allocation(HashMapElement<TKey, TValue>(p_key, p_value));
|
||||
|
||||
if (tail_element == nullptr) {
|
||||
head_element = elem;
|
||||
tail_element = elem;
|
||||
} else if (p_front_insert) {
|
||||
head_element->prev = elem;
|
||||
elem->next = head_element;
|
||||
head_element = elem;
|
||||
} else {
|
||||
tail_element->next = elem;
|
||||
elem->prev = tail_element;
|
||||
tail_element = elem;
|
||||
}
|
||||
|
||||
uint32_t hash = _hash(p_key);
|
||||
_insert_with_hash(hash, elem);
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
|
||||
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
|
||||
|
||||
/* Standard Godot Container API */
|
||||
|
||||
bool is_empty() const {
|
||||
return num_elements == 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (elements == nullptr) {
|
||||
return;
|
||||
}
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
if (hashes[i] == EMPTY_HASH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hashes[i] = EMPTY_HASH;
|
||||
element_alloc.delete_allocation(elements[i]);
|
||||
elements[i] = nullptr;
|
||||
}
|
||||
|
||||
tail_element = nullptr;
|
||||
head_element = nullptr;
|
||||
num_elements = 0;
|
||||
}
|
||||
|
||||
TValue &get(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
CRASH_COND_MSG(!exists, "HashMap key not found.");
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
|
||||
const TValue &get(const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
CRASH_COND_MSG(!exists, "HashMap key not found.");
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
|
||||
const TValue *getptr(const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
return &elements[pos]->data.value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TValue *getptr(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
return &elements[pos]->data.value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool has(const TKey &p_key) const {
|
||||
uint32_t _pos = 0;
|
||||
return _lookup_pos(p_key, _pos);
|
||||
}
|
||||
|
||||
bool erase(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (!exists) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t next_pos = (pos + 1) % capacity;
|
||||
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
|
||||
SWAP(hashes[next_pos], hashes[pos]);
|
||||
SWAP(elements[next_pos], elements[pos]);
|
||||
pos = next_pos;
|
||||
next_pos = (pos + 1) % capacity;
|
||||
}
|
||||
|
||||
hashes[pos] = EMPTY_HASH;
|
||||
|
||||
if (head_element == elements[pos]) {
|
||||
head_element = elements[pos]->next;
|
||||
}
|
||||
|
||||
if (tail_element == elements[pos]) {
|
||||
tail_element = elements[pos]->prev;
|
||||
}
|
||||
|
||||
if (elements[pos]->prev) {
|
||||
elements[pos]->prev->next = elements[pos]->next;
|
||||
}
|
||||
|
||||
if (elements[pos]->next) {
|
||||
elements[pos]->next->prev = elements[pos]->prev;
|
||||
}
|
||||
|
||||
element_alloc.delete_allocation(elements[pos]);
|
||||
elements[pos] = nullptr;
|
||||
|
||||
num_elements--;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
|
||||
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
|
||||
void reserve(uint32_t p_new_capacity) {
|
||||
uint32_t new_index = capacity_index;
|
||||
|
||||
while (hash_table_size_primes[new_index] < p_new_capacity) {
|
||||
ERR_FAIL_COND_MSG(new_index + 1 == (uint32_t)HASH_TABLE_SIZE_MAX, nullptr);
|
||||
new_index++;
|
||||
}
|
||||
|
||||
if (new_index == capacity_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (elements == nullptr) {
|
||||
capacity_index = new_index;
|
||||
return; // Unallocated yet.
|
||||
}
|
||||
_resize_and_rehash(new_index);
|
||||
}
|
||||
|
||||
/** Iterator API **/
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const KeyValue<TKey, TValue> &operator*() const {
|
||||
return E->data;
|
||||
}
|
||||
_FORCE_INLINE_ const KeyValue<TKey, TValue> *operator->() const { return &E->data; }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
if (E) {
|
||||
E = E->next;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
if (E) {
|
||||
E = E->prev;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||
|
||||
_FORCE_INLINE_ explicit operator bool() const {
|
||||
return E != nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator(const HashMapElement<TKey, TValue> *p_E) { E = p_E; }
|
||||
_FORCE_INLINE_ ConstIterator() {}
|
||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||
_FORCE_INLINE_ void operator=(const ConstIterator &p_it) {
|
||||
E = p_it.E;
|
||||
}
|
||||
|
||||
private:
|
||||
const HashMapElement<TKey, TValue> *E = nullptr;
|
||||
};
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ KeyValue<TKey, TValue> &operator*() const {
|
||||
return E->data;
|
||||
}
|
||||
_FORCE_INLINE_ KeyValue<TKey, TValue> *operator->() const { return &E->data; }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
if (E) {
|
||||
E = E->next;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
if (E) {
|
||||
E = E->prev;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||
|
||||
_FORCE_INLINE_ explicit operator bool() const {
|
||||
return E != nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Iterator(HashMapElement<TKey, TValue> *p_E) { E = p_E; }
|
||||
_FORCE_INLINE_ Iterator() {}
|
||||
_FORCE_INLINE_ Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
|
||||
E = p_it.E;
|
||||
}
|
||||
|
||||
operator ConstIterator() const {
|
||||
return ConstIterator(E);
|
||||
}
|
||||
|
||||
private:
|
||||
HashMapElement<TKey, TValue> *E = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(head_element);
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
_FORCE_INLINE_ Iterator last() {
|
||||
return Iterator(tail_element);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Iterator find(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
if (!exists) {
|
||||
return end();
|
||||
}
|
||||
return Iterator(elements[pos]);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
|
||||
if (p_iter) {
|
||||
erase(p_iter->key);
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(head_element);
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(nullptr);
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator last() const {
|
||||
return ConstIterator(tail_element);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator find(const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
if (!exists) {
|
||||
return end();
|
||||
}
|
||||
return ConstIterator(elements[pos]);
|
||||
}
|
||||
|
||||
/* Indexing */
|
||||
|
||||
const TValue &operator[](const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
CRASH_COND(!exists);
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
|
||||
TValue &operator[](const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
if (!exists) {
|
||||
return _insert(p_key, TValue())->data.value;
|
||||
} else {
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert */
|
||||
|
||||
Iterator insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) {
|
||||
return Iterator(_insert(p_key, p_value, p_front_insert));
|
||||
}
|
||||
|
||||
/* Constructors */
|
||||
|
||||
HashMap(const HashMap &p_other) {
|
||||
reserve(hash_table_size_primes[p_other.capacity_index]);
|
||||
|
||||
if (p_other.num_elements == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const KeyValue<TKey, TValue> &E : p_other) {
|
||||
insert(E.key, E.value);
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(const HashMap &p_other) {
|
||||
if (this == &p_other) {
|
||||
return; // Ignore self assignment.
|
||||
}
|
||||
if (num_elements != 0) {
|
||||
clear();
|
||||
}
|
||||
|
||||
reserve(hash_table_size_primes[p_other.capacity_index]);
|
||||
|
||||
if (p_other.elements == nullptr) {
|
||||
return; // Nothing to copy.
|
||||
}
|
||||
|
||||
for (const KeyValue<TKey, TValue> &E : p_other) {
|
||||
insert(E.key, E.value);
|
||||
}
|
||||
}
|
||||
|
||||
HashMap(uint32_t p_initial_capacity) {
|
||||
// Capacity can't be 0.
|
||||
capacity_index = 0;
|
||||
reserve(p_initial_capacity);
|
||||
}
|
||||
HashMap() {
|
||||
capacity_index = MIN_CAPACITY_INDEX;
|
||||
}
|
||||
|
||||
uint32_t debug_get_hash(uint32_t p_index) {
|
||||
if (num_elements == 0) {
|
||||
return 0;
|
||||
}
|
||||
ERR_FAIL_INDEX_V(p_index, get_capacity(), 0);
|
||||
return hashes[p_index];
|
||||
}
|
||||
Iterator debug_get_element(uint32_t p_index) {
|
||||
if (num_elements == 0) {
|
||||
return Iterator();
|
||||
}
|
||||
ERR_FAIL_INDEX_V(p_index, get_capacity(), Iterator());
|
||||
return Iterator(elements[p_index]);
|
||||
}
|
||||
|
||||
~HashMap() {
|
||||
clear();
|
||||
|
||||
if (elements != nullptr) {
|
||||
Memory::free_static(elements);
|
||||
Memory::free_static(hashes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_HASH_MAP_HPP
|
||||
@@ -1,477 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* hash_set.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_HASH_SET_HPP
|
||||
#define GODOT_HASH_SET_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/hash_map.hpp>
|
||||
#include <godot_cpp/templates/hashfuncs.hpp>
|
||||
#include <godot_cpp/templates/pair.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
/**
|
||||
* Implementation of Set using a bidi indexed hash map.
|
||||
* Use RBSet instead of this only if the following conditions are met:
|
||||
*
|
||||
* - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
|
||||
* - Iteration order does matter (via operator<)
|
||||
*
|
||||
*/
|
||||
|
||||
template <class TKey,
|
||||
class Hasher = HashMapHasherDefault,
|
||||
class Comparator = HashMapComparatorDefault<TKey>>
|
||||
class HashSet {
|
||||
public:
|
||||
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
|
||||
static constexpr float MAX_OCCUPANCY = 0.75;
|
||||
static constexpr uint32_t EMPTY_HASH = 0;
|
||||
|
||||
private:
|
||||
TKey *keys = nullptr;
|
||||
uint32_t *hash_to_key = nullptr;
|
||||
uint32_t *key_to_hash = nullptr;
|
||||
uint32_t *hashes = nullptr;
|
||||
|
||||
uint32_t capacity_index = 0;
|
||||
uint32_t num_elements = 0;
|
||||
|
||||
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
|
||||
uint32_t hash = Hasher::hash(p_key);
|
||||
|
||||
if (unlikely(hash == EMPTY_HASH)) {
|
||||
hash = EMPTY_HASH + 1;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
|
||||
uint32_t original_pos = p_hash % p_capacity;
|
||||
return (p_pos - original_pos + p_capacity) % p_capacity;
|
||||
}
|
||||
|
||||
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
|
||||
if (keys == nullptr) {
|
||||
return false; // Failed lookups, no elements
|
||||
}
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t hash = _hash(p_key);
|
||||
uint32_t pos = hash % capacity;
|
||||
uint32_t distance = 0;
|
||||
|
||||
while (true) {
|
||||
if (hashes[pos] == EMPTY_HASH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hashes[pos] == hash && Comparator::compare(keys[hash_to_key[pos]], p_key)) {
|
||||
r_pos = hash_to_key[pos];
|
||||
return true;
|
||||
}
|
||||
|
||||
pos = (pos + 1) % capacity;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t hash = p_hash;
|
||||
uint32_t index = p_index;
|
||||
uint32_t distance = 0;
|
||||
uint32_t pos = hash % capacity;
|
||||
|
||||
while (true) {
|
||||
if (hashes[pos] == EMPTY_HASH) {
|
||||
hashes[pos] = hash;
|
||||
key_to_hash[index] = pos;
|
||||
hash_to_key[pos] = index;
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Not an empty slot, let's check the probing length of the existing one.
|
||||
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
|
||||
if (existing_probe_len < distance) {
|
||||
key_to_hash[index] = pos;
|
||||
SWAP(hash, hashes[pos]);
|
||||
SWAP(index, hash_to_key[pos]);
|
||||
distance = existing_probe_len;
|
||||
}
|
||||
|
||||
pos = (pos + 1) % capacity;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
void _resize_and_rehash(uint32_t p_new_capacity_index) {
|
||||
// Capacity can't be 0.
|
||||
capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
|
||||
uint32_t *old_hashes = hashes;
|
||||
uint32_t *old_key_to_hash = key_to_hash;
|
||||
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
keys = reinterpret_cast<TKey *>(Memory::realloc_static(keys, sizeof(TKey) * capacity));
|
||||
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
hash_to_key = reinterpret_cast<uint32_t *>(Memory::realloc_static(hash_to_key, sizeof(uint32_t) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = EMPTY_HASH;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_elements; i++) {
|
||||
uint32_t h = old_hashes[old_key_to_hash[i]];
|
||||
_insert_with_hash(h, i);
|
||||
}
|
||||
|
||||
Memory::free_static(old_hashes);
|
||||
Memory::free_static(old_key_to_hash);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int32_t _insert(const TKey &p_key) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
if (unlikely(keys == nullptr)) {
|
||||
// Allocate on demand to save memory.
|
||||
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
|
||||
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = EMPTY_HASH;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
return pos;
|
||||
} else {
|
||||
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
|
||||
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, -1, "Hash table maximum capacity reached, aborting insertion.");
|
||||
_resize_and_rehash(capacity_index + 1);
|
||||
}
|
||||
|
||||
uint32_t hash = _hash(p_key);
|
||||
memnew_placement(&keys[num_elements], TKey(p_key));
|
||||
_insert_with_hash(hash, num_elements);
|
||||
num_elements++;
|
||||
return num_elements - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void _init_from(const HashSet &p_other) {
|
||||
capacity_index = p_other.capacity_index;
|
||||
num_elements = p_other.num_elements;
|
||||
|
||||
if (p_other.num_elements == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
|
||||
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
|
||||
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||
|
||||
for (uint32_t i = 0; i < num_elements; i++) {
|
||||
memnew_placement(&keys[i], TKey(p_other.keys[i]));
|
||||
key_to_hash[i] = p_other.key_to_hash[i];
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = p_other.hashes[i];
|
||||
hash_to_key[i] = p_other.hash_to_key[i];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
|
||||
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
|
||||
|
||||
/* Standard Godot Container API */
|
||||
|
||||
bool is_empty() const {
|
||||
return num_elements == 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (keys == nullptr) {
|
||||
return;
|
||||
}
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
hashes[i] = EMPTY_HASH;
|
||||
}
|
||||
for (uint32_t i = 0; i < num_elements; i++) {
|
||||
keys[i].~TKey();
|
||||
}
|
||||
|
||||
num_elements = 0;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool has(const TKey &p_key) const {
|
||||
uint32_t _pos = 0;
|
||||
return _lookup_pos(p_key, _pos);
|
||||
}
|
||||
|
||||
bool erase(const TKey &p_key) {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (!exists) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t key_pos = pos;
|
||||
pos = key_to_hash[pos]; // make hash pos
|
||||
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
uint32_t next_pos = (pos + 1) % capacity;
|
||||
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
|
||||
uint32_t kpos = hash_to_key[pos];
|
||||
uint32_t kpos_next = hash_to_key[next_pos];
|
||||
SWAP(key_to_hash[kpos], key_to_hash[kpos_next]);
|
||||
SWAP(hashes[next_pos], hashes[pos]);
|
||||
SWAP(hash_to_key[next_pos], hash_to_key[pos]);
|
||||
|
||||
pos = next_pos;
|
||||
next_pos = (pos + 1) % capacity;
|
||||
}
|
||||
|
||||
hashes[pos] = EMPTY_HASH;
|
||||
keys[key_pos].~TKey();
|
||||
num_elements--;
|
||||
if (key_pos < num_elements) {
|
||||
// Not the last key, move the last one here to keep keys lineal
|
||||
memnew_placement(&keys[key_pos], TKey(keys[num_elements]));
|
||||
keys[num_elements].~TKey();
|
||||
key_to_hash[key_pos] = key_to_hash[num_elements];
|
||||
hash_to_key[key_to_hash[num_elements]] = key_pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
|
||||
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
|
||||
void reserve(uint32_t p_new_capacity) {
|
||||
uint32_t new_index = capacity_index;
|
||||
|
||||
while (hash_table_size_primes[new_index] < p_new_capacity) {
|
||||
ERR_FAIL_COND_MSG(new_index + 1 == (uint32_t)HASH_TABLE_SIZE_MAX, nullptr);
|
||||
new_index++;
|
||||
}
|
||||
|
||||
if (new_index == capacity_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (keys == nullptr) {
|
||||
capacity_index = new_index;
|
||||
return; // Unallocated yet.
|
||||
}
|
||||
_resize_and_rehash(new_index);
|
||||
}
|
||||
|
||||
/** Iterator API **/
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ const TKey &operator*() const {
|
||||
return keys[index];
|
||||
}
|
||||
_FORCE_INLINE_ const TKey *operator->() const {
|
||||
return &keys[index];
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
index++;
|
||||
if (index >= (int32_t)num_keys) {
|
||||
index = -1;
|
||||
keys = nullptr;
|
||||
num_keys = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
index = -1;
|
||||
keys = nullptr;
|
||||
num_keys = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return keys == b.keys && index == b.index; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return keys != b.keys || index != b.index; }
|
||||
|
||||
_FORCE_INLINE_ explicit operator bool() const {
|
||||
return keys != nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Iterator(const TKey *p_keys, uint32_t p_num_keys, int32_t p_index = -1) {
|
||||
keys = p_keys;
|
||||
num_keys = p_num_keys;
|
||||
index = p_index;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator() {}
|
||||
_FORCE_INLINE_ Iterator(const Iterator &p_it) {
|
||||
keys = p_it.keys;
|
||||
num_keys = p_it.num_keys;
|
||||
index = p_it.index;
|
||||
}
|
||||
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
|
||||
keys = p_it.keys;
|
||||
num_keys = p_it.num_keys;
|
||||
index = p_it.index;
|
||||
}
|
||||
|
||||
private:
|
||||
const TKey *keys = nullptr;
|
||||
uint32_t num_keys = 0;
|
||||
int32_t index = -1;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() const {
|
||||
return num_elements ? Iterator(keys, num_elements, 0) : Iterator();
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() const {
|
||||
return Iterator();
|
||||
}
|
||||
_FORCE_INLINE_ Iterator last() const {
|
||||
if (num_elements == 0) {
|
||||
return Iterator();
|
||||
}
|
||||
return Iterator(keys, num_elements, num_elements - 1);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Iterator find(const TKey &p_key) const {
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
if (!exists) {
|
||||
return end();
|
||||
}
|
||||
return Iterator(keys, num_elements, pos);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
|
||||
if (p_iter) {
|
||||
erase(*p_iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert */
|
||||
|
||||
Iterator insert(const TKey &p_key) {
|
||||
uint32_t pos = _insert(p_key);
|
||||
return Iterator(keys, num_elements, pos);
|
||||
}
|
||||
|
||||
/* Constructors */
|
||||
|
||||
HashSet(const HashSet &p_other) {
|
||||
_init_from(p_other);
|
||||
}
|
||||
|
||||
void operator=(const HashSet &p_other) {
|
||||
if (this == &p_other) {
|
||||
return; // Ignore self assignment.
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
if (keys != nullptr) {
|
||||
Memory::free_static(keys);
|
||||
Memory::free_static(key_to_hash);
|
||||
Memory::free_static(hash_to_key);
|
||||
Memory::free_static(hashes);
|
||||
keys = nullptr;
|
||||
hashes = nullptr;
|
||||
hash_to_key = nullptr;
|
||||
key_to_hash = nullptr;
|
||||
}
|
||||
|
||||
_init_from(p_other);
|
||||
}
|
||||
|
||||
HashSet(uint32_t p_initial_capacity) {
|
||||
// Capacity can't be 0.
|
||||
capacity_index = 0;
|
||||
reserve(p_initial_capacity);
|
||||
}
|
||||
HashSet() {
|
||||
capacity_index = MIN_CAPACITY_INDEX;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
clear();
|
||||
|
||||
if (keys != nullptr) {
|
||||
Memory::free_static(keys);
|
||||
Memory::free_static(key_to_hash);
|
||||
Memory::free_static(hash_to_key);
|
||||
Memory::free_static(hashes);
|
||||
keys = nullptr;
|
||||
hashes = nullptr;
|
||||
hash_to_key = nullptr;
|
||||
key_to_hash = nullptr;
|
||||
}
|
||||
capacity_index = MIN_CAPACITY_INDEX;
|
||||
}
|
||||
|
||||
~HashSet() {
|
||||
clear();
|
||||
|
||||
if (keys != nullptr) {
|
||||
Memory::free_static(keys);
|
||||
Memory::free_static(key_to_hash);
|
||||
Memory::free_static(hash_to_key);
|
||||
Memory::free_static(hashes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_HASH_SET_HPP
|
||||
@@ -1,526 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* hashfuncs.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_HASHFUNCS_HPP
|
||||
#define GODOT_HASHFUNCS_HPP
|
||||
|
||||
// Needed for fastmod.
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include <godot_cpp/core/math.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/variant/aabb.hpp>
|
||||
#include <godot_cpp/variant/node_path.hpp>
|
||||
#include <godot_cpp/variant/rect2.hpp>
|
||||
#include <godot_cpp/variant/rect2i.hpp>
|
||||
#include <godot_cpp/variant/rid.hpp>
|
||||
#include <godot_cpp/variant/string.hpp>
|
||||
#include <godot_cpp/variant/string_name.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
#include <godot_cpp/variant/vector2.hpp>
|
||||
#include <godot_cpp/variant/vector2i.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
#include <godot_cpp/variant/vector3i.hpp>
|
||||
#include <godot_cpp/variant/vector4.hpp>
|
||||
#include <godot_cpp/variant/vector4i.hpp>
|
||||
|
||||
/**
|
||||
* Hashing functions
|
||||
*/
|
||||
|
||||
namespace godot {
|
||||
|
||||
/**
|
||||
* DJB2 Hash function
|
||||
* @param C String
|
||||
* @return 32-bits hashcode
|
||||
*/
|
||||
static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
|
||||
const unsigned char *chr = (const unsigned char *)p_cstr;
|
||||
uint32_t hash = 5381;
|
||||
uint32_t c;
|
||||
|
||||
while ((c = *chr++)) {
|
||||
hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) {
|
||||
uint32_t hash = p_prev;
|
||||
|
||||
for (int i = 0; i < p_len; i++) {
|
||||
hash = ((hash << 5) + hash) ^ p_buff[i]; /* hash * 33 + c */
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) {
|
||||
return ((p_prev << 5) + p_prev) ^ p_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thomas Wang's 64-bit to 32-bit Hash function:
|
||||
* https://web.archive.org/web/20071223173210/https:/www.concentric.net/~Ttwang/tech/inthash.htm
|
||||
*
|
||||
* @param p_int - 64-bit unsigned integer key to be hashed
|
||||
* @return unsigned 32-bit value representing hashcode
|
||||
*/
|
||||
static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
|
||||
uint64_t v = p_int;
|
||||
v = (~v) + (v << 18); // v = (v << 18) - v - 1;
|
||||
v = v ^ (v >> 31);
|
||||
v = v * 21; // v = (v + (v << 2)) + (v << 4);
|
||||
v = v ^ (v >> 11);
|
||||
v = v + (v << 6);
|
||||
v = v ^ (v >> 22);
|
||||
return uint32_t(v);
|
||||
}
|
||||
|
||||
#define HASH_MURMUR3_SEED 0x7F07C65
|
||||
// Murmurhash3 32-bit version.
|
||||
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
p_in *= 0xcc9e2d51;
|
||||
p_in = (p_in << 15) | (p_in >> 17);
|
||||
p_in *= 0x1b873593;
|
||||
|
||||
p_seed ^= p_in;
|
||||
p_seed = (p_seed << 13) | (p_seed >> 19);
|
||||
p_seed = p_seed * 5 + 0xe6546b64;
|
||||
|
||||
return p_seed;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
|
||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||
if (p_in == 0.0f) {
|
||||
u.f = 0.0;
|
||||
} else if (Math::is_nan(p_in)) {
|
||||
u.f = NAN;
|
||||
} else {
|
||||
u.f = p_in;
|
||||
}
|
||||
|
||||
return hash_murmur3_one_32(u.i, p_seed);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed);
|
||||
return hash_murmur3_one_32(p_in >> 32, p_seed);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
|
||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||
if (p_in == 0.0f) {
|
||||
u.d = 0.0;
|
||||
} else if (Math::is_nan(p_in)) {
|
||||
u.d = NAN;
|
||||
} else {
|
||||
u.d = p_in;
|
||||
}
|
||||
|
||||
return hash_murmur3_one_64(u.i, p_seed);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
return hash_murmur3_one_double(p_in, p_seed);
|
||||
#else
|
||||
return hash_murmur3_one_float(p_in, p_seed);
|
||||
#endif
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) {
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) {
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length, const uint32_t seed = HASH_MURMUR3_SEED) {
|
||||
// Although not required, this is a random prime number.
|
||||
const uint8_t *data = (const uint8_t *)key;
|
||||
const int nblocks = length / 4;
|
||||
|
||||
uint32_t h1 = seed;
|
||||
|
||||
const uint32_t c1 = 0xcc9e2d51;
|
||||
const uint32_t c2 = 0x1b873593;
|
||||
|
||||
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
|
||||
|
||||
for (int i = -nblocks; i; i++) {
|
||||
uint32_t k1 = blocks[i];
|
||||
|
||||
k1 *= c1;
|
||||
k1 = hash_rotl32(k1, 15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = hash_rotl32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
|
||||
switch (length & 3) {
|
||||
case 3:
|
||||
k1 ^= tail[2] << 16;
|
||||
[[fallthrough]];
|
||||
case 2:
|
||||
k1 ^= tail[1] << 8;
|
||||
[[fallthrough]];
|
||||
case 1:
|
||||
k1 ^= tail[0];
|
||||
k1 *= c1;
|
||||
k1 = hash_rotl32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
}
|
||||
|
||||
// Finalize with additional bit mixing.
|
||||
h1 ^= length;
|
||||
return hash_fmix32(h1);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
|
||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||
if (p_in == 0.0f) {
|
||||
u.d = 0.0;
|
||||
} else if (Math::is_nan(p_in)) {
|
||||
u.d = NAN;
|
||||
} else {
|
||||
u.d = p_in;
|
||||
}
|
||||
|
||||
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
|
||||
union {
|
||||
T t;
|
||||
uint32_t _u32;
|
||||
} _u;
|
||||
_u._u32 = 0;
|
||||
_u.t = p_in;
|
||||
return _u._u32;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
|
||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||
if (p_in == 0.0f) {
|
||||
u.d = 0.0;
|
||||
} else if (Math::is_nan(p_in)) {
|
||||
u.d = NAN;
|
||||
} else {
|
||||
u.d = p_in;
|
||||
}
|
||||
|
||||
return ((p_prev << 5) + p_prev) + u.i;
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) {
|
||||
return ((p_prev << 5) + p_prev) ^ p_in;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
|
||||
union {
|
||||
T t;
|
||||
uint64_t _u64;
|
||||
} _u;
|
||||
_u._u64 = 0; // in case p_in is smaller
|
||||
|
||||
_u.t = p_in;
|
||||
return _u._u64;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class Ref;
|
||||
|
||||
struct HashMapHasherDefault {
|
||||
// Generic hash function for any type.
|
||||
template <class T>
|
||||
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
|
||||
|
||||
template <class T>
|
||||
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(p_wchar); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
|
||||
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(p_int); }
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_32(p_vec.x);
|
||||
h = hash_murmur3_one_32(p_vec.y, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_32(p_vec.x);
|
||||
h = hash_murmur3_one_32(p_vec.y, h);
|
||||
h = hash_murmur3_one_32(p_vec.z, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_32(p_vec.x);
|
||||
h = hash_murmur3_one_32(p_vec.y, h);
|
||||
h = hash_murmur3_one_32(p_vec.z, h);
|
||||
h = hash_murmur3_one_32(p_vec.w, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_real(p_vec.x);
|
||||
h = hash_murmur3_one_real(p_vec.y, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_real(p_vec.x);
|
||||
h = hash_murmur3_one_real(p_vec.y, h);
|
||||
h = hash_murmur3_one_real(p_vec.z, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Vector4 &p_vec) {
|
||||
uint32_t h = hash_murmur3_one_real(p_vec.x);
|
||||
h = hash_murmur3_one_real(p_vec.y, h);
|
||||
h = hash_murmur3_one_real(p_vec.z, h);
|
||||
h = hash_murmur3_one_real(p_vec.w, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
|
||||
uint32_t h = hash_murmur3_one_32(p_rect.position.x);
|
||||
h = hash_murmur3_one_32(p_rect.position.y, h);
|
||||
h = hash_murmur3_one_32(p_rect.size.x, h);
|
||||
h = hash_murmur3_one_32(p_rect.size.y, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) {
|
||||
uint32_t h = hash_murmur3_one_real(p_rect.position.x);
|
||||
h = hash_murmur3_one_real(p_rect.position.y, h);
|
||||
h = hash_murmur3_one_real(p_rect.size.x, h);
|
||||
h = hash_murmur3_one_real(p_rect.size.y, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) {
|
||||
uint32_t h = hash_murmur3_one_real(p_aabb.position.x);
|
||||
h = hash_murmur3_one_real(p_aabb.position.y, h);
|
||||
h = hash_murmur3_one_real(p_aabb.position.z, h);
|
||||
h = hash_murmur3_one_real(p_aabb.size.x, h);
|
||||
h = hash_murmur3_one_real(p_aabb.size.y, h);
|
||||
h = hash_murmur3_one_real(p_aabb.size.z, h);
|
||||
return hash_fmix32(h);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct HashMapComparatorDefault {
|
||||
static bool compare(const T &p_lhs, const T &p_rhs) {
|
||||
return p_lhs == p_rhs;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashMapComparatorDefault<float> {
|
||||
static bool compare(const float &p_lhs, const float &p_rhs) {
|
||||
return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashMapComparatorDefault<double> {
|
||||
static bool compare(const double &p_lhs, const double &p_rhs) {
|
||||
return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashMapComparatorDefault<Vector2> {
|
||||
static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) {
|
||||
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y)));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashMapComparatorDefault<Vector3> {
|
||||
static bool compare(const Vector3 &p_lhs, const Vector3 &p_rhs) {
|
||||
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z)));
|
||||
}
|
||||
};
|
||||
|
||||
constexpr uint32_t HASH_TABLE_SIZE_MAX = 29;
|
||||
|
||||
const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
|
||||
5,
|
||||
13,
|
||||
23,
|
||||
47,
|
||||
97,
|
||||
193,
|
||||
389,
|
||||
769,
|
||||
1543,
|
||||
3079,
|
||||
6151,
|
||||
12289,
|
||||
24593,
|
||||
49157,
|
||||
98317,
|
||||
196613,
|
||||
393241,
|
||||
786433,
|
||||
1572869,
|
||||
3145739,
|
||||
6291469,
|
||||
12582917,
|
||||
25165843,
|
||||
50331653,
|
||||
100663319,
|
||||
201326611,
|
||||
402653189,
|
||||
805306457,
|
||||
1610612741,
|
||||
};
|
||||
|
||||
// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array.
|
||||
const uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
|
||||
3689348814741910324,
|
||||
1418980313362273202,
|
||||
802032351030850071,
|
||||
392483916461905354,
|
||||
190172619316593316,
|
||||
95578984837873325,
|
||||
47420935922132524,
|
||||
23987963684927896,
|
||||
11955116055547344,
|
||||
5991147799191151,
|
||||
2998982941588287,
|
||||
1501077717772769,
|
||||
750081082979285,
|
||||
375261795343686,
|
||||
187625172388393,
|
||||
93822606204624,
|
||||
46909513691883,
|
||||
23456218233098,
|
||||
11728086747027,
|
||||
5864041509391,
|
||||
2932024948977,
|
||||
1466014921160,
|
||||
733007198436,
|
||||
366503839517,
|
||||
183251896093,
|
||||
91625960335,
|
||||
45812983922,
|
||||
22906489714,
|
||||
11453246088
|
||||
};
|
||||
|
||||
/**
|
||||
* Fastmod computes ( n mod d ) given the precomputed c much faster than n % d.
|
||||
* The implementation of fastmod is based on the following paper by Daniel Lemire et al.
|
||||
* Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries
|
||||
* https://arxiv.org/abs/1902.01961
|
||||
*/
|
||||
static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const uint32_t d) {
|
||||
#if defined(_MSC_VER)
|
||||
// Returns the upper 64 bits of the product of two 64-bit unsigned integers.
|
||||
// This intrinsic function is required since MSVC does not support unsigned 128-bit integers.
|
||||
#if defined(_M_X64) || defined(_M_ARM64)
|
||||
return __umulh(c * n, d);
|
||||
#else
|
||||
// Fallback to the slower method for 32-bit platforms.
|
||||
return n % d;
|
||||
#endif // _M_X64 || _M_ARM64
|
||||
#else
|
||||
#ifdef __SIZEOF_INT128__
|
||||
// Prevent compiler warning, because we know what we are doing.
|
||||
uint64_t lowbits = c * n;
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
return static_cast<uint64_t>(((uint128)lowbits * d) >> 64);
|
||||
#else
|
||||
// Fallback to the slower method if no 128-bit unsigned integer type is available.
|
||||
return n % d;
|
||||
#endif // __SIZEOF_INT128__
|
||||
#endif // _MSC_VER
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_HASHFUNCS_HPP
|
||||
@@ -1,769 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* list.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_LIST_HPP
|
||||
#define GODOT_LIST_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/sort_array.hpp>
|
||||
|
||||
/**
|
||||
* Generic Templatized Linked List Implementation.
|
||||
* The implementation differs from the STL one because
|
||||
* a compatible preallocated linked list can be written
|
||||
* using the same API, or features such as erasing an element
|
||||
* from the iterator.
|
||||
*/
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, class A = DefaultAllocator>
|
||||
class List {
|
||||
struct _Data;
|
||||
|
||||
public:
|
||||
class Element {
|
||||
private:
|
||||
friend class List<T, A>;
|
||||
|
||||
T value;
|
||||
Element *next_ptr = nullptr;
|
||||
Element *prev_ptr = nullptr;
|
||||
_Data *data = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Get NEXT Element iterator, for constant lists.
|
||||
*/
|
||||
_FORCE_INLINE_ const Element *next() const {
|
||||
return next_ptr;
|
||||
}
|
||||
/**
|
||||
* Get NEXT Element iterator,
|
||||
*/
|
||||
_FORCE_INLINE_ Element *next() {
|
||||
return next_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PREV Element iterator, for constant lists.
|
||||
*/
|
||||
_FORCE_INLINE_ const Element *prev() const {
|
||||
return prev_ptr;
|
||||
}
|
||||
/**
|
||||
* Get PREV Element iterator,
|
||||
*/
|
||||
_FORCE_INLINE_ Element *prev() {
|
||||
return prev_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* * operator, for using as *iterator, when iterators are defined on stack.
|
||||
*/
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* operator->, for using as iterator->, when iterators are defined on stack, for constant lists.
|
||||
*/
|
||||
_FORCE_INLINE_ const T *operator->() const {
|
||||
return &value;
|
||||
}
|
||||
/**
|
||||
* * operator, for using as *iterator, when iterators are defined on stack,
|
||||
*/
|
||||
_FORCE_INLINE_ T &operator*() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* operator->, for using as iterator->, when iterators are defined on stack, for constant lists.
|
||||
*/
|
||||
_FORCE_INLINE_ T *operator->() {
|
||||
return &value;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the value stored in this element.
|
||||
*/
|
||||
_FORCE_INLINE_ T &get() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* get the value stored in this element, for constant lists
|
||||
*/
|
||||
_FORCE_INLINE_ const T &get() const {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* set the value stored in this element.
|
||||
*/
|
||||
_FORCE_INLINE_ void set(const T &p_value) {
|
||||
value = (T &)p_value;
|
||||
}
|
||||
|
||||
void erase() {
|
||||
data->erase(this);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Element() {}
|
||||
};
|
||||
|
||||
typedef T ValueType;
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
return E->get();
|
||||
}
|
||||
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||
|
||||
Iterator(Element *p_E) { E = p_E; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
Element *E = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return E->get();
|
||||
}
|
||||
_FORCE_INLINE_ const T *operator->() const { return &E->get(); }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||
|
||||
_FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
|
||||
_FORCE_INLINE_ ConstIterator() {}
|
||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
const Element *E = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ Iterator find(const K &p_key) {
|
||||
return Iterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(nullptr);
|
||||
}
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
|
||||
return ConstIterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
struct _Data {
|
||||
Element *first = nullptr;
|
||||
Element *last = nullptr;
|
||||
int size_cache = 0;
|
||||
|
||||
bool erase(const Element *p_I) {
|
||||
ERR_FAIL_NULL_V(p_I, false);
|
||||
ERR_FAIL_COND_V(p_I->data != this, false);
|
||||
|
||||
if (first == p_I) {
|
||||
first = p_I->next_ptr;
|
||||
}
|
||||
|
||||
if (last == p_I) {
|
||||
last = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
if (p_I->prev_ptr) {
|
||||
p_I->prev_ptr->next_ptr = p_I->next_ptr;
|
||||
}
|
||||
|
||||
if (p_I->next_ptr) {
|
||||
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
memdelete_allocator<Element, A>(const_cast<Element *>(p_I));
|
||||
size_cache--;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
_Data *_data = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* return a const iterator to the beginning of the list.
|
||||
*/
|
||||
_FORCE_INLINE_ const Element *front() const {
|
||||
return _data ? _data->first : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an iterator to the beginning of the list.
|
||||
*/
|
||||
_FORCE_INLINE_ Element *front() {
|
||||
return _data ? _data->first : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a const iterator to the last member of the list.
|
||||
*/
|
||||
_FORCE_INLINE_ const Element *back() const {
|
||||
return _data ? _data->last : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an iterator to the last member of the list.
|
||||
*/
|
||||
_FORCE_INLINE_ Element *back() {
|
||||
return _data ? _data->last : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* store a new element at the end of the list
|
||||
*/
|
||||
Element *push_back(const T &value) {
|
||||
if (!_data) {
|
||||
_data = memnew_allocator(_Data, A);
|
||||
_data->first = nullptr;
|
||||
_data->last = nullptr;
|
||||
_data->size_cache = 0;
|
||||
}
|
||||
|
||||
Element *n = memnew_allocator(Element, A);
|
||||
n->value = (T &)value;
|
||||
|
||||
n->prev_ptr = _data->last;
|
||||
n->next_ptr = nullptr;
|
||||
n->data = _data;
|
||||
|
||||
if (_data->last) {
|
||||
_data->last->next_ptr = n;
|
||||
}
|
||||
|
||||
_data->last = n;
|
||||
|
||||
if (!_data->first) {
|
||||
_data->first = n;
|
||||
}
|
||||
|
||||
_data->size_cache++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
if (_data && _data->last) {
|
||||
erase(_data->last);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* store a new element at the beginning of the list
|
||||
*/
|
||||
Element *push_front(const T &value) {
|
||||
if (!_data) {
|
||||
_data = memnew_allocator(_Data, A);
|
||||
_data->first = nullptr;
|
||||
_data->last = nullptr;
|
||||
_data->size_cache = 0;
|
||||
}
|
||||
|
||||
Element *n = memnew_allocator(Element, A);
|
||||
n->value = (T &)value;
|
||||
n->prev_ptr = nullptr;
|
||||
n->next_ptr = _data->first;
|
||||
n->data = _data;
|
||||
|
||||
if (_data->first) {
|
||||
_data->first->prev_ptr = n;
|
||||
}
|
||||
|
||||
_data->first = n;
|
||||
|
||||
if (!_data->last) {
|
||||
_data->last = n;
|
||||
}
|
||||
|
||||
_data->size_cache++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void pop_front() {
|
||||
if (_data && _data->first) {
|
||||
erase(_data->first);
|
||||
}
|
||||
}
|
||||
|
||||
Element *insert_after(Element *p_element, const T &p_value) {
|
||||
CRASH_COND(p_element && (!_data || p_element->data != _data));
|
||||
|
||||
if (!p_element) {
|
||||
return push_back(p_value);
|
||||
}
|
||||
|
||||
Element *n = memnew_allocator(Element, A);
|
||||
n->value = (T &)p_value;
|
||||
n->prev_ptr = p_element;
|
||||
n->next_ptr = p_element->next_ptr;
|
||||
n->data = _data;
|
||||
|
||||
if (!p_element->next_ptr) {
|
||||
_data->last = n;
|
||||
} else {
|
||||
p_element->next_ptr->prev_ptr = n;
|
||||
}
|
||||
|
||||
p_element->next_ptr = n;
|
||||
|
||||
_data->size_cache++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
Element *insert_before(Element *p_element, const T &p_value) {
|
||||
CRASH_COND(p_element && (!_data || p_element->data != _data));
|
||||
|
||||
if (!p_element) {
|
||||
return push_back(p_value);
|
||||
}
|
||||
|
||||
Element *n = memnew_allocator(Element, A);
|
||||
n->value = (T &)p_value;
|
||||
n->prev_ptr = p_element->prev_ptr;
|
||||
n->next_ptr = p_element;
|
||||
n->data = _data;
|
||||
|
||||
if (!p_element->prev_ptr) {
|
||||
_data->first = n;
|
||||
} else {
|
||||
p_element->prev_ptr->next_ptr = n;
|
||||
}
|
||||
|
||||
p_element->prev_ptr = n;
|
||||
|
||||
_data->size_cache++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* find an element in the list,
|
||||
*/
|
||||
template <class T_v>
|
||||
Element *find(const T_v &p_val) {
|
||||
Element *it = front();
|
||||
while (it) {
|
||||
if (it->value == p_val) {
|
||||
return it;
|
||||
}
|
||||
it = it->next();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* erase an element in the list, by iterator pointing to it. Return true if it was found/erased.
|
||||
*/
|
||||
bool erase(const Element *p_I) {
|
||||
if (_data && p_I) {
|
||||
bool ret = _data->erase(p_I);
|
||||
|
||||
if (_data->size_cache == 0) {
|
||||
memdelete_allocator<_Data, A>(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* erase the first element in the list, that contains value
|
||||
*/
|
||||
bool erase(const T &value) {
|
||||
Element *I = find(value);
|
||||
return erase(I);
|
||||
}
|
||||
|
||||
/**
|
||||
* return whether the list is empty
|
||||
*/
|
||||
_FORCE_INLINE_ bool is_empty() const {
|
||||
return (!_data || !_data->size_cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear the list
|
||||
*/
|
||||
void clear() {
|
||||
while (front()) {
|
||||
erase(front());
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int size() const {
|
||||
return _data ? _data->size_cache : 0;
|
||||
}
|
||||
|
||||
void swap(Element *p_A, Element *p_B) {
|
||||
ERR_FAIL_COND(!p_A || !p_B);
|
||||
ERR_FAIL_COND(p_A->data != _data);
|
||||
ERR_FAIL_COND(p_B->data != _data);
|
||||
|
||||
if (p_A == p_B) {
|
||||
return;
|
||||
}
|
||||
Element *A_prev = p_A->prev_ptr;
|
||||
Element *A_next = p_A->next_ptr;
|
||||
Element *B_prev = p_B->prev_ptr;
|
||||
Element *B_next = p_B->next_ptr;
|
||||
|
||||
if (A_prev) {
|
||||
A_prev->next_ptr = p_B;
|
||||
} else {
|
||||
_data->first = p_B;
|
||||
}
|
||||
if (B_prev) {
|
||||
B_prev->next_ptr = p_A;
|
||||
} else {
|
||||
_data->first = p_A;
|
||||
}
|
||||
if (A_next) {
|
||||
A_next->prev_ptr = p_B;
|
||||
} else {
|
||||
_data->last = p_B;
|
||||
}
|
||||
if (B_next) {
|
||||
B_next->prev_ptr = p_A;
|
||||
} else {
|
||||
_data->last = p_A;
|
||||
}
|
||||
p_A->prev_ptr = A_next == p_B ? p_B : B_prev;
|
||||
p_A->next_ptr = B_next == p_A ? p_B : B_next;
|
||||
p_B->prev_ptr = B_next == p_A ? p_A : A_prev;
|
||||
p_B->next_ptr = A_next == p_B ? p_A : A_next;
|
||||
}
|
||||
/**
|
||||
* copy the list
|
||||
*/
|
||||
void operator=(const List &p_list) {
|
||||
clear();
|
||||
const Element *it = p_list.front();
|
||||
while (it) {
|
||||
push_back(it->get());
|
||||
it = it->next();
|
||||
}
|
||||
}
|
||||
|
||||
T &operator[](int p_index) {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
|
||||
Element *I = front();
|
||||
int c = 0;
|
||||
while (c < p_index) {
|
||||
I = I->next();
|
||||
c++;
|
||||
}
|
||||
|
||||
return I->get();
|
||||
}
|
||||
|
||||
const T &operator[](int p_index) const {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
|
||||
const Element *I = front();
|
||||
int c = 0;
|
||||
while (c < p_index) {
|
||||
I = I->next();
|
||||
c++;
|
||||
}
|
||||
|
||||
return I->get();
|
||||
}
|
||||
|
||||
void move_to_back(Element *p_I) {
|
||||
ERR_FAIL_COND(p_I->data != _data);
|
||||
if (!p_I->next_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_data->first == p_I) {
|
||||
_data->first = p_I->next_ptr;
|
||||
}
|
||||
|
||||
if (_data->last == p_I) {
|
||||
_data->last = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
if (p_I->prev_ptr) {
|
||||
p_I->prev_ptr->next_ptr = p_I->next_ptr;
|
||||
}
|
||||
|
||||
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
|
||||
|
||||
_data->last->next_ptr = p_I;
|
||||
p_I->prev_ptr = _data->last;
|
||||
p_I->next_ptr = nullptr;
|
||||
_data->last = p_I;
|
||||
}
|
||||
|
||||
void reverse() {
|
||||
int s = size() / 2;
|
||||
Element *F = front();
|
||||
Element *B = back();
|
||||
for (int i = 0; i < s; i++) {
|
||||
SWAP(F->value, B->value);
|
||||
F = F->next();
|
||||
B = B->prev();
|
||||
}
|
||||
}
|
||||
|
||||
void move_to_front(Element *p_I) {
|
||||
ERR_FAIL_COND(p_I->data != _data);
|
||||
if (!p_I->prev_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_data->first == p_I) {
|
||||
_data->first = p_I->next_ptr;
|
||||
}
|
||||
|
||||
if (_data->last == p_I) {
|
||||
_data->last = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
p_I->prev_ptr->next_ptr = p_I->next_ptr;
|
||||
|
||||
if (p_I->next_ptr) {
|
||||
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
|
||||
}
|
||||
|
||||
_data->first->prev_ptr = p_I;
|
||||
p_I->next_ptr = _data->first;
|
||||
p_I->prev_ptr = nullptr;
|
||||
_data->first = p_I;
|
||||
}
|
||||
|
||||
void move_before(Element *value, Element *where) {
|
||||
if (value->prev_ptr) {
|
||||
value->prev_ptr->next_ptr = value->next_ptr;
|
||||
} else {
|
||||
_data->first = value->next_ptr;
|
||||
}
|
||||
if (value->next_ptr) {
|
||||
value->next_ptr->prev_ptr = value->prev_ptr;
|
||||
} else {
|
||||
_data->last = value->prev_ptr;
|
||||
}
|
||||
|
||||
value->next_ptr = where;
|
||||
if (!where) {
|
||||
value->prev_ptr = _data->last;
|
||||
_data->last = value;
|
||||
return;
|
||||
}
|
||||
|
||||
value->prev_ptr = where->prev_ptr;
|
||||
|
||||
if (where->prev_ptr) {
|
||||
where->prev_ptr->next_ptr = value;
|
||||
} else {
|
||||
_data->first = value;
|
||||
}
|
||||
|
||||
where->prev_ptr = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* simple insertion sort
|
||||
*/
|
||||
|
||||
void sort() {
|
||||
sort_custom<Comparator<T>>();
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void sort_custom_inplace() {
|
||||
if (size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
Element *from = front();
|
||||
Element *current = from;
|
||||
Element *to = from;
|
||||
|
||||
while (current) {
|
||||
Element *next = current->next_ptr;
|
||||
|
||||
if (from != current) {
|
||||
current->prev_ptr = nullptr;
|
||||
current->next_ptr = from;
|
||||
|
||||
Element *find = from;
|
||||
C less;
|
||||
while (find && less(find->value, current->value)) {
|
||||
current->prev_ptr = find;
|
||||
current->next_ptr = find->next_ptr;
|
||||
find = find->next_ptr;
|
||||
}
|
||||
|
||||
if (current->prev_ptr) {
|
||||
current->prev_ptr->next_ptr = current;
|
||||
} else {
|
||||
from = current;
|
||||
}
|
||||
|
||||
if (current->next_ptr) {
|
||||
current->next_ptr->prev_ptr = current;
|
||||
} else {
|
||||
to = current;
|
||||
}
|
||||
} else {
|
||||
current->prev_ptr = nullptr;
|
||||
current->next_ptr = nullptr;
|
||||
}
|
||||
|
||||
current = next;
|
||||
}
|
||||
_data->first = from;
|
||||
_data->last = to;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
struct AuxiliaryComparator {
|
||||
C compare;
|
||||
_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
|
||||
return compare(a->value, b->value);
|
||||
}
|
||||
};
|
||||
|
||||
template <class C>
|
||||
void sort_custom() {
|
||||
// this version uses auxiliary memory for speed.
|
||||
// if you don't want to use auxiliary memory, use the in_place version
|
||||
|
||||
int s = size();
|
||||
if (s < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
Element **aux_buffer = memnew_arr(Element *, s);
|
||||
|
||||
int idx = 0;
|
||||
for (Element *E = front(); E; E = E->next_ptr) {
|
||||
aux_buffer[idx] = E;
|
||||
idx++;
|
||||
}
|
||||
|
||||
SortArray<Element *, AuxiliaryComparator<C>> sort;
|
||||
sort.sort(aux_buffer, s);
|
||||
|
||||
_data->first = aux_buffer[0];
|
||||
aux_buffer[0]->prev_ptr = nullptr;
|
||||
aux_buffer[0]->next_ptr = aux_buffer[1];
|
||||
|
||||
_data->last = aux_buffer[s - 1];
|
||||
aux_buffer[s - 1]->prev_ptr = aux_buffer[s - 2];
|
||||
aux_buffer[s - 1]->next_ptr = nullptr;
|
||||
|
||||
for (int i = 1; i < s - 1; i++) {
|
||||
aux_buffer[i]->prev_ptr = aux_buffer[i - 1];
|
||||
aux_buffer[i]->next_ptr = aux_buffer[i + 1];
|
||||
}
|
||||
|
||||
memdelete_arr(aux_buffer);
|
||||
}
|
||||
|
||||
const void *id() const {
|
||||
return (void *)_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* copy constructor for the list
|
||||
*/
|
||||
List(const List &p_list) {
|
||||
const Element *it = p_list.front();
|
||||
while (it) {
|
||||
push_back(it->get());
|
||||
it = it->next();
|
||||
}
|
||||
}
|
||||
|
||||
List() {}
|
||||
|
||||
~List() {
|
||||
clear();
|
||||
if (_data) {
|
||||
ERR_FAIL_COND(_data->size_cache);
|
||||
memdelete_allocator<_Data, A>(_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_LIST_HPP
|
||||
@@ -1,339 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* local_vector.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_LOCAL_VECTOR_HPP
|
||||
#define GODOT_LOCAL_VECTOR_HPP
|
||||
|
||||
#include "godot_cpp/core/error_macros.hpp"
|
||||
#include "godot_cpp/core/memory.hpp"
|
||||
#include "godot_cpp/templates/sort_array.hpp"
|
||||
#include "godot_cpp/templates/vector.hpp"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
|
||||
namespace godot {
|
||||
|
||||
// If tight, it grows strictly as much as needed.
|
||||
// Otherwise, it grows exponentially (the default and what you want in most cases).
|
||||
template <class T, class U = uint32_t, bool force_trivial = false, bool tight = false>
|
||||
class LocalVector {
|
||||
private:
|
||||
U count = 0;
|
||||
U capacity = 0;
|
||||
T *data = nullptr;
|
||||
|
||||
public:
|
||||
T *ptr() {
|
||||
return data;
|
||||
}
|
||||
|
||||
const T *ptr() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void push_back(T p_elem) {
|
||||
if (unlikely(count == capacity)) {
|
||||
if (capacity == 0) {
|
||||
capacity = 1;
|
||||
} else {
|
||||
capacity <<= 1;
|
||||
}
|
||||
data = (T *)memrealloc(data, capacity * sizeof(T));
|
||||
CRASH_COND_MSG(!data, "Out of memory");
|
||||
}
|
||||
|
||||
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
|
||||
memnew_placement(&data[count++], T(p_elem));
|
||||
} else {
|
||||
data[count++] = p_elem;
|
||||
}
|
||||
}
|
||||
|
||||
void remove_at(U p_index) {
|
||||
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
|
||||
count--;
|
||||
for (U i = p_index; i < count; i++) {
|
||||
data[i] = data[i + 1];
|
||||
}
|
||||
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
|
||||
data[count].~T();
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the item copying the last value into the position of the one to
|
||||
/// remove. It's generally faster than `remove`.
|
||||
void remove_at_unordered(U p_index) {
|
||||
ERR_FAIL_INDEX(p_index, count);
|
||||
count--;
|
||||
if (count > p_index) {
|
||||
data[p_index] = data[count];
|
||||
}
|
||||
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
|
||||
data[count].~T();
|
||||
}
|
||||
}
|
||||
|
||||
void erase(const T &p_val) {
|
||||
int64_t idx = find(p_val);
|
||||
if (idx >= 0) {
|
||||
remove_at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void invert() {
|
||||
for (U i = 0; i < count / 2; i++) {
|
||||
SWAP(data[i], data[count - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void clear() { resize(0); }
|
||||
_FORCE_INLINE_ void reset() {
|
||||
clear();
|
||||
if (data) {
|
||||
memfree(data);
|
||||
data = nullptr;
|
||||
capacity = 0;
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ bool is_empty() const { return count == 0; }
|
||||
_FORCE_INLINE_ U get_capacity() const { return capacity; }
|
||||
_FORCE_INLINE_ void reserve(U p_size) {
|
||||
p_size = tight ? p_size : nearest_power_of_2_templated(p_size);
|
||||
if (p_size > capacity) {
|
||||
capacity = p_size;
|
||||
data = (T *)memrealloc(data, capacity * sizeof(T));
|
||||
CRASH_COND_MSG(!data, "Out of memory");
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ U size() const { return count; }
|
||||
void resize(U p_size) {
|
||||
if (p_size < count) {
|
||||
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
|
||||
for (U i = p_size; i < count; i++) {
|
||||
data[i].~T();
|
||||
}
|
||||
}
|
||||
count = p_size;
|
||||
} else if (p_size > count) {
|
||||
if (unlikely(p_size > capacity)) {
|
||||
if (capacity == 0) {
|
||||
capacity = 1;
|
||||
}
|
||||
while (capacity < p_size) {
|
||||
capacity <<= 1;
|
||||
}
|
||||
data = (T *)memrealloc(data, capacity * sizeof(T));
|
||||
CRASH_COND_MSG(!data, "Out of memory");
|
||||
}
|
||||
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
|
||||
for (U i = count; i < p_size; i++) {
|
||||
memnew_placement(&data[i], T);
|
||||
}
|
||||
}
|
||||
count = p_size;
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ const T &operator[](U p_index) const {
|
||||
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
|
||||
return data[p_index];
|
||||
}
|
||||
_FORCE_INLINE_ T &operator[](U p_index) {
|
||||
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
|
||||
return data[p_index];
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
return *elem_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
elem_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
elem_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
|
||||
|
||||
Iterator(T *p_ptr) { elem_ptr = p_ptr; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
|
||||
|
||||
private:
|
||||
T *elem_ptr = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return *elem_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
elem_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
elem_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
|
||||
|
||||
ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
|
||||
ConstIterator() {}
|
||||
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
|
||||
|
||||
private:
|
||||
const T *elem_ptr = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(data);
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(data + size());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(ptr());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(ptr() + size());
|
||||
}
|
||||
|
||||
void insert(U p_pos, T p_val) {
|
||||
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
|
||||
if (p_pos == count) {
|
||||
push_back(p_val);
|
||||
} else {
|
||||
resize(count + 1);
|
||||
for (U i = count - 1; i > p_pos; i--) {
|
||||
data[i] = data[i - 1];
|
||||
}
|
||||
data[p_pos] = p_val;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t find(const T &p_val, U p_from = 0) const {
|
||||
for (U i = p_from; i < count; i++) {
|
||||
if (data[i] == p_val) {
|
||||
return int64_t(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void sort_custom() {
|
||||
U len = count;
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SortArray<T, C> sorter;
|
||||
sorter.sort(data, len);
|
||||
}
|
||||
|
||||
void sort() {
|
||||
sort_custom<_DefaultComparator<T>>();
|
||||
}
|
||||
|
||||
void ordered_insert(T p_val) {
|
||||
U i;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (p_val < data[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
insert(i, p_val);
|
||||
}
|
||||
|
||||
operator Vector<T>() const {
|
||||
Vector<T> ret;
|
||||
ret.resize(size());
|
||||
T *w = ret.ptrw();
|
||||
memcpy(w, data, sizeof(T) * count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
|
||||
Vector<uint8_t> ret;
|
||||
ret.resize(count * sizeof(T));
|
||||
uint8_t *w = ret.ptrw();
|
||||
memcpy(w, data, sizeof(T) * count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ LocalVector() {}
|
||||
_FORCE_INLINE_ LocalVector(std::initializer_list<T> p_init) {
|
||||
reserve(p_init.size());
|
||||
for (const T &element : p_init) {
|
||||
push_back(element);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ LocalVector(const LocalVector &p_from) {
|
||||
resize(p_from.size());
|
||||
for (U i = 0; i < p_from.count; i++) {
|
||||
data[i] = p_from.data[i];
|
||||
}
|
||||
}
|
||||
inline void operator=(const LocalVector &p_from) {
|
||||
resize(p_from.size());
|
||||
for (U i = 0; i < p_from.count; i++) {
|
||||
data[i] = p_from.data[i];
|
||||
}
|
||||
}
|
||||
inline void operator=(const Vector<T> &p_from) {
|
||||
resize(p_from.size());
|
||||
for (U i = 0; i < count; i++) {
|
||||
data[i] = p_from[i];
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ~LocalVector() {
|
||||
if (data) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class U = uint32_t, bool force_trivial = false>
|
||||
using TightLocalVector = LocalVector<T, U, force_trivial, true>;
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_LOCAL_VECTOR_HPP
|
||||
@@ -1,107 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* pair.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_PAIR_HPP
|
||||
#define GODOT_PAIR_HPP
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class F, class S>
|
||||
struct Pair {
|
||||
F first;
|
||||
S second;
|
||||
|
||||
Pair() :
|
||||
first(),
|
||||
second() {
|
||||
}
|
||||
|
||||
Pair(F p_first, const S &p_second) :
|
||||
first(p_first),
|
||||
second(p_second) {
|
||||
}
|
||||
};
|
||||
|
||||
template <class F, class S>
|
||||
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
|
||||
return (pair.first == other.first) && (pair.second == other.second);
|
||||
}
|
||||
|
||||
template <class F, class S>
|
||||
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
|
||||
return (pair.first != other.first) || (pair.second != other.second);
|
||||
}
|
||||
|
||||
template <class F, class S>
|
||||
struct PairSort {
|
||||
bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
|
||||
if (A.first != B.first) {
|
||||
return A.first < B.first;
|
||||
}
|
||||
return A.second < B.second;
|
||||
}
|
||||
};
|
||||
|
||||
template <class K, class V>
|
||||
struct KeyValue {
|
||||
const K key;
|
||||
V value;
|
||||
|
||||
void operator=(const KeyValue &p_kv) = delete;
|
||||
_FORCE_INLINE_ KeyValue(const KeyValue &p_kv) :
|
||||
key(p_kv.key),
|
||||
value(p_kv.value) {
|
||||
}
|
||||
_FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) :
|
||||
key(p_key),
|
||||
value(p_value) {
|
||||
}
|
||||
};
|
||||
|
||||
template <class K, class V>
|
||||
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
|
||||
return (pair.key == other.key) && (pair.value == other.value);
|
||||
}
|
||||
|
||||
template <class K, class V>
|
||||
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
|
||||
return (pair.key != other.key) || (pair.value != other.value);
|
||||
}
|
||||
|
||||
template <class K, class V>
|
||||
struct KeyValueSort {
|
||||
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
|
||||
return A.key < B.key;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_PAIR_HPP
|
||||
@@ -1,765 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* rb_map.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_RB_MAP_HPP
|
||||
#define GODOT_RB_MAP_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/pair.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
// based on the very nice implementation of rb-trees by:
|
||||
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
|
||||
|
||||
template <class K, class V, class C = Comparator<K>, class A = DefaultAllocator>
|
||||
class RBMap {
|
||||
enum Color {
|
||||
RED,
|
||||
BLACK
|
||||
};
|
||||
struct _Data;
|
||||
|
||||
public:
|
||||
class Element {
|
||||
private:
|
||||
friend class RBMap<K, V, C, A>;
|
||||
int color = RED;
|
||||
Element *right = nullptr;
|
||||
Element *left = nullptr;
|
||||
Element *parent = nullptr;
|
||||
Element *_next = nullptr;
|
||||
Element *_prev = nullptr;
|
||||
KeyValue<K, V> _data;
|
||||
|
||||
public:
|
||||
KeyValue<K, V> &key_value() { return _data; }
|
||||
const KeyValue<K, V> &key_value() const { return _data; }
|
||||
|
||||
const Element *next() const {
|
||||
return _next;
|
||||
}
|
||||
Element *next() {
|
||||
return _next;
|
||||
}
|
||||
const Element *prev() const {
|
||||
return _prev;
|
||||
}
|
||||
Element *prev() {
|
||||
return _prev;
|
||||
}
|
||||
const K &key() const {
|
||||
return _data.key;
|
||||
}
|
||||
V &value() {
|
||||
return _data.value;
|
||||
}
|
||||
const V &value() const {
|
||||
return _data.value;
|
||||
}
|
||||
V &get() {
|
||||
return _data.value;
|
||||
}
|
||||
const V &get() const {
|
||||
return _data.value;
|
||||
}
|
||||
Element(const KeyValue<K, V> &p_data) :
|
||||
_data(p_data) {}
|
||||
};
|
||||
|
||||
typedef KeyValue<K, V> ValueType;
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ KeyValue<K, V> &operator*() const {
|
||||
return E->key_value();
|
||||
}
|
||||
_FORCE_INLINE_ KeyValue<K, V> *operator->() const { return &E->key_value(); }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||
explicit operator bool() const {
|
||||
return E != nullptr;
|
||||
}
|
||||
Iterator(Element *p_E) { E = p_E; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
Element *E = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const KeyValue<K, V> &operator*() const {
|
||||
return E->key_value();
|
||||
}
|
||||
_FORCE_INLINE_ const KeyValue<K, V> *operator->() const { return &E->key_value(); }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||
explicit operator bool() const {
|
||||
return E != nullptr;
|
||||
}
|
||||
ConstIterator(const Element *p_E) { E = p_E; }
|
||||
ConstIterator() {}
|
||||
ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
const Element *E = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ Iterator find(const K &p_key) {
|
||||
return Iterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
|
||||
return erase(p_iter.E);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
|
||||
return ConstIterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
struct _Data {
|
||||
Element *_root = nullptr;
|
||||
Element *_nil = nullptr;
|
||||
int size_cache = 0;
|
||||
|
||||
_FORCE_INLINE_ _Data() {
|
||||
#ifdef GLOBALNIL_DISABLED
|
||||
_nil = memnew_allocator(Element, A);
|
||||
_nil->parent = _nil->left = _nil->right = _nil;
|
||||
_nil->color = BLACK;
|
||||
#else
|
||||
_nil = (Element *)&_GlobalNilClass::_nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
void _create_root() {
|
||||
_root = memnew_allocator(Element(KeyValue<K, V>(K(), V())), A);
|
||||
_root->parent = _root->left = _root->right = _nil;
|
||||
_root->color = BLACK;
|
||||
}
|
||||
|
||||
void _free_root() {
|
||||
if (_root) {
|
||||
memdelete_allocator<Element, A>(_root);
|
||||
_root = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
~_Data() {
|
||||
_free_root();
|
||||
|
||||
#ifdef GLOBALNIL_DISABLED
|
||||
memdelete_allocator<Element, A>(_nil);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
_Data _data;
|
||||
|
||||
inline void _set_color(Element *p_node, int p_color) {
|
||||
ERR_FAIL_COND(p_node == _data._nil && p_color == RED);
|
||||
p_node->color = p_color;
|
||||
}
|
||||
|
||||
inline void _rotate_left(Element *p_node) {
|
||||
Element *r = p_node->right;
|
||||
p_node->right = r->left;
|
||||
if (r->left != _data._nil) {
|
||||
r->left->parent = p_node;
|
||||
}
|
||||
r->parent = p_node->parent;
|
||||
if (p_node == p_node->parent->left) {
|
||||
p_node->parent->left = r;
|
||||
} else {
|
||||
p_node->parent->right = r;
|
||||
}
|
||||
|
||||
r->left = p_node;
|
||||
p_node->parent = r;
|
||||
}
|
||||
|
||||
inline void _rotate_right(Element *p_node) {
|
||||
Element *l = p_node->left;
|
||||
p_node->left = l->right;
|
||||
if (l->right != _data._nil) {
|
||||
l->right->parent = p_node;
|
||||
}
|
||||
l->parent = p_node->parent;
|
||||
if (p_node == p_node->parent->right) {
|
||||
p_node->parent->right = l;
|
||||
} else {
|
||||
p_node->parent->left = l;
|
||||
}
|
||||
|
||||
l->right = p_node;
|
||||
p_node->parent = l;
|
||||
}
|
||||
|
||||
inline Element *_successor(Element *p_node) const {
|
||||
Element *node = p_node;
|
||||
|
||||
if (node->right != _data._nil) {
|
||||
node = node->right;
|
||||
while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */
|
||||
node = node->left;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while (node == node->parent->right) {
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (node->parent == _data._root) {
|
||||
return nullptr; // No successor, as p_node = last node
|
||||
}
|
||||
return node->parent;
|
||||
}
|
||||
}
|
||||
|
||||
inline Element *_predecessor(Element *p_node) const {
|
||||
Element *node = p_node;
|
||||
|
||||
if (node->left != _data._nil) {
|
||||
node = node->left;
|
||||
while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */
|
||||
node = node->right;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while (node == node->parent->left) {
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (node == _data._root) {
|
||||
return nullptr; // No predecessor, as p_node = first node
|
||||
}
|
||||
return node->parent;
|
||||
}
|
||||
}
|
||||
|
||||
Element *_find(const K &p_key) const {
|
||||
Element *node = _data._root->left;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
if (less(p_key, node->_data.key)) {
|
||||
node = node->left;
|
||||
} else if (less(node->_data.key, p_key)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // found
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *_find_closest(const K &p_key) const {
|
||||
Element *node = _data._root->left;
|
||||
Element *prev = nullptr;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
prev = node;
|
||||
|
||||
if (less(p_key, node->_data.key)) {
|
||||
node = node->left;
|
||||
} else if (less(node->_data.key, p_key)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // found
|
||||
}
|
||||
}
|
||||
|
||||
if (prev == nullptr) {
|
||||
return nullptr; // tree empty
|
||||
}
|
||||
|
||||
if (less(p_key, prev->_data.key)) {
|
||||
prev = prev->_prev;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
void _insert_rb_fix(Element *p_new_node) {
|
||||
Element *node = p_new_node;
|
||||
Element *nparent = node->parent;
|
||||
Element *ngrand_parent = nullptr;
|
||||
|
||||
while (nparent->color == RED) {
|
||||
ngrand_parent = nparent->parent;
|
||||
|
||||
if (nparent == ngrand_parent->left) {
|
||||
if (ngrand_parent->right->color == RED) {
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent->right, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
node = ngrand_parent;
|
||||
nparent = node->parent;
|
||||
} else {
|
||||
if (node == nparent->right) {
|
||||
_rotate_left(nparent);
|
||||
node = nparent;
|
||||
nparent = node->parent;
|
||||
}
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
_rotate_right(ngrand_parent);
|
||||
}
|
||||
} else {
|
||||
if (ngrand_parent->left->color == RED) {
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent->left, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
node = ngrand_parent;
|
||||
nparent = node->parent;
|
||||
} else {
|
||||
if (node == nparent->left) {
|
||||
_rotate_right(nparent);
|
||||
node = nparent;
|
||||
nparent = node->parent;
|
||||
}
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
_rotate_left(ngrand_parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_set_color(_data._root->left, BLACK);
|
||||
}
|
||||
|
||||
Element *_insert(const K &p_key, const V &p_value) {
|
||||
Element *new_parent = _data._root;
|
||||
Element *node = _data._root->left;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
new_parent = node;
|
||||
|
||||
if (less(p_key, node->_data.key)) {
|
||||
node = node->left;
|
||||
} else if (less(node->_data.key, p_key)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
node->_data.value = p_value;
|
||||
return node; // Return existing node with new value
|
||||
}
|
||||
}
|
||||
|
||||
typedef KeyValue<K, V> KV;
|
||||
Element *new_node = memnew_allocator(Element(KV(p_key, p_value)), A);
|
||||
new_node->parent = new_parent;
|
||||
new_node->right = _data._nil;
|
||||
new_node->left = _data._nil;
|
||||
|
||||
// new_node->data=_data;
|
||||
|
||||
if (new_parent == _data._root || less(p_key, new_parent->_data.key)) {
|
||||
new_parent->left = new_node;
|
||||
} else {
|
||||
new_parent->right = new_node;
|
||||
}
|
||||
|
||||
new_node->_next = _successor(new_node);
|
||||
new_node->_prev = _predecessor(new_node);
|
||||
if (new_node->_next) {
|
||||
new_node->_next->_prev = new_node;
|
||||
}
|
||||
if (new_node->_prev) {
|
||||
new_node->_prev->_next = new_node;
|
||||
}
|
||||
|
||||
_data.size_cache++;
|
||||
_insert_rb_fix(new_node);
|
||||
return new_node;
|
||||
}
|
||||
|
||||
void _erase_fix_rb(Element *p_node) {
|
||||
Element *root = _data._root->left;
|
||||
Element *node = _data._nil;
|
||||
Element *sibling = p_node;
|
||||
Element *parent = sibling->parent;
|
||||
|
||||
while (node != root) { // If red node found, will exit at a break
|
||||
if (sibling->color == RED) {
|
||||
_set_color(sibling, BLACK);
|
||||
_set_color(parent, RED);
|
||||
if (sibling == parent->right) {
|
||||
sibling = sibling->left;
|
||||
_rotate_left(parent);
|
||||
} else {
|
||||
sibling = sibling->right;
|
||||
_rotate_right(parent);
|
||||
}
|
||||
}
|
||||
if ((sibling->left->color == BLACK) && (sibling->right->color == BLACK)) {
|
||||
_set_color(sibling, RED);
|
||||
if (parent->color == RED) {
|
||||
_set_color(parent, BLACK);
|
||||
break;
|
||||
} else { // loop: haven't found any red nodes yet
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
sibling = (node == parent->left) ? parent->right : parent->left;
|
||||
}
|
||||
} else {
|
||||
if (sibling == parent->right) {
|
||||
if (sibling->right->color == BLACK) {
|
||||
_set_color(sibling->left, BLACK);
|
||||
_set_color(sibling, RED);
|
||||
_rotate_right(sibling);
|
||||
sibling = sibling->parent;
|
||||
}
|
||||
_set_color(sibling, parent->color);
|
||||
_set_color(parent, BLACK);
|
||||
_set_color(sibling->right, BLACK);
|
||||
_rotate_left(parent);
|
||||
break;
|
||||
} else {
|
||||
if (sibling->left->color == BLACK) {
|
||||
_set_color(sibling->right, BLACK);
|
||||
_set_color(sibling, RED);
|
||||
_rotate_left(sibling);
|
||||
sibling = sibling->parent;
|
||||
}
|
||||
|
||||
_set_color(sibling, parent->color);
|
||||
_set_color(parent, BLACK);
|
||||
_set_color(sibling->left, BLACK);
|
||||
_rotate_right(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(_data._nil->color != BLACK);
|
||||
}
|
||||
|
||||
void _erase(Element *p_node) {
|
||||
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
|
||||
Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
|
||||
|
||||
Element *sibling = nullptr;
|
||||
if (rp == rp->parent->left) {
|
||||
rp->parent->left = node;
|
||||
sibling = rp->parent->right;
|
||||
} else {
|
||||
rp->parent->right = node;
|
||||
sibling = rp->parent->left;
|
||||
}
|
||||
|
||||
if (node->color == RED) {
|
||||
node->parent = rp->parent;
|
||||
_set_color(node, BLACK);
|
||||
} else if (rp->color == BLACK && rp->parent != _data._root) {
|
||||
_erase_fix_rb(sibling);
|
||||
}
|
||||
|
||||
if (rp != p_node) {
|
||||
ERR_FAIL_COND(rp == _data._nil);
|
||||
|
||||
rp->left = p_node->left;
|
||||
rp->right = p_node->right;
|
||||
rp->parent = p_node->parent;
|
||||
rp->color = p_node->color;
|
||||
if (p_node->left != _data._nil) {
|
||||
p_node->left->parent = rp;
|
||||
}
|
||||
if (p_node->right != _data._nil) {
|
||||
p_node->right->parent = rp;
|
||||
}
|
||||
|
||||
if (p_node == p_node->parent->left) {
|
||||
p_node->parent->left = rp;
|
||||
} else {
|
||||
p_node->parent->right = rp;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_node->_next) {
|
||||
p_node->_next->_prev = p_node->_prev;
|
||||
}
|
||||
if (p_node->_prev) {
|
||||
p_node->_prev->_next = p_node->_next;
|
||||
}
|
||||
|
||||
memdelete_allocator<Element, A>(p_node);
|
||||
_data.size_cache--;
|
||||
ERR_FAIL_COND(_data._nil->color == RED);
|
||||
}
|
||||
|
||||
void _calculate_depth(Element *p_element, int &max_d, int d) const {
|
||||
if (p_element == _data._nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
_calculate_depth(p_element->left, max_d, d + 1);
|
||||
_calculate_depth(p_element->right, max_d, d + 1);
|
||||
|
||||
if (d > max_d) {
|
||||
max_d = d;
|
||||
}
|
||||
}
|
||||
|
||||
void _cleanup_tree(Element *p_element) {
|
||||
if (p_element == _data._nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_tree(p_element->left);
|
||||
_cleanup_tree(p_element->right);
|
||||
memdelete_allocator<Element, A>(p_element);
|
||||
}
|
||||
|
||||
void _copy_from(const RBMap &p_map) {
|
||||
clear();
|
||||
// not the fastest way, but safeset to write.
|
||||
for (Element *I = p_map.front(); I; I = I->next()) {
|
||||
insert(I->key(), I->value());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
const Element *find(const K &p_key) const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Element *res = _find(p_key);
|
||||
return res;
|
||||
}
|
||||
|
||||
Element *find(const K &p_key) {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *res = _find(p_key);
|
||||
return res;
|
||||
}
|
||||
|
||||
const Element *find_closest(const K &p_key) const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Element *res = _find_closest(p_key);
|
||||
return res;
|
||||
}
|
||||
|
||||
Element *find_closest(const K &p_key) {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *res = _find_closest(p_key);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool has(const K &p_key) const {
|
||||
return find(p_key) != nullptr;
|
||||
}
|
||||
|
||||
Element *insert(const K &p_key, const V &p_value) {
|
||||
if (!_data._root) {
|
||||
_data._create_root();
|
||||
}
|
||||
return _insert(p_key, p_value);
|
||||
}
|
||||
|
||||
void erase(Element *p_element) {
|
||||
if (!_data._root || !p_element) {
|
||||
return;
|
||||
}
|
||||
|
||||
_erase(p_element);
|
||||
if (_data.size_cache == 0 && _data._root) {
|
||||
_data._free_root();
|
||||
}
|
||||
}
|
||||
|
||||
bool erase(const K &p_key) {
|
||||
if (!_data._root) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Element *e = find(p_key);
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_erase(e);
|
||||
if (_data.size_cache == 0 && _data._root) {
|
||||
_data._free_root();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const V &operator[](const K &p_key) const {
|
||||
CRASH_COND(!_data._root);
|
||||
const Element *e = find(p_key);
|
||||
CRASH_COND(!e);
|
||||
return e->_data.value;
|
||||
}
|
||||
|
||||
V &operator[](const K &p_key) {
|
||||
if (!_data._root) {
|
||||
_data._create_root();
|
||||
}
|
||||
|
||||
Element *e = find(p_key);
|
||||
if (!e) {
|
||||
e = insert(p_key, V());
|
||||
}
|
||||
|
||||
return e->_data.value;
|
||||
}
|
||||
|
||||
Element *front() const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *e = _data._root->left;
|
||||
if (e == _data._nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (e->left != _data._nil) {
|
||||
e = e->left;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
Element *back() const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *e = _data._root->left;
|
||||
if (e == _data._nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (e->right != _data._nil) {
|
||||
e = e->right;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
inline bool is_empty() const {
|
||||
return _data.size_cache == 0;
|
||||
}
|
||||
inline int size() const {
|
||||
return _data.size_cache;
|
||||
}
|
||||
|
||||
int calculate_depth() const {
|
||||
// used for debug mostly
|
||||
if (!_data._root) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max_d = 0;
|
||||
_calculate_depth(_data._root->left, max_d, 0);
|
||||
return max_d;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (!_data._root) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_tree(_data._root->left);
|
||||
_data._root->left = _data._nil;
|
||||
_data.size_cache = 0;
|
||||
_data._free_root();
|
||||
}
|
||||
|
||||
void operator=(const RBMap &p_map) {
|
||||
_copy_from(p_map);
|
||||
}
|
||||
|
||||
RBMap(const RBMap &p_map) {
|
||||
_copy_from(p_map);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RBMap() {}
|
||||
|
||||
~RBMap() {
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_RB_MAP_HPP
|
||||
@@ -1,714 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* rb_set.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_RB_SET_HPP
|
||||
#define GODOT_RB_SET_HPP
|
||||
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
|
||||
// based on the very nice implementation of rb-trees by:
|
||||
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, class C = Comparator<T>, class A = DefaultAllocator>
|
||||
class RBSet {
|
||||
enum Color {
|
||||
RED,
|
||||
BLACK
|
||||
};
|
||||
struct _Data;
|
||||
|
||||
public:
|
||||
class Element {
|
||||
private:
|
||||
friend class RBSet<T, C, A>;
|
||||
int color = RED;
|
||||
Element *right = nullptr;
|
||||
Element *left = nullptr;
|
||||
Element *parent = nullptr;
|
||||
Element *_next = nullptr;
|
||||
Element *_prev = nullptr;
|
||||
T value;
|
||||
//_Data *data;
|
||||
|
||||
public:
|
||||
const Element *next() const {
|
||||
return _next;
|
||||
}
|
||||
Element *next() {
|
||||
return _next;
|
||||
}
|
||||
const Element *prev() const {
|
||||
return _prev;
|
||||
}
|
||||
Element *prev() {
|
||||
return _prev;
|
||||
}
|
||||
T &get() {
|
||||
return value;
|
||||
}
|
||||
const T &get() const {
|
||||
return value;
|
||||
}
|
||||
Element() {}
|
||||
};
|
||||
|
||||
typedef T ValueType;
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
return E->get();
|
||||
}
|
||||
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||
|
||||
explicit operator bool() const { return E != nullptr; }
|
||||
Iterator(Element *p_E) { E = p_E; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||
|
||||
private:
|
||||
Element *E = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return E->get();
|
||||
}
|
||||
_FORCE_INLINE_ const T *operator->() const { return &E->get(); }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
E = E->next();
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
E = E->prev();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||
|
||||
_FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
|
||||
_FORCE_INLINE_ ConstIterator() {}
|
||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||
|
||||
explicit operator bool() const { return E != nullptr; }
|
||||
|
||||
private:
|
||||
const Element *E = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ Iterator find(const K &p_key) {
|
||||
return Iterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(front());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(nullptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//to use when replacing find()
|
||||
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
|
||||
return ConstIterator(find(p_key));
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
struct _Data {
|
||||
Element *_root = nullptr;
|
||||
Element *_nil = nullptr;
|
||||
int size_cache = 0;
|
||||
|
||||
_FORCE_INLINE_ _Data() {
|
||||
#ifdef GLOBALNIL_DISABLED
|
||||
_nil = memnew_allocator(Element, A);
|
||||
_nil->parent = _nil->left = _nil->right = _nil;
|
||||
_nil->color = BLACK;
|
||||
#else
|
||||
_nil = (Element *)&_GlobalNilClass::_nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
void _create_root() {
|
||||
_root = memnew_allocator(Element, A);
|
||||
_root->parent = _root->left = _root->right = _nil;
|
||||
_root->color = BLACK;
|
||||
}
|
||||
|
||||
void _free_root() {
|
||||
if (_root) {
|
||||
memdelete_allocator<Element, A>(_root);
|
||||
_root = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
~_Data() {
|
||||
_free_root();
|
||||
|
||||
#ifdef GLOBALNIL_DISABLED
|
||||
memdelete_allocator<Element, A>(_nil);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
_Data _data;
|
||||
|
||||
inline void _set_color(Element *p_node, int p_color) {
|
||||
ERR_FAIL_COND(p_node == _data._nil && p_color == RED);
|
||||
p_node->color = p_color;
|
||||
}
|
||||
|
||||
inline void _rotate_left(Element *p_node) {
|
||||
Element *r = p_node->right;
|
||||
p_node->right = r->left;
|
||||
if (r->left != _data._nil) {
|
||||
r->left->parent = p_node;
|
||||
}
|
||||
r->parent = p_node->parent;
|
||||
if (p_node == p_node->parent->left) {
|
||||
p_node->parent->left = r;
|
||||
} else {
|
||||
p_node->parent->right = r;
|
||||
}
|
||||
|
||||
r->left = p_node;
|
||||
p_node->parent = r;
|
||||
}
|
||||
|
||||
inline void _rotate_right(Element *p_node) {
|
||||
Element *l = p_node->left;
|
||||
p_node->left = l->right;
|
||||
if (l->right != _data._nil) {
|
||||
l->right->parent = p_node;
|
||||
}
|
||||
l->parent = p_node->parent;
|
||||
if (p_node == p_node->parent->right) {
|
||||
p_node->parent->right = l;
|
||||
} else {
|
||||
p_node->parent->left = l;
|
||||
}
|
||||
|
||||
l->right = p_node;
|
||||
p_node->parent = l;
|
||||
}
|
||||
|
||||
inline Element *_successor(Element *p_node) const {
|
||||
Element *node = p_node;
|
||||
|
||||
if (node->right != _data._nil) {
|
||||
node = node->right;
|
||||
while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */
|
||||
node = node->left;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while (node == node->parent->right) {
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (node->parent == _data._root) {
|
||||
return nullptr; // No successor, as p_node = last node
|
||||
}
|
||||
return node->parent;
|
||||
}
|
||||
}
|
||||
|
||||
inline Element *_predecessor(Element *p_node) const {
|
||||
Element *node = p_node;
|
||||
|
||||
if (node->left != _data._nil) {
|
||||
node = node->left;
|
||||
while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */
|
||||
node = node->right;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while (node == node->parent->left) {
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (node == _data._root) {
|
||||
return nullptr; // No predecessor, as p_node = first node.
|
||||
}
|
||||
return node->parent;
|
||||
}
|
||||
}
|
||||
|
||||
Element *_find(const T &p_value) const {
|
||||
Element *node = _data._root->left;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
if (less(p_value, node->value)) {
|
||||
node = node->left;
|
||||
} else if (less(node->value, p_value)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // found
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *_lower_bound(const T &p_value) const {
|
||||
Element *node = _data._root->left;
|
||||
Element *prev = nullptr;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
prev = node;
|
||||
|
||||
if (less(p_value, node->value)) {
|
||||
node = node->left;
|
||||
} else if (less(node->value, p_value)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // found
|
||||
}
|
||||
}
|
||||
|
||||
if (prev == nullptr) {
|
||||
return nullptr; // tree empty
|
||||
}
|
||||
|
||||
if (less(prev->value, p_value)) {
|
||||
prev = prev->_next;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
void _insert_rb_fix(Element *p_new_node) {
|
||||
Element *node = p_new_node;
|
||||
Element *nparent = node->parent;
|
||||
Element *ngrand_parent = nullptr;
|
||||
|
||||
while (nparent->color == RED) {
|
||||
ngrand_parent = nparent->parent;
|
||||
|
||||
if (nparent == ngrand_parent->left) {
|
||||
if (ngrand_parent->right->color == RED) {
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent->right, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
node = ngrand_parent;
|
||||
nparent = node->parent;
|
||||
} else {
|
||||
if (node == nparent->right) {
|
||||
_rotate_left(nparent);
|
||||
node = nparent;
|
||||
nparent = node->parent;
|
||||
}
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
_rotate_right(ngrand_parent);
|
||||
}
|
||||
} else {
|
||||
if (ngrand_parent->left->color == RED) {
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent->left, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
node = ngrand_parent;
|
||||
nparent = node->parent;
|
||||
} else {
|
||||
if (node == nparent->left) {
|
||||
_rotate_right(nparent);
|
||||
node = nparent;
|
||||
nparent = node->parent;
|
||||
}
|
||||
_set_color(nparent, BLACK);
|
||||
_set_color(ngrand_parent, RED);
|
||||
_rotate_left(ngrand_parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_set_color(_data._root->left, BLACK);
|
||||
}
|
||||
|
||||
Element *_insert(const T &p_value) {
|
||||
Element *new_parent = _data._root;
|
||||
Element *node = _data._root->left;
|
||||
C less;
|
||||
|
||||
while (node != _data._nil) {
|
||||
new_parent = node;
|
||||
|
||||
if (less(p_value, node->value)) {
|
||||
node = node->left;
|
||||
} else if (less(node->value, p_value)) {
|
||||
node = node->right;
|
||||
} else {
|
||||
return node; // Return existing node
|
||||
}
|
||||
}
|
||||
|
||||
Element *new_node = memnew_allocator(Element, A);
|
||||
new_node->parent = new_parent;
|
||||
new_node->right = _data._nil;
|
||||
new_node->left = _data._nil;
|
||||
new_node->value = p_value;
|
||||
// new_node->data=_data;
|
||||
|
||||
if (new_parent == _data._root || less(p_value, new_parent->value)) {
|
||||
new_parent->left = new_node;
|
||||
} else {
|
||||
new_parent->right = new_node;
|
||||
}
|
||||
|
||||
new_node->_next = _successor(new_node);
|
||||
new_node->_prev = _predecessor(new_node);
|
||||
if (new_node->_next) {
|
||||
new_node->_next->_prev = new_node;
|
||||
}
|
||||
if (new_node->_prev) {
|
||||
new_node->_prev->_next = new_node;
|
||||
}
|
||||
|
||||
_data.size_cache++;
|
||||
_insert_rb_fix(new_node);
|
||||
return new_node;
|
||||
}
|
||||
|
||||
void _erase_fix_rb(Element *p_node) {
|
||||
Element *root = _data._root->left;
|
||||
Element *node = _data._nil;
|
||||
Element *sibling = p_node;
|
||||
Element *parent = sibling->parent;
|
||||
|
||||
while (node != root) { // If red node found, will exit at a break
|
||||
if (sibling->color == RED) {
|
||||
_set_color(sibling, BLACK);
|
||||
_set_color(parent, RED);
|
||||
if (sibling == parent->right) {
|
||||
sibling = sibling->left;
|
||||
_rotate_left(parent);
|
||||
} else {
|
||||
sibling = sibling->right;
|
||||
_rotate_right(parent);
|
||||
}
|
||||
}
|
||||
if ((sibling->left->color == BLACK) && (sibling->right->color == BLACK)) {
|
||||
_set_color(sibling, RED);
|
||||
if (parent->color == RED) {
|
||||
_set_color(parent, BLACK);
|
||||
break;
|
||||
} else { // loop: haven't found any red nodes yet
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
sibling = (node == parent->left) ? parent->right : parent->left;
|
||||
}
|
||||
} else {
|
||||
if (sibling == parent->right) {
|
||||
if (sibling->right->color == BLACK) {
|
||||
_set_color(sibling->left, BLACK);
|
||||
_set_color(sibling, RED);
|
||||
_rotate_right(sibling);
|
||||
sibling = sibling->parent;
|
||||
}
|
||||
_set_color(sibling, parent->color);
|
||||
_set_color(parent, BLACK);
|
||||
_set_color(sibling->right, BLACK);
|
||||
_rotate_left(parent);
|
||||
break;
|
||||
} else {
|
||||
if (sibling->left->color == BLACK) {
|
||||
_set_color(sibling->right, BLACK);
|
||||
_set_color(sibling, RED);
|
||||
_rotate_left(sibling);
|
||||
sibling = sibling->parent;
|
||||
}
|
||||
|
||||
_set_color(sibling, parent->color);
|
||||
_set_color(parent, BLACK);
|
||||
_set_color(sibling->left, BLACK);
|
||||
_rotate_right(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(_data._nil->color != BLACK);
|
||||
}
|
||||
|
||||
void _erase(Element *p_node) {
|
||||
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
|
||||
Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
|
||||
|
||||
Element *sibling = nullptr;
|
||||
if (rp == rp->parent->left) {
|
||||
rp->parent->left = node;
|
||||
sibling = rp->parent->right;
|
||||
} else {
|
||||
rp->parent->right = node;
|
||||
sibling = rp->parent->left;
|
||||
}
|
||||
|
||||
if (node->color == RED) {
|
||||
node->parent = rp->parent;
|
||||
_set_color(node, BLACK);
|
||||
} else if (rp->color == BLACK && rp->parent != _data._root) {
|
||||
_erase_fix_rb(sibling);
|
||||
}
|
||||
|
||||
if (rp != p_node) {
|
||||
ERR_FAIL_COND(rp == _data._nil);
|
||||
|
||||
rp->left = p_node->left;
|
||||
rp->right = p_node->right;
|
||||
rp->parent = p_node->parent;
|
||||
rp->color = p_node->color;
|
||||
if (p_node->left != _data._nil) {
|
||||
p_node->left->parent = rp;
|
||||
}
|
||||
if (p_node->right != _data._nil) {
|
||||
p_node->right->parent = rp;
|
||||
}
|
||||
|
||||
if (p_node == p_node->parent->left) {
|
||||
p_node->parent->left = rp;
|
||||
} else {
|
||||
p_node->parent->right = rp;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_node->_next) {
|
||||
p_node->_next->_prev = p_node->_prev;
|
||||
}
|
||||
if (p_node->_prev) {
|
||||
p_node->_prev->_next = p_node->_next;
|
||||
}
|
||||
|
||||
memdelete_allocator<Element, A>(p_node);
|
||||
_data.size_cache--;
|
||||
ERR_FAIL_COND(_data._nil->color == RED);
|
||||
}
|
||||
|
||||
void _calculate_depth(Element *p_element, int &max_d, int d) const {
|
||||
if (p_element == _data._nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
_calculate_depth(p_element->left, max_d, d + 1);
|
||||
_calculate_depth(p_element->right, max_d, d + 1);
|
||||
|
||||
if (d > max_d) {
|
||||
max_d = d;
|
||||
}
|
||||
}
|
||||
|
||||
void _cleanup_tree(Element *p_element) {
|
||||
if (p_element == _data._nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_tree(p_element->left);
|
||||
_cleanup_tree(p_element->right);
|
||||
memdelete_allocator<Element, A>(p_element);
|
||||
}
|
||||
|
||||
void _copy_from(const RBSet &p_set) {
|
||||
clear();
|
||||
// not the fastest way, but safeset to write.
|
||||
for (Element *I = p_set.front(); I; I = I->next()) {
|
||||
insert(I->get());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
const Element *find(const T &p_value) const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Element *res = _find(p_value);
|
||||
return res;
|
||||
}
|
||||
|
||||
Element *find(const T &p_value) {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *res = _find(p_value);
|
||||
return res;
|
||||
}
|
||||
|
||||
Element *lower_bound(const T &p_value) const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
return _lower_bound(p_value);
|
||||
}
|
||||
|
||||
bool has(const T &p_value) const {
|
||||
return find(p_value) != nullptr;
|
||||
}
|
||||
|
||||
Element *insert(const T &p_value) {
|
||||
if (!_data._root) {
|
||||
_data._create_root();
|
||||
}
|
||||
return _insert(p_value);
|
||||
}
|
||||
|
||||
void erase(Element *p_element) {
|
||||
if (!_data._root || !p_element) {
|
||||
return;
|
||||
}
|
||||
|
||||
_erase(p_element);
|
||||
if (_data.size_cache == 0 && _data._root) {
|
||||
_data._free_root();
|
||||
}
|
||||
}
|
||||
|
||||
bool erase(const T &p_value) {
|
||||
if (!_data._root) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Element *e = find(p_value);
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_erase(e);
|
||||
if (_data.size_cache == 0 && _data._root) {
|
||||
_data._free_root();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Element *front() const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *e = _data._root->left;
|
||||
if (e == _data._nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (e->left != _data._nil) {
|
||||
e = e->left;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
Element *back() const {
|
||||
if (!_data._root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *e = _data._root->left;
|
||||
if (e == _data._nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (e->right != _data._nil) {
|
||||
e = e->right;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
inline bool is_empty() const {
|
||||
return _data.size_cache == 0;
|
||||
}
|
||||
inline int size() const {
|
||||
return _data.size_cache;
|
||||
}
|
||||
|
||||
int calculate_depth() const {
|
||||
// used for debug mostly
|
||||
if (!_data._root) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max_d = 0;
|
||||
_calculate_depth(_data._root->left, max_d, 0);
|
||||
return max_d;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (!_data._root) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_tree(_data._root->left);
|
||||
_data._root->left = _data._nil;
|
||||
_data.size_cache = 0;
|
||||
_data._free_root();
|
||||
}
|
||||
|
||||
void operator=(const RBSet &p_set) {
|
||||
_copy_from(p_set);
|
||||
}
|
||||
|
||||
RBSet(const RBSet &p_set) {
|
||||
_copy_from(p_set);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RBSet() {}
|
||||
|
||||
~RBSet() {
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_RB_SET_HPP
|
||||
@@ -1,465 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* rid_owner.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_RID_OWNER_HPP
|
||||
#define GODOT_RID_OWNER_HPP
|
||||
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
#include <godot_cpp/templates/list.hpp>
|
||||
#include <godot_cpp/templates/spin_lock.hpp>
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, bool THREAD_SAFE = false>
|
||||
class RID_Alloc {
|
||||
T **chunks = nullptr;
|
||||
uint32_t **free_list_chunks = nullptr;
|
||||
uint32_t **validator_chunks = nullptr;
|
||||
|
||||
uint32_t elements_in_chunk;
|
||||
uint32_t max_alloc = 0;
|
||||
uint32_t alloc_count = 0;
|
||||
|
||||
const char *description = nullptr;
|
||||
|
||||
SpinLock spin_lock;
|
||||
|
||||
_FORCE_INLINE_ RID _allocate_rid() {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
|
||||
if (alloc_count == max_alloc) {
|
||||
// allocate a new chunk
|
||||
uint32_t chunk_count = alloc_count == 0 ? 0 : (max_alloc / elements_in_chunk);
|
||||
|
||||
// grow chunks
|
||||
chunks = (T **)memrealloc(chunks, sizeof(T *) * (chunk_count + 1));
|
||||
chunks[chunk_count] = (T *)memalloc(sizeof(T) * elements_in_chunk); // but don't initialize
|
||||
|
||||
// grow validators
|
||||
validator_chunks = (uint32_t **)memrealloc(validator_chunks, sizeof(uint32_t *) * (chunk_count + 1));
|
||||
validator_chunks[chunk_count] = (uint32_t *)memalloc(sizeof(uint32_t) * elements_in_chunk);
|
||||
// grow free lists
|
||||
free_list_chunks = (uint32_t **)memrealloc(free_list_chunks, sizeof(uint32_t *) * (chunk_count + 1));
|
||||
free_list_chunks[chunk_count] = (uint32_t *)memalloc(sizeof(uint32_t) * elements_in_chunk);
|
||||
|
||||
// initialize
|
||||
for (uint32_t i = 0; i < elements_in_chunk; i++) {
|
||||
// Don't initialize chunk.
|
||||
validator_chunks[chunk_count][i] = 0xFFFFFFFF;
|
||||
free_list_chunks[chunk_count][i] = alloc_count + i;
|
||||
}
|
||||
|
||||
max_alloc += elements_in_chunk;
|
||||
}
|
||||
|
||||
uint32_t free_index = free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk];
|
||||
|
||||
uint32_t free_chunk = free_index / elements_in_chunk;
|
||||
uint32_t free_element = free_index % elements_in_chunk;
|
||||
|
||||
uint32_t validator = (uint32_t)(UtilityFunctions::rid_allocate_id() & 0x7FFFFFFF);
|
||||
uint64_t id = validator;
|
||||
id <<= 32;
|
||||
id |= free_index;
|
||||
|
||||
validator_chunks[free_chunk][free_element] = validator;
|
||||
|
||||
validator_chunks[free_chunk][free_element] |= 0x80000000; // mark uninitialized bit
|
||||
|
||||
alloc_count++;
|
||||
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
|
||||
return UtilityFunctions::rid_from_int64(id);
|
||||
}
|
||||
|
||||
public:
|
||||
RID make_rid() {
|
||||
RID rid = _allocate_rid();
|
||||
initialize_rid(rid);
|
||||
return rid;
|
||||
}
|
||||
RID make_rid(const T &p_value) {
|
||||
RID rid = _allocate_rid();
|
||||
initialize_rid(rid, p_value);
|
||||
return rid;
|
||||
}
|
||||
|
||||
// allocate but don't initialize, use initialize_rid afterwards
|
||||
RID allocate_rid() {
|
||||
return _allocate_rid();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *get_or_null(const RID &p_rid, bool p_initialize = false) {
|
||||
if (p_rid == RID()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
|
||||
uint64_t id = p_rid.get_id();
|
||||
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
|
||||
if (unlikely(idx >= max_alloc)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t idx_chunk = idx / elements_in_chunk;
|
||||
uint32_t idx_element = idx % elements_in_chunk;
|
||||
|
||||
uint32_t validator = uint32_t(id >> 32);
|
||||
|
||||
if (unlikely(p_initialize)) {
|
||||
if (unlikely(!(validator_chunks[idx_chunk][idx_element] & 0x80000000))) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL_V_MSG(nullptr, "Initializing already initialized RID");
|
||||
}
|
||||
|
||||
if (unlikely((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) != validator)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL_V_MSG(nullptr, "Attempting to initialize the wrong RID");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF; // initialized
|
||||
|
||||
} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
if ((validator_chunks[idx_chunk][idx_element] & 0x80000000) && validator_chunks[idx_chunk][idx_element] != 0xFFFFFFFF) {
|
||||
ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T *ptr = &chunks[idx_chunk][idx_element];
|
||||
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
void initialize_rid(RID p_rid) {
|
||||
T *mem = get_or_null(p_rid, true);
|
||||
ERR_FAIL_NULL(mem);
|
||||
memnew_placement(mem, T);
|
||||
}
|
||||
void initialize_rid(RID p_rid, const T &p_value) {
|
||||
T *mem = get_or_null(p_rid, true);
|
||||
ERR_FAIL_NULL(mem);
|
||||
memnew_placement(mem, T(p_value));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool owns(const RID &p_rid) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
|
||||
uint64_t id = p_rid.get_id();
|
||||
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
|
||||
if (unlikely(idx >= max_alloc)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t idx_chunk = idx / elements_in_chunk;
|
||||
uint32_t idx_element = idx % elements_in_chunk;
|
||||
|
||||
uint32_t validator = uint32_t(id >> 32);
|
||||
|
||||
bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
|
||||
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
|
||||
return owned;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void free(const RID &p_rid) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
|
||||
uint64_t id = p_rid.get_id();
|
||||
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
|
||||
if (unlikely(idx >= max_alloc)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
uint32_t idx_chunk = idx / elements_in_chunk;
|
||||
uint32_t idx_element = idx % elements_in_chunk;
|
||||
|
||||
uint32_t validator = uint32_t(id >> 32);
|
||||
if (unlikely(validator_chunks[idx_chunk][idx_element] & 0x80000000)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID");
|
||||
} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
chunks[idx_chunk][idx_element].~T();
|
||||
validator_chunks[idx_chunk][idx_element] = 0xFFFFFFFF; // go invalid
|
||||
|
||||
alloc_count--;
|
||||
free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk] = idx;
|
||||
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t get_rid_count() const {
|
||||
return alloc_count;
|
||||
}
|
||||
|
||||
void get_owned_list(List<RID> *p_owned) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
for (size_t i = 0; i < max_alloc; i++) {
|
||||
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
|
||||
if (validator != 0xFFFFFFFF) {
|
||||
p_owned->push_back(UtilityFunctions::rid_from_int64((validator << 32) | i));
|
||||
}
|
||||
}
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// used for fast iteration in the elements or RIDs
|
||||
void fill_owned_buffer(RID *p_rid_buffer) {
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.lock();
|
||||
}
|
||||
uint32_t idx = 0;
|
||||
for (size_t i = 0; i < max_alloc; i++) {
|
||||
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
|
||||
if (validator != 0xFFFFFFFF) {
|
||||
p_rid_buffer[idx] = UtilityFunctions::rid_from_int64((validator << 32) | i);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
if (THREAD_SAFE) {
|
||||
spin_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void set_description(const char *p_descrption) {
|
||||
description = p_descrption;
|
||||
}
|
||||
|
||||
RID_Alloc(uint32_t p_target_chunk_byte_size = 65536) {
|
||||
elements_in_chunk = sizeof(T) > p_target_chunk_byte_size ? 1 : (p_target_chunk_byte_size / sizeof(T));
|
||||
}
|
||||
|
||||
~RID_Alloc() {
|
||||
if (alloc_count) {
|
||||
if (description) {
|
||||
printf("ERROR: %d RID allocations of type '%s' were leaked at exit.", alloc_count, description);
|
||||
} else {
|
||||
#ifdef NO_SAFE_CAST
|
||||
printf("ERROR: %d RID allocations of type 'unknown' were leaked at exit.", alloc_count);
|
||||
#else
|
||||
printf("ERROR: %d RID allocations of type '%s' were leaked at exit.", alloc_count, typeid(T).name());
|
||||
#endif
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < max_alloc; i++) {
|
||||
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
|
||||
if (validator & 0x80000000) {
|
||||
continue; // uninitialized
|
||||
}
|
||||
if (validator != 0xFFFFFFFF) {
|
||||
chunks[i / elements_in_chunk][i % elements_in_chunk].~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t chunk_count = max_alloc / elements_in_chunk;
|
||||
for (uint32_t i = 0; i < chunk_count; i++) {
|
||||
memfree(chunks[i]);
|
||||
memfree(validator_chunks[i]);
|
||||
memfree(free_list_chunks[i]);
|
||||
}
|
||||
|
||||
if (chunks) {
|
||||
memfree(chunks);
|
||||
memfree(free_list_chunks);
|
||||
memfree(validator_chunks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, bool THREAD_SAFE = false>
|
||||
class RID_PtrOwner {
|
||||
RID_Alloc<T *, THREAD_SAFE> alloc;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ RID make_rid(T *p_ptr) {
|
||||
return alloc.make_rid(p_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RID allocate_rid() {
|
||||
return alloc.allocate_rid();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void initialize_rid(RID p_rid, T *p_ptr) {
|
||||
alloc.initialize_rid(p_rid, p_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *get_or_null(const RID &p_rid) {
|
||||
T **ptr = alloc.get_or_null(p_rid);
|
||||
if (unlikely(!ptr)) {
|
||||
return nullptr;
|
||||
}
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
|
||||
T **ptr = alloc.get_or_null(p_rid);
|
||||
ERR_FAIL_NULL(ptr);
|
||||
*ptr = p_new_ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool owns(const RID &p_rid) {
|
||||
return alloc.owns(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void free(const RID &p_rid) {
|
||||
alloc.free(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t get_rid_count() const {
|
||||
return alloc.get_rid_count();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
|
||||
return alloc.get_owned_list(p_owned);
|
||||
}
|
||||
|
||||
void fill_owned_buffer(RID *p_rid_buffer) {
|
||||
alloc.fill_owned_buffer(p_rid_buffer);
|
||||
}
|
||||
|
||||
void set_description(const char *p_descrption) {
|
||||
alloc.set_description(p_descrption);
|
||||
}
|
||||
|
||||
RID_PtrOwner(uint32_t p_target_chunk_byte_size = 65536) :
|
||||
alloc(p_target_chunk_byte_size) {}
|
||||
};
|
||||
|
||||
template <class T, bool THREAD_SAFE = false>
|
||||
class RID_Owner {
|
||||
RID_Alloc<T, THREAD_SAFE> alloc;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ RID make_rid() {
|
||||
return alloc.make_rid();
|
||||
}
|
||||
_FORCE_INLINE_ RID make_rid(const T &p_ptr) {
|
||||
return alloc.make_rid(p_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RID allocate_rid() {
|
||||
return alloc.allocate_rid();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void initialize_rid(RID p_rid) {
|
||||
alloc.initialize_rid(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) {
|
||||
alloc.initialize_rid(p_rid, p_ptr);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *get_or_null(const RID &p_rid) {
|
||||
return alloc.get_or_null(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool owns(const RID &p_rid) {
|
||||
return alloc.owns(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void free(const RID &p_rid) {
|
||||
alloc.free(p_rid);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t get_rid_count() const {
|
||||
return alloc.get_rid_count();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
|
||||
return alloc.get_owned_list(p_owned);
|
||||
}
|
||||
void fill_owned_buffer(RID *p_rid_buffer) {
|
||||
alloc.fill_owned_buffer(p_rid_buffer);
|
||||
}
|
||||
|
||||
void set_description(const char *p_descrption) {
|
||||
alloc.set_description(p_descrption);
|
||||
}
|
||||
RID_Owner(uint32_t p_target_chunk_byte_size = 65536) :
|
||||
alloc(p_target_chunk_byte_size) {}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_RID_OWNER_HPP
|
||||
@@ -1,326 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* safe_refcount.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_SAFE_REFCOUNT_HPP
|
||||
#define GODOT_SAFE_REFCOUNT_HPP
|
||||
|
||||
#if !defined(NO_THREADS)
|
||||
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
|
||||
namespace godot {
|
||||
|
||||
// Design goals for these classes:
|
||||
// - No automatic conversions or arithmetic operators,
|
||||
// to keep explicit the use of atomics everywhere.
|
||||
// - Using acquire-release semantics, even to set the first value.
|
||||
// The first value may be set relaxedly in many cases, but adding the distinction
|
||||
// between relaxed and unrelaxed operation to the interface would make it needlessly
|
||||
// flexible. There's negligible waste in having release semantics for the initial
|
||||
// value and, as an important benefit, you can be sure the value is properly synchronized
|
||||
// even with threads that are already running.
|
||||
|
||||
template <class T>
|
||||
class SafeNumeric {
|
||||
std::atomic<T> value;
|
||||
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ void set(T p_value) {
|
||||
value.store(p_value, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T get() const {
|
||||
return value.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T increment() {
|
||||
return value.fetch_add(1, std::memory_order_acq_rel) + 1;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postincrement() {
|
||||
return value.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T decrement() {
|
||||
return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postdecrement() {
|
||||
return value.fetch_sub(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T add(T p_value) {
|
||||
return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postadd(T p_value) {
|
||||
return value.fetch_add(p_value, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T sub(T p_value) {
|
||||
return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
|
||||
}
|
||||
|
||||
// Returns the original value instead of the new one
|
||||
_ALWAYS_INLINE_ T postsub(T p_value) {
|
||||
return value.fetch_sub(p_value, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
|
||||
while (true) {
|
||||
T tmp = value.load(std::memory_order_acquire);
|
||||
if (tmp >= p_value) {
|
||||
return tmp; // already greater, or equal
|
||||
}
|
||||
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
|
||||
return p_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T conditional_increment() {
|
||||
while (true) {
|
||||
T c = value.load(std::memory_order_acquire);
|
||||
if (c == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
|
||||
return c + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
|
||||
set(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
class SafeFlag {
|
||||
std::atomic_bool flag;
|
||||
|
||||
static_assert(std::atomic_bool::is_always_lock_free);
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool is_set() const {
|
||||
return flag.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set() {
|
||||
flag.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void clear() {
|
||||
flag.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set_to(bool p_value) {
|
||||
flag.store(p_value, std::memory_order_release);
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
|
||||
set_to(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
class SafeRefCount {
|
||||
SafeNumeric<uint32_t> count;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool ref() { // true on success
|
||||
return count.conditional_increment() != 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
|
||||
return count.conditional_increment();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
|
||||
return count.decrement() == 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
|
||||
return count.decrement();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t get() const {
|
||||
return count.get();
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
|
||||
count.set(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
class SafeNumeric {
|
||||
protected:
|
||||
T value;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ void set(T p_value) {
|
||||
value = p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T increment() {
|
||||
return ++value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postincrement() {
|
||||
return value++;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T decrement() {
|
||||
return --value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postdecrement() {
|
||||
return value--;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T add(T p_value) {
|
||||
return value += p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postadd(T p_value) {
|
||||
T old = value;
|
||||
value += p_value;
|
||||
return old;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T sub(T p_value) {
|
||||
return value -= p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T postsub(T p_value) {
|
||||
T old = value;
|
||||
value -= p_value;
|
||||
return old;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
|
||||
if (value < p_value) {
|
||||
value = p_value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ T conditional_increment() {
|
||||
if (value == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return ++value;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
|
||||
value(p_value) {
|
||||
}
|
||||
};
|
||||
|
||||
class SafeFlag {
|
||||
protected:
|
||||
bool flag;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool is_set() const {
|
||||
return flag;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set() {
|
||||
flag = true;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void clear() {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void set_to(bool p_value) {
|
||||
flag = p_value;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
|
||||
flag(p_value) {}
|
||||
};
|
||||
|
||||
class SafeRefCount {
|
||||
uint32_t count = 0;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ bool ref() { // true on success
|
||||
if (count != 0) {
|
||||
++count;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
|
||||
if (count != 0) {
|
||||
return ++count;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
|
||||
return --count == 0;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
|
||||
return --count;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ uint32_t get() const {
|
||||
return count;
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
|
||||
count = p_value;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SAFE_REFCOUNT_HPP
|
||||
@@ -1,71 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* search_array.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_SEARCH_ARRAY_HPP
|
||||
#define GODOT_SEARCH_ARRAY_HPP
|
||||
|
||||
#include <godot_cpp/templates/sort_array.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, class Comparator = _DefaultComparator<T>>
|
||||
class SearchArray {
|
||||
public:
|
||||
Comparator compare;
|
||||
|
||||
inline int bisect(const T *p_array, int p_len, const T &p_value, bool p_before) const {
|
||||
int lo = 0;
|
||||
int hi = p_len;
|
||||
if (p_before) {
|
||||
while (lo < hi) {
|
||||
const int mid = (lo + hi) / 2;
|
||||
if (compare(p_array[mid], p_value)) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (lo < hi) {
|
||||
const int mid = (lo + hi) / 2;
|
||||
if (compare(p_value, p_array[mid])) {
|
||||
hi = mid;
|
||||
} else {
|
||||
lo = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SEARCH_ARRAY_HPP
|
||||
@@ -1,143 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* self_list.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_SELF_LIST_HPP
|
||||
#define GODOT_SELF_LIST_HPP
|
||||
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
class SelfList {
|
||||
public:
|
||||
class List {
|
||||
SelfList<T> *_first = nullptr;
|
||||
SelfList<T> *_last = nullptr;
|
||||
|
||||
public:
|
||||
void add(SelfList<T> *p_elem) {
|
||||
ERR_FAIL_COND(p_elem->_root);
|
||||
|
||||
p_elem->_root = this;
|
||||
p_elem->_next = _first;
|
||||
p_elem->_prev = nullptr;
|
||||
|
||||
if (_first) {
|
||||
_first->_prev = p_elem;
|
||||
|
||||
} else {
|
||||
_last = p_elem;
|
||||
}
|
||||
|
||||
_first = p_elem;
|
||||
}
|
||||
|
||||
void add_last(SelfList<T> *p_elem) {
|
||||
ERR_FAIL_COND(p_elem->_root);
|
||||
|
||||
p_elem->_root = this;
|
||||
p_elem->_next = nullptr;
|
||||
p_elem->_prev = _last;
|
||||
|
||||
if (_last) {
|
||||
_last->_next = p_elem;
|
||||
|
||||
} else {
|
||||
_first = p_elem;
|
||||
}
|
||||
|
||||
_last = p_elem;
|
||||
}
|
||||
|
||||
void remove(SelfList<T> *p_elem) {
|
||||
ERR_FAIL_COND(p_elem->_root != this);
|
||||
if (p_elem->_next) {
|
||||
p_elem->_next->_prev = p_elem->_prev;
|
||||
}
|
||||
|
||||
if (p_elem->_prev) {
|
||||
p_elem->_prev->_next = p_elem->_next;
|
||||
}
|
||||
|
||||
if (_first == p_elem) {
|
||||
_first = p_elem->_next;
|
||||
}
|
||||
|
||||
if (_last == p_elem) {
|
||||
_last = p_elem->_prev;
|
||||
}
|
||||
|
||||
p_elem->_next = nullptr;
|
||||
p_elem->_prev = nullptr;
|
||||
p_elem->_root = nullptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ SelfList<T> *first() { return _first; }
|
||||
_FORCE_INLINE_ const SelfList<T> *first() const { return _first; }
|
||||
|
||||
_FORCE_INLINE_ List() {}
|
||||
_FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != nullptr); }
|
||||
};
|
||||
|
||||
private:
|
||||
List *_root = nullptr;
|
||||
T *_self = nullptr;
|
||||
SelfList<T> *_next = nullptr;
|
||||
SelfList<T> *_prev = nullptr;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ bool in_list() const { return _root; }
|
||||
_FORCE_INLINE_ void remove_from_list() {
|
||||
if (_root) {
|
||||
_root->remove(this);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ SelfList<T> *next() { return _next; }
|
||||
_FORCE_INLINE_ SelfList<T> *prev() { return _prev; }
|
||||
_FORCE_INLINE_ const SelfList<T> *next() const { return _next; }
|
||||
_FORCE_INLINE_ const SelfList<T> *prev() const { return _prev; }
|
||||
_FORCE_INLINE_ T *self() const { return _self; }
|
||||
|
||||
_FORCE_INLINE_ SelfList(T *p_self) {
|
||||
_self = p_self;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ~SelfList() {
|
||||
if (_root) {
|
||||
_root->remove(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SELF_LIST_HPP
|
||||
@@ -1,323 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* sort_array.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_SORT_ARRAY_HPP
|
||||
#define GODOT_SORT_ARRAY_HPP
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
#define ERR_BAD_COMPARE(cond) \
|
||||
if (unlikely(cond)) { \
|
||||
ERR_PRINT("bad comparison function; sorting will be broken"); \
|
||||
break; \
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct _DefaultComparator {
|
||||
_FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
|
||||
};
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define SORT_ARRAY_VALIDATE_ENABLED true
|
||||
#else
|
||||
#define SORT_ARRAY_VALIDATE_ENABLED false
|
||||
#endif
|
||||
|
||||
template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
|
||||
class SortArray {
|
||||
enum {
|
||||
INTROSORT_THRESHOLD = 16
|
||||
};
|
||||
|
||||
public:
|
||||
Comparator compare;
|
||||
|
||||
inline const T &median_of_3(const T &a, const T &b, const T &c) const {
|
||||
if (compare(a, b)) {
|
||||
if (compare(b, c)) {
|
||||
return b;
|
||||
} else if (compare(a, c)) {
|
||||
return c;
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
} else if (compare(a, c)) {
|
||||
return a;
|
||||
} else if (compare(b, c)) {
|
||||
return c;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
inline int bitlog(int n) const {
|
||||
int k;
|
||||
for (k = 0; n != 1; n >>= 1) {
|
||||
++k;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/* Heap / Heapsort functions */
|
||||
|
||||
inline void push_heap(int p_first, int p_hole_idx, int p_top_index, T p_value, T *p_array) const {
|
||||
int parent = (p_hole_idx - 1) / 2;
|
||||
while (p_hole_idx > p_top_index && compare(p_array[p_first + parent], p_value)) {
|
||||
p_array[p_first + p_hole_idx] = p_array[p_first + parent];
|
||||
p_hole_idx = parent;
|
||||
parent = (p_hole_idx - 1) / 2;
|
||||
}
|
||||
p_array[p_first + p_hole_idx] = p_value;
|
||||
}
|
||||
|
||||
inline void pop_heap(int p_first, int p_last, int p_result, T p_value, T *p_array) const {
|
||||
p_array[p_result] = p_array[p_first];
|
||||
adjust_heap(p_first, 0, p_last - p_first, p_value, p_array);
|
||||
}
|
||||
inline void pop_heap(int p_first, int p_last, T *p_array) const {
|
||||
pop_heap(p_first, p_last - 1, p_last - 1, p_array[p_last - 1], p_array);
|
||||
}
|
||||
|
||||
inline void adjust_heap(int p_first, int p_hole_idx, int p_len, T p_value, T *p_array) const {
|
||||
int top_index = p_hole_idx;
|
||||
int second_child = 2 * p_hole_idx + 2;
|
||||
|
||||
while (second_child < p_len) {
|
||||
if (compare(p_array[p_first + second_child], p_array[p_first + (second_child - 1)])) {
|
||||
second_child--;
|
||||
}
|
||||
|
||||
p_array[p_first + p_hole_idx] = p_array[p_first + second_child];
|
||||
p_hole_idx = second_child;
|
||||
second_child = 2 * (second_child + 1);
|
||||
}
|
||||
|
||||
if (second_child == p_len) {
|
||||
p_array[p_first + p_hole_idx] = p_array[p_first + (second_child - 1)];
|
||||
p_hole_idx = second_child - 1;
|
||||
}
|
||||
push_heap(p_first, p_hole_idx, top_index, p_value, p_array);
|
||||
}
|
||||
|
||||
inline void sort_heap(int p_first, int p_last, T *p_array) const {
|
||||
while (p_last - p_first > 1) {
|
||||
pop_heap(p_first, p_last--, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void make_heap(int p_first, int p_last, T *p_array) const {
|
||||
if (p_last - p_first < 2) {
|
||||
return;
|
||||
}
|
||||
int len = p_last - p_first;
|
||||
int parent = (len - 2) / 2;
|
||||
|
||||
while (true) {
|
||||
adjust_heap(p_first, parent, len, p_array[p_first + parent], p_array);
|
||||
if (parent == 0) {
|
||||
return;
|
||||
}
|
||||
parent--;
|
||||
}
|
||||
}
|
||||
|
||||
inline void partial_sort(int p_first, int p_last, int p_middle, T *p_array) const {
|
||||
make_heap(p_first, p_middle, p_array);
|
||||
for (int i = p_middle; i < p_last; i++) {
|
||||
if (compare(p_array[i], p_array[p_first])) {
|
||||
pop_heap(p_first, p_middle, i, p_array[i], p_array);
|
||||
}
|
||||
}
|
||||
sort_heap(p_first, p_middle, p_array);
|
||||
}
|
||||
|
||||
inline void partial_select(int p_first, int p_last, int p_middle, T *p_array) const {
|
||||
make_heap(p_first, p_middle, p_array);
|
||||
for (int i = p_middle; i < p_last; i++) {
|
||||
if (compare(p_array[i], p_array[p_first])) {
|
||||
pop_heap(p_first, p_middle, i, p_array[i], p_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const {
|
||||
const int unmodified_first = p_first;
|
||||
const int unmodified_last = p_last;
|
||||
|
||||
while (true) {
|
||||
while (compare(p_array[p_first], p_pivot)) {
|
||||
if (Validate) {
|
||||
ERR_BAD_COMPARE(p_first == unmodified_last - 1);
|
||||
}
|
||||
p_first++;
|
||||
}
|
||||
p_last--;
|
||||
while (compare(p_pivot, p_array[p_last])) {
|
||||
if (Validate) {
|
||||
ERR_BAD_COMPARE(p_last == unmodified_first);
|
||||
}
|
||||
p_last--;
|
||||
}
|
||||
|
||||
if (!(p_first < p_last)) {
|
||||
return p_first;
|
||||
}
|
||||
|
||||
SWAP(p_array[p_first], p_array[p_last]);
|
||||
p_first++;
|
||||
}
|
||||
}
|
||||
|
||||
inline void introsort(int p_first, int p_last, T *p_array, int p_max_depth) const {
|
||||
while (p_last - p_first > INTROSORT_THRESHOLD) {
|
||||
if (p_max_depth == 0) {
|
||||
partial_sort(p_first, p_last, p_last, p_array);
|
||||
return;
|
||||
}
|
||||
|
||||
p_max_depth--;
|
||||
|
||||
int cut = partitioner(
|
||||
p_first,
|
||||
p_last,
|
||||
median_of_3(
|
||||
p_array[p_first],
|
||||
p_array[p_first + (p_last - p_first) / 2],
|
||||
p_array[p_last - 1]),
|
||||
p_array);
|
||||
|
||||
introsort(cut, p_last, p_array, p_max_depth);
|
||||
p_last = cut;
|
||||
}
|
||||
}
|
||||
|
||||
inline void introselect(int p_first, int p_nth, int p_last, T *p_array, int p_max_depth) const {
|
||||
while (p_last - p_first > 3) {
|
||||
if (p_max_depth == 0) {
|
||||
partial_select(p_first, p_nth + 1, p_last, p_array);
|
||||
SWAP(p_first, p_nth);
|
||||
return;
|
||||
}
|
||||
|
||||
p_max_depth--;
|
||||
|
||||
int cut = partitioner(
|
||||
p_first,
|
||||
p_last,
|
||||
median_of_3(
|
||||
p_array[p_first],
|
||||
p_array[p_first + (p_last - p_first) / 2],
|
||||
p_array[p_last - 1]),
|
||||
p_array);
|
||||
|
||||
if (cut <= p_nth) {
|
||||
p_first = cut;
|
||||
} else {
|
||||
p_last = cut;
|
||||
}
|
||||
}
|
||||
|
||||
insertion_sort(p_first, p_last, p_array);
|
||||
}
|
||||
|
||||
inline void unguarded_linear_insert(int p_last, T p_value, T *p_array) const {
|
||||
int next = p_last - 1;
|
||||
while (compare(p_value, p_array[next])) {
|
||||
if (Validate) {
|
||||
ERR_BAD_COMPARE(next == 0);
|
||||
}
|
||||
p_array[p_last] = p_array[next];
|
||||
p_last = next;
|
||||
next--;
|
||||
}
|
||||
p_array[p_last] = p_value;
|
||||
}
|
||||
|
||||
inline void linear_insert(int p_first, int p_last, T *p_array) const {
|
||||
T val = p_array[p_last];
|
||||
if (compare(val, p_array[p_first])) {
|
||||
for (int i = p_last; i > p_first; i--) {
|
||||
p_array[i] = p_array[i - 1];
|
||||
}
|
||||
|
||||
p_array[p_first] = val;
|
||||
} else {
|
||||
unguarded_linear_insert(p_last, val, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void insertion_sort(int p_first, int p_last, T *p_array) const {
|
||||
if (p_first == p_last) {
|
||||
return;
|
||||
}
|
||||
for (int i = p_first + 1; i != p_last; i++) {
|
||||
linear_insert(p_first, i, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void unguarded_insertion_sort(int p_first, int p_last, T *p_array) const {
|
||||
for (int i = p_first; i != p_last; i++) {
|
||||
unguarded_linear_insert(i, p_array[i], p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void final_insertion_sort(int p_first, int p_last, T *p_array) const {
|
||||
if (p_last - p_first > INTROSORT_THRESHOLD) {
|
||||
insertion_sort(p_first, p_first + INTROSORT_THRESHOLD, p_array);
|
||||
unguarded_insertion_sort(p_first + INTROSORT_THRESHOLD, p_last, p_array);
|
||||
} else {
|
||||
insertion_sort(p_first, p_last, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void sort_range(int p_first, int p_last, T *p_array) const {
|
||||
if (p_first != p_last) {
|
||||
introsort(p_first, p_last, p_array, bitlog(p_last - p_first) * 2);
|
||||
final_insertion_sort(p_first, p_last, p_array);
|
||||
}
|
||||
}
|
||||
|
||||
inline void sort(T *p_array, int p_len) const {
|
||||
sort_range(0, p_len, p_array);
|
||||
}
|
||||
|
||||
inline void nth_element(int p_first, int p_last, int p_nth, T *p_array) const {
|
||||
if (p_first == p_last || p_nth == p_last) {
|
||||
return;
|
||||
}
|
||||
introselect(p_first, p_nth, p_last, p_array, bitlog(p_last - p_first) * 2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SORT_ARRAY_HPP
|
||||
@@ -1,54 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* spin_lock.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_SPIN_LOCK_HPP
|
||||
#define GODOT_SPIN_LOCK_HPP
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class SpinLock {
|
||||
std::atomic_flag locked = ATOMIC_FLAG_INIT;
|
||||
|
||||
public:
|
||||
_ALWAYS_INLINE_ void lock() {
|
||||
while (locked.test_and_set(std::memory_order_acquire)) {
|
||||
;
|
||||
}
|
||||
}
|
||||
_ALWAYS_INLINE_ void unlock() {
|
||||
locked.clear(std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_SPIN_LOCK_HPP
|
||||
@@ -1,205 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* thread_work_pool.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_THREAD_WORK_POOL_HPP
|
||||
#define GODOT_THREAD_WORK_POOL_HPP
|
||||
|
||||
#include <godot_cpp/classes/os.hpp>
|
||||
#include <godot_cpp/classes/semaphore.hpp>
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class ThreadWorkPool {
|
||||
std::atomic<uint32_t> index;
|
||||
|
||||
struct BaseWork {
|
||||
std::atomic<uint32_t> *index = nullptr;
|
||||
uint32_t max_elements = 0;
|
||||
virtual void work() = 0;
|
||||
virtual ~BaseWork() = default;
|
||||
};
|
||||
|
||||
template <class C, class M, class U>
|
||||
struct Work : public BaseWork {
|
||||
C *instance;
|
||||
M method;
|
||||
U userdata;
|
||||
virtual void work() {
|
||||
while (true) {
|
||||
uint32_t work_index = index->fetch_add(1, std::memory_order_relaxed);
|
||||
if (work_index >= max_elements) {
|
||||
break;
|
||||
}
|
||||
(instance->*method)(work_index, userdata);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ThreadData {
|
||||
std::thread thread;
|
||||
Semaphore start;
|
||||
Semaphore completed;
|
||||
std::atomic<bool> exit;
|
||||
BaseWork *work;
|
||||
};
|
||||
|
||||
ThreadData *threads = nullptr;
|
||||
uint32_t thread_count = 0;
|
||||
uint32_t threads_working = 0;
|
||||
BaseWork *current_work = nullptr;
|
||||
|
||||
static void _thread_function(void *p_user) {
|
||||
ThreadData *thread = static_cast<ThreadData *>(p_user);
|
||||
while (true) {
|
||||
thread->start.wait();
|
||||
if (thread->exit.load()) {
|
||||
break;
|
||||
}
|
||||
thread->work->work();
|
||||
thread->completed.post();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template <class C, class M, class U>
|
||||
void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
|
||||
ERR_FAIL_NULL(threads); // Never initialized.
|
||||
ERR_FAIL_COND(current_work != nullptr);
|
||||
|
||||
index.store(0, std::memory_order_release);
|
||||
|
||||
Work<C, M, U> *w = new (Work<C, M, U>);
|
||||
w->instance = p_instance;
|
||||
w->userdata = p_userdata;
|
||||
w->method = p_method;
|
||||
w->index = &index;
|
||||
w->max_elements = p_elements;
|
||||
|
||||
current_work = w;
|
||||
|
||||
threads_working = Math::min(p_elements, thread_count);
|
||||
|
||||
for (uint32_t i = 0; i < threads_working; i++) {
|
||||
threads[i].work = w;
|
||||
threads[i].start.post();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_working() const {
|
||||
return current_work != nullptr;
|
||||
}
|
||||
|
||||
bool is_done_dispatching() const {
|
||||
ERR_FAIL_NULL_V(current_work, true);
|
||||
return index.load(std::memory_order_acquire) >= current_work->max_elements;
|
||||
}
|
||||
|
||||
uint32_t get_work_index() const {
|
||||
ERR_FAIL_NULL_V(current_work, 0);
|
||||
uint32_t idx = index.load(std::memory_order_acquire);
|
||||
return Math::min(idx, current_work->max_elements);
|
||||
}
|
||||
|
||||
void end_work() {
|
||||
ERR_FAIL_NULL(current_work);
|
||||
for (uint32_t i = 0; i < threads_working; i++) {
|
||||
threads[i].completed.wait();
|
||||
threads[i].work = nullptr;
|
||||
}
|
||||
|
||||
threads_working = 0;
|
||||
delete current_work;
|
||||
current_work = nullptr;
|
||||
}
|
||||
|
||||
template <class C, class M, class U>
|
||||
void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
|
||||
switch (p_elements) {
|
||||
case 0:
|
||||
// Nothing to do, so do nothing.
|
||||
break;
|
||||
case 1:
|
||||
// No value in pushing the work to another thread if it's a single job
|
||||
// and we're going to wait for it to finish. Just run it right here.
|
||||
(p_instance->*p_method)(0, p_userdata);
|
||||
break;
|
||||
default:
|
||||
// Multiple jobs to do; commence threaded business.
|
||||
begin_work(p_elements, p_instance, p_method, p_userdata);
|
||||
end_work();
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int get_thread_count() const { return thread_count; }
|
||||
void init(int p_thread_count = -1) {
|
||||
ERR_FAIL_COND(threads != nullptr);
|
||||
if (p_thread_count < 0) {
|
||||
p_thread_count = OS::get_singleton()->get_processor_count();
|
||||
}
|
||||
|
||||
thread_count = p_thread_count;
|
||||
threads = new ThreadData[thread_count];
|
||||
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
threads[i].exit.store(false);
|
||||
threads[i].thread = std::thread(&ThreadWorkPool::_thread_function, &threads[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void finish() {
|
||||
if (threads == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
threads[i].exit.store(true);
|
||||
threads[i].start.post();
|
||||
}
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
threads[i].thread.join();
|
||||
}
|
||||
|
||||
delete[] (threads);
|
||||
threads = nullptr;
|
||||
}
|
||||
~ThreadWorkPool() {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_THREAD_WORK_POOL_HPP
|
||||
@@ -1,321 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* vector.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_VECTOR_HPP
|
||||
#define GODOT_VECTOR_HPP
|
||||
|
||||
/**
|
||||
* @class Vector
|
||||
* Vector container. Regular Vector Container. Use with care and for smaller arrays when possible. Use Vector for large arrays.
|
||||
*/
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/templates/cowdata.hpp>
|
||||
#include <godot_cpp/templates/search_array.hpp>
|
||||
#include <godot_cpp/templates/sort_array.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
class VectorWriteProxy {
|
||||
public:
|
||||
_FORCE_INLINE_ T &operator[](int p_index) {
|
||||
CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
|
||||
|
||||
return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Vector {
|
||||
friend class VectorWriteProxy<T>;
|
||||
|
||||
public:
|
||||
VectorWriteProxy<T> write;
|
||||
|
||||
private:
|
||||
CowData<T> _cowdata;
|
||||
|
||||
public:
|
||||
bool push_back(T p_elem);
|
||||
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } // alias
|
||||
void fill(T p_elem);
|
||||
|
||||
void remove_at(int p_index) { _cowdata.remove_at(p_index); }
|
||||
void erase(const T &p_val) {
|
||||
int idx = find(p_val);
|
||||
if (idx >= 0) {
|
||||
remove_at(idx);
|
||||
}
|
||||
}
|
||||
void reverse();
|
||||
|
||||
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
|
||||
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
|
||||
_FORCE_INLINE_ void clear() { resize(0); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
|
||||
|
||||
_FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); }
|
||||
_FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); }
|
||||
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
|
||||
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
|
||||
Error resize(int p_size) { return _cowdata.resize(p_size); }
|
||||
_FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); }
|
||||
Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
|
||||
int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); }
|
||||
|
||||
void append_array(Vector<T> p_other);
|
||||
|
||||
_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
|
||||
|
||||
template <class C>
|
||||
void sort_custom() {
|
||||
int len = _cowdata.size();
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
T *data = ptrw();
|
||||
SortArray<T, C> sorter;
|
||||
sorter.sort(data, len);
|
||||
}
|
||||
|
||||
void sort() {
|
||||
sort_custom<_DefaultComparator<T>>();
|
||||
}
|
||||
|
||||
int bsearch(const T &p_value, bool p_before) {
|
||||
SearchArray<T> search;
|
||||
return search.bisect(ptrw(), size(), p_value, p_before);
|
||||
}
|
||||
|
||||
Vector<T> duplicate() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ordered_insert(const T &p_val) {
|
||||
int i;
|
||||
for (i = 0; i < _cowdata.size(); i++) {
|
||||
if (p_val < operator[](i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
insert(i, p_val);
|
||||
}
|
||||
|
||||
inline void operator=(const Vector &p_from) {
|
||||
_cowdata._ref(p_from._cowdata);
|
||||
}
|
||||
|
||||
Vector<uint8_t> to_byte_array() const {
|
||||
Vector<uint8_t> ret;
|
||||
ret.resize(size() * sizeof(T));
|
||||
memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector<T> slice(int p_begin, int p_end = INT_MAX) const {
|
||||
Vector<T> result;
|
||||
|
||||
const int s = size();
|
||||
|
||||
int begin = Math::clamp(p_begin, -s, s);
|
||||
if (begin < 0) {
|
||||
begin += s;
|
||||
}
|
||||
int end = Math::clamp(p_end, -s, s);
|
||||
if (end < 0) {
|
||||
end += s;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(begin > end, result);
|
||||
|
||||
int result_size = end - begin;
|
||||
result.resize(result_size);
|
||||
|
||||
const T *const r = ptr();
|
||||
T *const w = result.ptrw();
|
||||
for (int i = 0; i < result_size; ++i) {
|
||||
w[i] = r[begin + i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const Vector<T> &p_arr) const {
|
||||
int s = size();
|
||||
if (s != p_arr.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (operator[](i) != p_arr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const Vector<T> &p_arr) const {
|
||||
int s = size();
|
||||
if (s != p_arr.size()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (operator[](i) != p_arr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
_FORCE_INLINE_ T &operator*() const {
|
||||
return *elem_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
|
||||
_FORCE_INLINE_ Iterator &operator++() {
|
||||
elem_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ Iterator &operator--() {
|
||||
elem_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
|
||||
|
||||
Iterator(T *p_ptr) { elem_ptr = p_ptr; }
|
||||
Iterator() {}
|
||||
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
|
||||
|
||||
private:
|
||||
T *elem_ptr = nullptr;
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
_FORCE_INLINE_ const T &operator*() const {
|
||||
return *elem_ptr;
|
||||
}
|
||||
_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
|
||||
_FORCE_INLINE_ ConstIterator &operator++() {
|
||||
elem_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator &operator--() {
|
||||
elem_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
|
||||
|
||||
ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
|
||||
ConstIterator() {}
|
||||
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
|
||||
|
||||
private:
|
||||
const T *elem_ptr = nullptr;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Iterator begin() {
|
||||
return Iterator(ptrw());
|
||||
}
|
||||
_FORCE_INLINE_ Iterator end() {
|
||||
return Iterator(ptrw() + size());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ConstIterator begin() const {
|
||||
return ConstIterator(ptr());
|
||||
}
|
||||
_FORCE_INLINE_ ConstIterator end() const {
|
||||
return ConstIterator(ptr() + size());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector() {}
|
||||
_FORCE_INLINE_ Vector(std::initializer_list<T> p_init) {
|
||||
Error err = _cowdata.resize(p_init.size());
|
||||
ERR_FAIL_COND(err);
|
||||
|
||||
int i = 0;
|
||||
for (const T &element : p_init) {
|
||||
_cowdata.set(i++, element);
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
|
||||
|
||||
_FORCE_INLINE_ ~Vector() {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void Vector<T>::reverse() {
|
||||
for (int i = 0; i < size() / 2; i++) {
|
||||
T *p = ptrw();
|
||||
SWAP(p[i], p[size() - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Vector<T>::append_array(Vector<T> p_other) {
|
||||
const int ds = p_other.size();
|
||||
if (ds == 0) {
|
||||
return;
|
||||
}
|
||||
const int bs = size();
|
||||
resize(bs + ds);
|
||||
for (int i = 0; i < ds; ++i) {
|
||||
ptrw()[bs + i] = p_other[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool Vector<T>::push_back(T p_elem) {
|
||||
Error err = resize(size() + 1);
|
||||
ERR_FAIL_COND_V(err, true);
|
||||
set(size() - 1, p_elem);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Vector<T>::fill(T p_elem) {
|
||||
T *p = ptrw();
|
||||
for (int i = 0; i < size(); i++) {
|
||||
p[i] = p_elem;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_VECTOR_HPP
|
||||
@@ -1,204 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* vmap.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_VMAP_HPP
|
||||
#define GODOT_VMAP_HPP
|
||||
|
||||
#include <godot_cpp/templates/cowdata.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, class V>
|
||||
class VMap {
|
||||
public:
|
||||
struct Pair {
|
||||
T key;
|
||||
V value;
|
||||
|
||||
_FORCE_INLINE_ Pair() {}
|
||||
|
||||
_FORCE_INLINE_ Pair(const T &p_key, const V &p_value) {
|
||||
key = p_key;
|
||||
value = p_value;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
CowData<Pair> _cowdata;
|
||||
|
||||
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
|
||||
r_exact = false;
|
||||
if (_cowdata.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _cowdata.size() - 1;
|
||||
const Pair *a = _cowdata.ptr();
|
||||
int middle = 0;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (low > high) {
|
||||
ERR_PRINT("low > high, this may be a bug");
|
||||
}
|
||||
#endif
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle].key) {
|
||||
high = middle - 1; // search low end of array
|
||||
} else if (a[middle].key < p_val) {
|
||||
low = middle + 1; // search high end of array
|
||||
} else {
|
||||
r_exact = true;
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
// return the position where this would be inserted
|
||||
if (a[middle].key < p_val) {
|
||||
middle++;
|
||||
}
|
||||
return middle;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
|
||||
if (_cowdata.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _cowdata.size() - 1;
|
||||
int middle;
|
||||
const Pair *a = _cowdata.ptr();
|
||||
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle].key) {
|
||||
high = middle - 1; // search low end of array
|
||||
} else if (a[middle].key < p_val) {
|
||||
low = middle + 1; // search high end of array
|
||||
} else {
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
int insert(const T &p_key, const V &p_val) {
|
||||
bool exact;
|
||||
int pos = _find(p_key, exact);
|
||||
if (exact) {
|
||||
_cowdata.get_m(pos).value = p_val;
|
||||
return pos;
|
||||
}
|
||||
_cowdata.insert(pos, Pair(p_key, p_val));
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool has(const T &p_val) const {
|
||||
return _find_exact(p_val) != -1;
|
||||
}
|
||||
|
||||
void erase(const T &p_val) {
|
||||
int pos = _find_exact(p_val);
|
||||
if (pos < 0) {
|
||||
return;
|
||||
}
|
||||
_cowdata.remove_at(pos);
|
||||
}
|
||||
|
||||
int find(const T &p_val) const {
|
||||
return _find_exact(p_val);
|
||||
}
|
||||
|
||||
int find_nearest(const T &p_val) const {
|
||||
bool exact;
|
||||
return _find(p_val, exact);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
|
||||
|
||||
const Pair *get_array() const {
|
||||
return _cowdata.ptr();
|
||||
}
|
||||
|
||||
Pair *get_array() {
|
||||
return _cowdata.ptrw();
|
||||
}
|
||||
|
||||
const V &getv(int p_index) const {
|
||||
return _cowdata.get(p_index).value;
|
||||
}
|
||||
|
||||
V &getv(int p_index) {
|
||||
return _cowdata.get_m(p_index).value;
|
||||
}
|
||||
|
||||
const T &getk(int p_index) const {
|
||||
return _cowdata.get(p_index).key;
|
||||
}
|
||||
|
||||
T &getk(int p_index) {
|
||||
return _cowdata.get_m(p_index).key;
|
||||
}
|
||||
|
||||
inline const V &operator[](const T &p_key) const {
|
||||
int pos = _find_exact(p_key);
|
||||
|
||||
CRASH_COND(pos < 0);
|
||||
|
||||
return _cowdata.get(pos).value;
|
||||
}
|
||||
|
||||
inline V &operator[](const T &p_key) {
|
||||
int pos = _find_exact(p_key);
|
||||
if (pos < 0) {
|
||||
pos = insert(p_key, V());
|
||||
}
|
||||
|
||||
return _cowdata.get_m(pos).value;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ VMap() {}
|
||||
_FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); }
|
||||
|
||||
inline void operator=(const VMap &p_from) {
|
||||
_cowdata._ref(p_from._cowdata);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_VMAP_HPP
|
||||
@@ -1,145 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* vset.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_VSET_HPP
|
||||
#define GODOT_VSET_HPP
|
||||
|
||||
#include <godot_cpp/templates/vector.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
class VSet {
|
||||
Vector<T> _data;
|
||||
|
||||
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
|
||||
r_exact = false;
|
||||
if (_data.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _data.size() - 1;
|
||||
const T *a = &_data[0];
|
||||
int middle = 0;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (low > high) {
|
||||
ERR_PRINT("low > high, this may be a bug");
|
||||
}
|
||||
#endif
|
||||
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle]) {
|
||||
high = middle - 1; // search low end of array
|
||||
} else if (a[middle] < p_val) {
|
||||
low = middle + 1; // search high end of array
|
||||
} else {
|
||||
r_exact = true;
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
// return the position where this would be inserted
|
||||
if (a[middle] < p_val) {
|
||||
middle++;
|
||||
}
|
||||
return middle;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
|
||||
if (_data.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _data.size() - 1;
|
||||
int middle;
|
||||
const T *a = &_data[0];
|
||||
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle]) {
|
||||
high = middle - 1; // search low end of array
|
||||
} else if (a[middle] < p_val) {
|
||||
low = middle + 1; // search high end of array
|
||||
} else {
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
void insert(const T &p_val) {
|
||||
bool exact;
|
||||
int pos = _find(p_val, exact);
|
||||
if (exact) {
|
||||
return;
|
||||
}
|
||||
_data.insert(pos, p_val);
|
||||
}
|
||||
|
||||
bool has(const T &p_val) const {
|
||||
return _find_exact(p_val) != -1;
|
||||
}
|
||||
|
||||
void erase(const T &p_val) {
|
||||
int pos = _find_exact(p_val);
|
||||
if (pos < 0) {
|
||||
return;
|
||||
}
|
||||
_data.remove_at(pos);
|
||||
}
|
||||
|
||||
int find(const T &p_val) const {
|
||||
return _find_exact(p_val);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool is_empty() const { return _data.is_empty(); }
|
||||
|
||||
_FORCE_INLINE_ int size() const { return _data.size(); }
|
||||
|
||||
inline T &operator[](int p_index) {
|
||||
return _data.write[p_index];
|
||||
}
|
||||
|
||||
inline const T &operator[](int p_index) const {
|
||||
return _data[p_index];
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_VSET_HPP
|
||||
@@ -1,494 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* aabb.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_AABB_HPP
|
||||
#define GODOT_AABB_HPP
|
||||
|
||||
#include <godot_cpp/variant/plane.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
|
||||
/**
|
||||
* AABB (Axis Aligned Bounding Box)
|
||||
* This is implemented by a point (position) and the box size.
|
||||
*/
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Variant;
|
||||
|
||||
struct _NO_DISCARD_ AABB {
|
||||
Vector3 position;
|
||||
Vector3 size;
|
||||
|
||||
real_t get_volume() const;
|
||||
_FORCE_INLINE_ bool has_volume() const {
|
||||
return size.x > 0.0f && size.y > 0.0f && size.z > 0.0f;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool has_surface() const {
|
||||
return size.x > 0.0f || size.y > 0.0f || size.z > 0.0f;
|
||||
}
|
||||
|
||||
const Vector3 &get_position() const { return position; }
|
||||
void set_position(const Vector3 &p_pos) { position = p_pos; }
|
||||
const Vector3 &get_size() const { return size; }
|
||||
void set_size(const Vector3 &p_size) { size = p_size; }
|
||||
|
||||
bool operator==(const AABB &p_rval) const;
|
||||
bool operator!=(const AABB &p_rval) const;
|
||||
|
||||
bool is_equal_approx(const AABB &p_aabb) const;
|
||||
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
|
||||
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
|
||||
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
|
||||
|
||||
AABB merge(const AABB &p_with) const;
|
||||
void merge_with(const AABB &p_aabb); ///merge with another AABB
|
||||
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
|
||||
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
|
||||
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
|
||||
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
|
||||
|
||||
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
|
||||
_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
|
||||
bool intersects_plane(const Plane &p_plane) const;
|
||||
|
||||
_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
|
||||
_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const;
|
||||
|
||||
Vector3 get_longest_axis() const;
|
||||
int get_longest_axis_index() const;
|
||||
_FORCE_INLINE_ real_t get_longest_axis_size() const;
|
||||
|
||||
Vector3 get_shortest_axis() const;
|
||||
int get_shortest_axis_index() const;
|
||||
_FORCE_INLINE_ real_t get_shortest_axis_size() const;
|
||||
|
||||
AABB grow(real_t p_by) const;
|
||||
_FORCE_INLINE_ void grow_by(real_t p_amount);
|
||||
|
||||
void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const;
|
||||
_FORCE_INLINE_ Vector3 get_endpoint(int p_point) const;
|
||||
|
||||
AABB expand(const Vector3 &p_vector) const;
|
||||
_FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
|
||||
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
|
||||
|
||||
_FORCE_INLINE_ AABB abs() const {
|
||||
return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
|
||||
}
|
||||
|
||||
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
|
||||
Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
|
||||
|
||||
_FORCE_INLINE_ void quantize(real_t p_unit);
|
||||
_FORCE_INLINE_ AABB quantized(real_t p_unit) const;
|
||||
|
||||
_FORCE_INLINE_ void set_end(const Vector3 &p_end) {
|
||||
size = p_end - position;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 get_end() const {
|
||||
return position + size;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 get_center() const {
|
||||
return position + (size * 0.5f);
|
||||
}
|
||||
|
||||
operator String() const;
|
||||
|
||||
_FORCE_INLINE_ AABB() {}
|
||||
inline AABB(const Vector3 &p_pos, const Vector3 &p_size) :
|
||||
position(p_pos),
|
||||
size(p_size) {
|
||||
}
|
||||
};
|
||||
|
||||
inline bool AABB::intersects(const AABB &p_aabb) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (position.x >= (p_aabb.position.x + p_aabb.size.x)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.x + size.x) <= p_aabb.position.x) {
|
||||
return false;
|
||||
}
|
||||
if (position.y >= (p_aabb.position.y + p_aabb.size.y)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.y + size.y) <= p_aabb.position.y) {
|
||||
return false;
|
||||
}
|
||||
if (position.z >= (p_aabb.position.z + p_aabb.size.z)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.z + size.z) <= p_aabb.position.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool AABB::intersects_inclusive(const AABB &p_aabb) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (position.x > (p_aabb.position.x + p_aabb.size.x)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.x + size.x) < p_aabb.position.x) {
|
||||
return false;
|
||||
}
|
||||
if (position.y > (p_aabb.position.y + p_aabb.size.y)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.y + size.y) < p_aabb.position.y) {
|
||||
return false;
|
||||
}
|
||||
if (position.z > (p_aabb.position.z + p_aabb.size.z)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.z + size.z) < p_aabb.position.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool AABB::encloses(const AABB &p_aabb) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
Vector3 src_min = position;
|
||||
Vector3 src_max = position + size;
|
||||
Vector3 dst_min = p_aabb.position;
|
||||
Vector3 dst_max = p_aabb.position + p_aabb.size;
|
||||
|
||||
return (
|
||||
(src_min.x <= dst_min.x) &&
|
||||
(src_max.x > dst_max.x) &&
|
||||
(src_min.y <= dst_min.y) &&
|
||||
(src_max.y > dst_max.y) &&
|
||||
(src_min.z <= dst_min.z) &&
|
||||
(src_max.z > dst_max.z));
|
||||
}
|
||||
|
||||
Vector3 AABB::get_support(const Vector3 &p_normal) const {
|
||||
Vector3 half_extents = size * 0.5f;
|
||||
Vector3 ofs = position + half_extents;
|
||||
|
||||
return Vector3(
|
||||
(p_normal.x > 0) ? half_extents.x : -half_extents.x,
|
||||
(p_normal.y > 0) ? half_extents.y : -half_extents.y,
|
||||
(p_normal.z > 0) ? half_extents.z : -half_extents.z) +
|
||||
ofs;
|
||||
}
|
||||
|
||||
Vector3 AABB::get_endpoint(int p_point) const {
|
||||
switch (p_point) {
|
||||
case 0:
|
||||
return Vector3(position.x, position.y, position.z);
|
||||
case 1:
|
||||
return Vector3(position.x, position.y, position.z + size.z);
|
||||
case 2:
|
||||
return Vector3(position.x, position.y + size.y, position.z);
|
||||
case 3:
|
||||
return Vector3(position.x, position.y + size.y, position.z + size.z);
|
||||
case 4:
|
||||
return Vector3(position.x + size.x, position.y, position.z);
|
||||
case 5:
|
||||
return Vector3(position.x + size.x, position.y, position.z + size.z);
|
||||
case 6:
|
||||
return Vector3(position.x + size.x, position.y + size.y, position.z);
|
||||
case 7:
|
||||
return Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
|
||||
}
|
||||
|
||||
ERR_FAIL_V(Vector3());
|
||||
}
|
||||
|
||||
bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
|
||||
Vector3 half_extents = size * 0.5f;
|
||||
Vector3 ofs = position + half_extents;
|
||||
|
||||
for (int i = 0; i < p_plane_count; i++) {
|
||||
const Plane &p = p_planes[i];
|
||||
Vector3 point(
|
||||
(p.normal.x > 0) ? -half_extents.x : half_extents.x,
|
||||
(p.normal.y > 0) ? -half_extents.y : half_extents.y,
|
||||
(p.normal.z > 0) ? -half_extents.z : half_extents.z);
|
||||
point += ofs;
|
||||
if (p.is_point_over(point)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all points in the shape aren't fully separated from the AABB on
|
||||
// each axis.
|
||||
int bad_point_counts_positive[3] = { 0 };
|
||||
int bad_point_counts_negative[3] = { 0 };
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
for (int i = 0; i < p_point_count; i++) {
|
||||
if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) {
|
||||
bad_point_counts_positive[k]++;
|
||||
}
|
||||
if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) {
|
||||
bad_point_counts_negative[k]++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bad_point_counts_negative[k] == p_point_count) {
|
||||
return false;
|
||||
}
|
||||
if (bad_point_counts_positive[k] == p_point_count) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const {
|
||||
Vector3 half_extents = size * 0.5f;
|
||||
Vector3 ofs = position + half_extents;
|
||||
|
||||
for (int i = 0; i < p_plane_count; i++) {
|
||||
const Plane &p = p_planes[i];
|
||||
Vector3 point(
|
||||
(p.normal.x < 0) ? -half_extents.x : half_extents.x,
|
||||
(p.normal.y < 0) ? -half_extents.y : half_extents.y,
|
||||
(p.normal.z < 0) ? -half_extents.z : half_extents.z);
|
||||
point += ofs;
|
||||
if (p.is_point_over(point)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AABB::has_point(const Vector3 &p_point) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (p_point.x < position.x) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.y < position.y) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.z < position.z) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.x > position.x + size.x) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.y > position.y + size.y) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.z > position.z + size.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void AABB::expand_to(const Vector3 &p_vector) {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
Vector3 begin = position;
|
||||
Vector3 end = position + size;
|
||||
|
||||
if (p_vector.x < begin.x) {
|
||||
begin.x = p_vector.x;
|
||||
}
|
||||
if (p_vector.y < begin.y) {
|
||||
begin.y = p_vector.y;
|
||||
}
|
||||
if (p_vector.z < begin.z) {
|
||||
begin.z = p_vector.z;
|
||||
}
|
||||
|
||||
if (p_vector.x > end.x) {
|
||||
end.x = p_vector.x;
|
||||
}
|
||||
if (p_vector.y > end.y) {
|
||||
end.y = p_vector.y;
|
||||
}
|
||||
if (p_vector.z > end.z) {
|
||||
end.z = p_vector.z;
|
||||
}
|
||||
|
||||
position = begin;
|
||||
size = end - begin;
|
||||
}
|
||||
|
||||
void AABB::project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const {
|
||||
Vector3 half_extents(size.x * 0.5f, size.y * 0.5f, size.z * 0.5f);
|
||||
Vector3 center(position.x + half_extents.x, position.y + half_extents.y, position.z + half_extents.z);
|
||||
|
||||
real_t length = p_plane.normal.abs().dot(half_extents);
|
||||
real_t distance = p_plane.distance_to(center);
|
||||
r_min = distance - length;
|
||||
r_max = distance + length;
|
||||
}
|
||||
|
||||
inline real_t AABB::get_longest_axis_size() const {
|
||||
real_t max_size = size.x;
|
||||
|
||||
if (size.y > max_size) {
|
||||
max_size = size.y;
|
||||
}
|
||||
|
||||
if (size.z > max_size) {
|
||||
max_size = size.z;
|
||||
}
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
inline real_t AABB::get_shortest_axis_size() const {
|
||||
real_t max_size = size.x;
|
||||
|
||||
if (size.y < max_size) {
|
||||
max_size = size.y;
|
||||
}
|
||||
|
||||
if (size.z < max_size) {
|
||||
max_size = size.z;
|
||||
}
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
|
||||
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
|
||||
}
|
||||
#endif
|
||||
real_t divx = 1.0f / p_dir.x;
|
||||
real_t divy = 1.0f / p_dir.y;
|
||||
real_t divz = 1.0f / p_dir.z;
|
||||
|
||||
Vector3 upbound = position + size;
|
||||
real_t tmin, tmax, tymin, tymax, tzmin, tzmax;
|
||||
if (p_dir.x >= 0) {
|
||||
tmin = (position.x - p_from.x) * divx;
|
||||
tmax = (upbound.x - p_from.x) * divx;
|
||||
} else {
|
||||
tmin = (upbound.x - p_from.x) * divx;
|
||||
tmax = (position.x - p_from.x) * divx;
|
||||
}
|
||||
if (p_dir.y >= 0) {
|
||||
tymin = (position.y - p_from.y) * divy;
|
||||
tymax = (upbound.y - p_from.y) * divy;
|
||||
} else {
|
||||
tymin = (upbound.y - p_from.y) * divy;
|
||||
tymax = (position.y - p_from.y) * divy;
|
||||
}
|
||||
if ((tmin > tymax) || (tymin > tmax)) {
|
||||
return false;
|
||||
}
|
||||
if (tymin > tmin) {
|
||||
tmin = tymin;
|
||||
}
|
||||
if (tymax < tmax) {
|
||||
tmax = tymax;
|
||||
}
|
||||
if (p_dir.z >= 0) {
|
||||
tzmin = (position.z - p_from.z) * divz;
|
||||
tzmax = (upbound.z - p_from.z) * divz;
|
||||
} else {
|
||||
tzmin = (upbound.z - p_from.z) * divz;
|
||||
tzmax = (position.z - p_from.z) * divz;
|
||||
}
|
||||
if ((tmin > tzmax) || (tzmin > tmax)) {
|
||||
return false;
|
||||
}
|
||||
if (tzmin > tmin) {
|
||||
tmin = tzmin;
|
||||
}
|
||||
if (tzmax < tmax) {
|
||||
tmax = tzmax;
|
||||
}
|
||||
return ((tmin < t1) && (tmax > t0));
|
||||
}
|
||||
|
||||
void AABB::grow_by(real_t p_amount) {
|
||||
position.x -= p_amount;
|
||||
position.y -= p_amount;
|
||||
position.z -= p_amount;
|
||||
size.x += 2.0f * p_amount;
|
||||
size.y += 2.0f * p_amount;
|
||||
size.z += 2.0f * p_amount;
|
||||
}
|
||||
|
||||
void AABB::quantize(real_t p_unit) {
|
||||
size += position;
|
||||
|
||||
position.x -= Math::fposmodp(position.x, p_unit);
|
||||
position.y -= Math::fposmodp(position.y, p_unit);
|
||||
position.z -= Math::fposmodp(position.z, p_unit);
|
||||
|
||||
size.x -= Math::fposmodp(size.x, p_unit);
|
||||
size.y -= Math::fposmodp(size.y, p_unit);
|
||||
size.z -= Math::fposmodp(size.z, p_unit);
|
||||
|
||||
size.x += p_unit;
|
||||
size.y += p_unit;
|
||||
size.z += p_unit;
|
||||
|
||||
size -= position;
|
||||
}
|
||||
|
||||
AABB AABB::quantized(real_t p_unit) const {
|
||||
AABB ret = *this;
|
||||
ret.quantize(p_unit);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_AABB_HPP
|
||||
@@ -1,50 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* array_helpers.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
namespace godot {
|
||||
namespace helpers {
|
||||
template <typename T, typename ValueT>
|
||||
T append_all(T appendable, ValueT value) {
|
||||
appendable.append(value);
|
||||
return appendable;
|
||||
}
|
||||
|
||||
template <typename T, typename ValueT, typename... Args>
|
||||
T append_all(T appendable, ValueT value, Args... args) {
|
||||
appendable.append(value);
|
||||
return append_all(appendable, args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T append_all(T appendable) {
|
||||
return appendable;
|
||||
}
|
||||
} // namespace helpers
|
||||
} // namespace godot
|
||||
@@ -1,318 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* basis.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_BASIS_HPP
|
||||
#define GODOT_BASIS_HPP
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/variant/quaternion.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct _NO_DISCARD_ Basis {
|
||||
Vector3 rows[3] = {
|
||||
Vector3(1, 0, 0),
|
||||
Vector3(0, 1, 0),
|
||||
Vector3(0, 0, 1)
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ const Vector3 &operator[](int axis) const {
|
||||
return rows[axis];
|
||||
}
|
||||
_FORCE_INLINE_ Vector3 &operator[](int axis) {
|
||||
return rows[axis];
|
||||
}
|
||||
|
||||
void invert();
|
||||
void transpose();
|
||||
|
||||
Basis inverse() const;
|
||||
Basis transposed() const;
|
||||
|
||||
_FORCE_INLINE_ real_t determinant() const;
|
||||
|
||||
void from_z(const Vector3 &p_z);
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_angle);
|
||||
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
|
||||
|
||||
void rotate_local(const Vector3 &p_axis, real_t p_angle);
|
||||
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
|
||||
|
||||
void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
|
||||
Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const;
|
||||
|
||||
void rotate(const Quaternion &p_quaternion);
|
||||
Basis rotated(const Quaternion &p_quaternion) const;
|
||||
|
||||
Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const;
|
||||
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
|
||||
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
|
||||
Quaternion get_rotation_quaternion() const;
|
||||
|
||||
void rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction);
|
||||
|
||||
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
|
||||
|
||||
Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const;
|
||||
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
|
||||
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) {
|
||||
Basis b;
|
||||
b.set_euler(p_euler, p_order);
|
||||
return b;
|
||||
}
|
||||
|
||||
Quaternion get_quaternion() const;
|
||||
void set_quaternion(const Quaternion &p_quaternion);
|
||||
|
||||
void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const;
|
||||
void set_axis_angle(const Vector3 &p_axis, real_t p_angle);
|
||||
|
||||
void scale(const Vector3 &p_scale);
|
||||
Basis scaled(const Vector3 &p_scale) const;
|
||||
|
||||
void scale_local(const Vector3 &p_scale);
|
||||
Basis scaled_local(const Vector3 &p_scale) const;
|
||||
|
||||
void scale_orthogonal(const Vector3 &p_scale);
|
||||
Basis scaled_orthogonal(const Vector3 &p_scale) const;
|
||||
|
||||
void make_scale_uniform();
|
||||
float get_uniform_scale() const;
|
||||
|
||||
Vector3 get_scale() const;
|
||||
Vector3 get_scale_abs() const;
|
||||
Vector3 get_scale_local() const;
|
||||
|
||||
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
|
||||
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ);
|
||||
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
|
||||
|
||||
// transposed dot products
|
||||
_FORCE_INLINE_ real_t tdotx(const Vector3 &v) const {
|
||||
return rows[0][0] * v[0] + rows[1][0] * v[1] + rows[2][0] * v[2];
|
||||
}
|
||||
_FORCE_INLINE_ real_t tdoty(const Vector3 &v) const {
|
||||
return rows[0][1] * v[0] + rows[1][1] * v[1] + rows[2][1] * v[2];
|
||||
}
|
||||
_FORCE_INLINE_ real_t tdotz(const Vector3 &v) const {
|
||||
return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2];
|
||||
}
|
||||
|
||||
bool is_equal_approx(const Basis &p_basis) const;
|
||||
|
||||
bool operator==(const Basis &p_matrix) const;
|
||||
bool operator!=(const Basis &p_matrix) const;
|
||||
|
||||
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const;
|
||||
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const;
|
||||
_FORCE_INLINE_ void operator*=(const Basis &p_matrix);
|
||||
_FORCE_INLINE_ Basis operator*(const Basis &p_matrix) const;
|
||||
_FORCE_INLINE_ void operator+=(const Basis &p_matrix);
|
||||
_FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const;
|
||||
_FORCE_INLINE_ void operator-=(const Basis &p_matrix);
|
||||
_FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const;
|
||||
_FORCE_INLINE_ void operator*=(const real_t p_val);
|
||||
_FORCE_INLINE_ Basis operator*(const real_t p_val) const;
|
||||
|
||||
bool is_orthogonal() const;
|
||||
bool is_diagonal() const;
|
||||
bool is_rotation() const;
|
||||
|
||||
Basis lerp(const Basis &p_to, const real_t &p_weight) const;
|
||||
Basis slerp(const Basis &p_to, const real_t &p_weight) const;
|
||||
void rotate_sh(real_t *p_values);
|
||||
|
||||
operator String() const;
|
||||
|
||||
/* create / set */
|
||||
|
||||
_FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
|
||||
rows[0][0] = xx;
|
||||
rows[0][1] = xy;
|
||||
rows[0][2] = xz;
|
||||
rows[1][0] = yx;
|
||||
rows[1][1] = yy;
|
||||
rows[1][2] = yz;
|
||||
rows[2][0] = zx;
|
||||
rows[2][1] = zy;
|
||||
rows[2][2] = zz;
|
||||
}
|
||||
_FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) {
|
||||
set_column(0, p_x);
|
||||
set_column(1, p_y);
|
||||
set_column(2, p_z);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 get_column(int p_index) const {
|
||||
// Get actual basis axis column (we store transposed as rows for performance).
|
||||
return Vector3(rows[0][p_index], rows[1][p_index], rows[2][p_index]);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void set_column(int p_index, const Vector3 &p_value) {
|
||||
// Set actual basis axis column (we store transposed as rows for performance).
|
||||
rows[0][p_index] = p_value.x;
|
||||
rows[1][p_index] = p_value.y;
|
||||
rows[2][p_index] = p_value.z;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 get_main_diagonal() const {
|
||||
return Vector3(rows[0][0], rows[1][1], rows[2][2]);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void set_zero() {
|
||||
rows[0].zero();
|
||||
rows[1].zero();
|
||||
rows[2].zero();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis transpose_xform(const Basis &m) const {
|
||||
return Basis(
|
||||
rows[0].x * m[0].x + rows[1].x * m[1].x + rows[2].x * m[2].x,
|
||||
rows[0].x * m[0].y + rows[1].x * m[1].y + rows[2].x * m[2].y,
|
||||
rows[0].x * m[0].z + rows[1].x * m[1].z + rows[2].x * m[2].z,
|
||||
rows[0].y * m[0].x + rows[1].y * m[1].x + rows[2].y * m[2].x,
|
||||
rows[0].y * m[0].y + rows[1].y * m[1].y + rows[2].y * m[2].y,
|
||||
rows[0].y * m[0].z + rows[1].y * m[1].z + rows[2].y * m[2].z,
|
||||
rows[0].z * m[0].x + rows[1].z * m[1].x + rows[2].z * m[2].x,
|
||||
rows[0].z * m[0].y + rows[1].z * m[1].y + rows[2].z * m[2].y,
|
||||
rows[0].z * m[0].z + rows[1].z * m[1].z + rows[2].z * m[2].z);
|
||||
}
|
||||
Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
|
||||
set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
|
||||
}
|
||||
|
||||
void orthonormalize();
|
||||
Basis orthonormalized() const;
|
||||
|
||||
void orthogonalize();
|
||||
Basis orthogonalized() const;
|
||||
|
||||
#ifdef MATH_CHECKS
|
||||
bool is_symmetric() const;
|
||||
#endif
|
||||
Basis diagonalize();
|
||||
|
||||
operator Quaternion() const { return get_quaternion(); }
|
||||
|
||||
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
|
||||
|
||||
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
|
||||
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
|
||||
|
||||
Basis(const Vector3 &p_axis, real_t p_angle) { set_axis_angle(p_axis, p_angle); }
|
||||
Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); }
|
||||
static Basis from_scale(const Vector3 &p_scale);
|
||||
|
||||
_FORCE_INLINE_ Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) {
|
||||
set_columns(p_x_axis, p_y_axis, p_z_axis);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis() {}
|
||||
|
||||
private:
|
||||
// Helper method.
|
||||
void _set_diagonal(const Vector3 &p_diag);
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) {
|
||||
set(
|
||||
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
|
||||
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
|
||||
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const {
|
||||
return Basis(
|
||||
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
|
||||
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
|
||||
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void Basis::operator+=(const Basis &p_matrix) {
|
||||
rows[0] += p_matrix.rows[0];
|
||||
rows[1] += p_matrix.rows[1];
|
||||
rows[2] += p_matrix.rows[2];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const {
|
||||
Basis ret(*this);
|
||||
ret += p_matrix;
|
||||
return ret;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void Basis::operator-=(const Basis &p_matrix) {
|
||||
rows[0] -= p_matrix.rows[0];
|
||||
rows[1] -= p_matrix.rows[1];
|
||||
rows[2] -= p_matrix.rows[2];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const {
|
||||
Basis ret(*this);
|
||||
ret -= p_matrix;
|
||||
return ret;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void Basis::operator*=(const real_t p_val) {
|
||||
rows[0] *= p_val;
|
||||
rows[1] *= p_val;
|
||||
rows[2] *= p_val;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const {
|
||||
Basis ret(*this);
|
||||
ret *= p_val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector3 Basis::xform(const Vector3 &p_vector) const {
|
||||
return Vector3(
|
||||
rows[0].dot(p_vector),
|
||||
rows[1].dot(p_vector),
|
||||
rows[2].dot(p_vector));
|
||||
}
|
||||
|
||||
Vector3 Basis::xform_inv(const Vector3 &p_vector) const {
|
||||
return Vector3(
|
||||
(rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z),
|
||||
(rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z),
|
||||
(rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z));
|
||||
}
|
||||
|
||||
real_t Basis::determinant() const {
|
||||
return rows[0][0] * (rows[1][1] * rows[2][2] - rows[2][1] * rows[1][2]) -
|
||||
rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) +
|
||||
rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]);
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_BASIS_HPP
|
||||
@@ -1,142 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* char_string.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_CHAR_STRING_HPP
|
||||
#define GODOT_CHAR_STRING_HPP
|
||||
|
||||
#include <godot_cpp/templates/cowdata.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
class CharStringT;
|
||||
|
||||
template <class T>
|
||||
class CharProxy {
|
||||
template <class TS>
|
||||
friend class CharStringT;
|
||||
|
||||
const int _index;
|
||||
CowData<T> &_cowdata;
|
||||
static inline const T _null = 0;
|
||||
|
||||
_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &p_cowdata) :
|
||||
_index(p_index),
|
||||
_cowdata(p_cowdata) {}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ CharProxy(const CharProxy<T> &p_other) :
|
||||
_index(p_other._index),
|
||||
_cowdata(p_other._cowdata) {}
|
||||
|
||||
_FORCE_INLINE_ operator T() const {
|
||||
if (unlikely(_index == _cowdata.size())) {
|
||||
return _null;
|
||||
}
|
||||
|
||||
return _cowdata.get(_index);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const T *operator&() const {
|
||||
return _cowdata.ptr() + _index;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void operator=(const T &p_other) const {
|
||||
_cowdata.set(_index, p_other);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void operator=(const CharProxy<T> &p_other) const {
|
||||
_cowdata.set(_index, p_other.operator T());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CharStringT {
|
||||
friend class String;
|
||||
|
||||
CowData<T> _cowdata;
|
||||
static inline const T _null = 0;
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
|
||||
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
|
||||
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
|
||||
Error resize(int p_size) { return _cowdata.resize(p_size); }
|
||||
|
||||
_FORCE_INLINE_ T get(int p_index) const { return _cowdata.get(p_index); }
|
||||
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
|
||||
_FORCE_INLINE_ const T &operator[](int p_index) const {
|
||||
if (unlikely(p_index == _cowdata.size())) {
|
||||
return _null;
|
||||
}
|
||||
|
||||
return _cowdata.get(p_index);
|
||||
}
|
||||
_FORCE_INLINE_ CharProxy<T> operator[](int p_index) { return CharProxy<T>(p_index, _cowdata); }
|
||||
|
||||
_FORCE_INLINE_ CharStringT() {}
|
||||
_FORCE_INLINE_ CharStringT(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
|
||||
_FORCE_INLINE_ void operator=(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
|
||||
_FORCE_INLINE_ CharStringT(const T *p_cstr) { copy_from(p_cstr); }
|
||||
|
||||
void operator=(const T *p_cstr);
|
||||
bool operator<(const CharStringT<T> &p_right) const;
|
||||
CharStringT<T> &operator+=(T p_char);
|
||||
int length() const { return size() ? size() - 1 : 0; }
|
||||
const T *get_data() const;
|
||||
operator const T *() const { return get_data(); };
|
||||
|
||||
protected:
|
||||
void copy_from(const T *p_cstr);
|
||||
};
|
||||
|
||||
template <>
|
||||
const char *CharStringT<char>::get_data() const;
|
||||
|
||||
template <>
|
||||
const char16_t *CharStringT<char16_t>::get_data() const;
|
||||
|
||||
template <>
|
||||
const char32_t *CharStringT<char32_t>::get_data() const;
|
||||
|
||||
template <>
|
||||
const wchar_t *CharStringT<wchar_t>::get_data() const;
|
||||
|
||||
typedef CharStringT<char> CharString;
|
||||
typedef CharStringT<char16_t> Char16String;
|
||||
typedef CharStringT<char32_t> Char32String;
|
||||
typedef CharStringT<wchar_t> CharWideString;
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_CHAR_STRING_HPP
|
||||
@@ -1,90 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* char_utils.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_CHAR_UTILS_HPP
|
||||
#define GODOT_CHAR_UTILS_HPP
|
||||
|
||||
static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) {
|
||||
return (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_ascii_lower_case(char32_t c) {
|
||||
return (c >= 'a' && c <= 'z');
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_digit(char32_t c) {
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_hex_digit(char32_t c) {
|
||||
return (is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_binary_digit(char32_t c) {
|
||||
return (c == '0' || c == '1');
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_ascii_char(char32_t c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_ascii_alphanumeric_char(char32_t c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_ascii_identifier_char(char32_t c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_symbol(char32_t c) {
|
||||
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_control(char32_t p_char) {
|
||||
return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009f);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_whitespace(char32_t p_char) {
|
||||
return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
|
||||
return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_punct(char32_t p_char) {
|
||||
return (p_char >= ' ' && p_char <= '/') || (p_char >= ':' && p_char <= '@') || (p_char >= '[' && p_char <= '^') || (p_char == '`') || (p_char >= '{' && p_char <= '~') || (p_char >= 0x2000 && p_char <= 0x206f) || (p_char >= 0x3000 && p_char <= 0x303f);
|
||||
}
|
||||
|
||||
static _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
|
||||
return (p_char == '_');
|
||||
}
|
||||
|
||||
#endif // GODOT_CHAR_UTILS_HPP
|
||||
@@ -1,289 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* color.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_COLOR_HPP
|
||||
#define GODOT_COLOR_HPP
|
||||
|
||||
#include <godot_cpp/core/math.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
struct _NO_DISCARD_ Color {
|
||||
union {
|
||||
struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
};
|
||||
float components[4] = { 0, 0, 0, 1.0 };
|
||||
};
|
||||
|
||||
uint32_t to_rgba32() const;
|
||||
uint32_t to_argb32() const;
|
||||
uint32_t to_abgr32() const;
|
||||
uint64_t to_rgba64() const;
|
||||
uint64_t to_argb64() const;
|
||||
uint64_t to_abgr64() const;
|
||||
String to_html(bool p_alpha = true) const;
|
||||
float get_h() const;
|
||||
float get_s() const;
|
||||
float get_v() const;
|
||||
void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
|
||||
|
||||
_FORCE_INLINE_ float &operator[](int p_idx) {
|
||||
return components[p_idx];
|
||||
}
|
||||
_FORCE_INLINE_ const float &operator[](int p_idx) const {
|
||||
return components[p_idx];
|
||||
}
|
||||
|
||||
bool operator==(const Color &p_color) const {
|
||||
return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a);
|
||||
}
|
||||
bool operator!=(const Color &p_color) const {
|
||||
return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a);
|
||||
}
|
||||
|
||||
Color operator+(const Color &p_color) const;
|
||||
void operator+=(const Color &p_color);
|
||||
|
||||
Color operator-() const;
|
||||
Color operator-(const Color &p_color) const;
|
||||
void operator-=(const Color &p_color);
|
||||
|
||||
Color operator*(const Color &p_color) const;
|
||||
Color operator*(float p_scalar) const;
|
||||
void operator*=(const Color &p_color);
|
||||
void operator*=(float p_scalar);
|
||||
|
||||
Color operator/(const Color &p_color) const;
|
||||
Color operator/(float p_scalar) const;
|
||||
void operator/=(const Color &p_color);
|
||||
void operator/=(float p_scalar);
|
||||
|
||||
bool is_equal_approx(const Color &p_color) const;
|
||||
|
||||
Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const;
|
||||
void invert();
|
||||
Color inverted() const;
|
||||
|
||||
_FORCE_INLINE_ float get_luminance() const {
|
||||
return 0.2126f * r + 0.7152f * g + 0.0722f * b;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const {
|
||||
Color res = *this;
|
||||
|
||||
res.r += (p_weight * (p_to.r - r));
|
||||
res.g += (p_weight * (p_to.g - g));
|
||||
res.b += (p_weight * (p_to.b - b));
|
||||
res.a += (p_weight * (p_to.a - a));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Color darkened(float p_amount) const {
|
||||
Color res = *this;
|
||||
res.r = res.r * (1.0f - p_amount);
|
||||
res.g = res.g * (1.0f - p_amount);
|
||||
res.b = res.b * (1.0f - p_amount);
|
||||
return res;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Color lightened(float p_amount) const {
|
||||
Color res = *this;
|
||||
res.r = res.r + (1.0f - res.r) * p_amount;
|
||||
res.g = res.g + (1.0f - res.g) * p_amount;
|
||||
res.b = res.b + (1.0f - res.b) * p_amount;
|
||||
return res;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t to_rgbe9995() const {
|
||||
const float pow2to9 = 512.0f;
|
||||
const float B = 15.0f;
|
||||
const float N = 9.0f;
|
||||
|
||||
float sharedexp = 65408.000f; // Result of: ((pow2to9 - 1.0f) / pow2to9) * powf(2.0f, 31.0f - 15.0f)
|
||||
|
||||
float cRed = MAX(0.0f, MIN(sharedexp, r));
|
||||
float cGreen = MAX(0.0f, MIN(sharedexp, g));
|
||||
float cBlue = MAX(0.0f, MIN(sharedexp, b));
|
||||
|
||||
float cMax = MAX(cRed, MAX(cGreen, cBlue));
|
||||
|
||||
float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
|
||||
|
||||
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
|
||||
|
||||
float exps = expp + 1.0f;
|
||||
|
||||
if (0.0f <= sMax && sMax < pow2to9) {
|
||||
exps = expp;
|
||||
}
|
||||
|
||||
float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
|
||||
float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
|
||||
float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
|
||||
|
||||
return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Color blend(const Color &p_over) const {
|
||||
Color res;
|
||||
float sa = 1.0f - p_over.a;
|
||||
res.a = a * sa + p_over.a;
|
||||
if (res.a == 0) {
|
||||
return Color(0, 0, 0, 0);
|
||||
} else {
|
||||
res.r = (r * a * sa + p_over.r * p_over.a) / res.a;
|
||||
res.g = (g * a * sa + p_over.g * p_over.a) / res.a;
|
||||
res.b = (b * a * sa + p_over.b * p_over.a) / res.a;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Color srgb_to_linear() const {
|
||||
return Color(
|
||||
r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
|
||||
g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
|
||||
b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
|
||||
a);
|
||||
}
|
||||
_FORCE_INLINE_ Color linear_to_srgb() const {
|
||||
return Color(
|
||||
r < 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math::pow(r, 1.0f / 2.4f) - 0.055f,
|
||||
g < 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math::pow(g, 1.0f / 2.4f) - 0.055f,
|
||||
b < 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * Math::pow(b, 1.0f / 2.4f) - 0.055f, a);
|
||||
}
|
||||
|
||||
static Color hex(uint32_t p_hex);
|
||||
static Color hex64(uint64_t p_hex);
|
||||
static Color html(const String &p_rgba);
|
||||
static bool html_is_valid(const String &p_color);
|
||||
static Color named(const String &p_name);
|
||||
static Color named(const String &p_name, const Color &p_default);
|
||||
static int find_named_color(const String &p_name);
|
||||
static int get_named_color_count();
|
||||
static String get_named_color_name(int p_idx);
|
||||
static Color get_named_color(int p_idx);
|
||||
static Color from_string(const String &p_string, const Color &p_default);
|
||||
static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
|
||||
static Color from_rgbe9995(uint32_t p_rgbe);
|
||||
|
||||
_FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys.
|
||||
operator String() const;
|
||||
|
||||
// For the binder.
|
||||
_FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); }
|
||||
_FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); }
|
||||
_FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0f); }
|
||||
_FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); }
|
||||
_FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0f); }
|
||||
_FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); }
|
||||
_FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); }
|
||||
_FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); }
|
||||
|
||||
_FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); }
|
||||
_FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); }
|
||||
_FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); }
|
||||
|
||||
_FORCE_INLINE_ Color() {}
|
||||
|
||||
/**
|
||||
* RGBA construct parameters.
|
||||
* Alpha is not optional as otherwise we can't bind the RGB version for scripting.
|
||||
*/
|
||||
_FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a) {
|
||||
r = p_r;
|
||||
g = p_g;
|
||||
b = p_b;
|
||||
a = p_a;
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB construct parameters.
|
||||
*/
|
||||
_FORCE_INLINE_ Color(float p_r, float p_g, float p_b) {
|
||||
r = p_r;
|
||||
g = p_g;
|
||||
b = p_b;
|
||||
a = 1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Color from another Color, but with the specified alpha value.
|
||||
*/
|
||||
_FORCE_INLINE_ Color(const Color &p_c, float p_a) {
|
||||
r = p_c.r;
|
||||
g = p_c.g;
|
||||
b = p_c.b;
|
||||
a = p_a;
|
||||
}
|
||||
|
||||
Color(const String &p_code) {
|
||||
if (html_is_valid(p_code)) {
|
||||
*this = html(p_code);
|
||||
} else {
|
||||
*this = named(p_code);
|
||||
}
|
||||
}
|
||||
|
||||
Color(const String &p_code, float p_a) {
|
||||
*this = Color(p_code);
|
||||
a = p_a;
|
||||
}
|
||||
};
|
||||
|
||||
bool Color::operator<(const Color &p_color) const {
|
||||
if (r == p_color.r) {
|
||||
if (g == p_color.g) {
|
||||
if (b == p_color.b) {
|
||||
return (a < p_color.a);
|
||||
} else {
|
||||
return (b < p_color.b);
|
||||
}
|
||||
} else {
|
||||
return g < p_color.g;
|
||||
}
|
||||
} else {
|
||||
return r < p_color.r;
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) {
|
||||
return p_color * p_scalar;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_COLOR_HPP
|
||||
@@ -1,191 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* color_names.inc.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
namespace godot {
|
||||
|
||||
// Names from https://en.wikipedia.org/wiki/X11_color_names
|
||||
// Keep these in sync with the engine (both in core and in C#)
|
||||
|
||||
struct NamedColor {
|
||||
const char *name;
|
||||
Color color;
|
||||
};
|
||||
|
||||
static NamedColor named_colors[] = {
|
||||
{ "ALICE_BLUE", Color::hex(0xF0F8FFFF) },
|
||||
{ "ANTIQUE_WHITE", Color::hex(0xFAEBD7FF) },
|
||||
{ "AQUA", Color::hex(0x00FFFFFF) },
|
||||
{ "AQUAMARINE", Color::hex(0x7FFFD4FF) },
|
||||
{ "AZURE", Color::hex(0xF0FFFFFF) },
|
||||
{ "BEIGE", Color::hex(0xF5F5DCFF) },
|
||||
{ "BISQUE", Color::hex(0xFFE4C4FF) },
|
||||
{ "BLACK", Color::hex(0x000000FF) },
|
||||
{ "BLANCHED_ALMOND", Color::hex(0xFFEBCDFF) },
|
||||
{ "BLUE", Color::hex(0x0000FFFF) },
|
||||
{ "BLUE_VIOLET", Color::hex(0x8A2BE2FF) },
|
||||
{ "BROWN", Color::hex(0xA52A2AFF) },
|
||||
{ "BURLYWOOD", Color::hex(0xDEB887FF) },
|
||||
{ "CADET_BLUE", Color::hex(0x5F9EA0FF) },
|
||||
{ "CHARTREUSE", Color::hex(0x7FFF00FF) },
|
||||
{ "CHOCOLATE", Color::hex(0xD2691EFF) },
|
||||
{ "CORAL", Color::hex(0xFF7F50FF) },
|
||||
{ "CORNFLOWER_BLUE", Color::hex(0x6495EDFF) },
|
||||
{ "CORNSILK", Color::hex(0xFFF8DCFF) },
|
||||
{ "CRIMSON", Color::hex(0xDC143CFF) },
|
||||
{ "CYAN", Color::hex(0x00FFFFFF) },
|
||||
{ "DARK_BLUE", Color::hex(0x00008BFF) },
|
||||
{ "DARK_CYAN", Color::hex(0x008B8BFF) },
|
||||
{ "DARK_GOLDENROD", Color::hex(0xB8860BFF) },
|
||||
{ "DARK_GRAY", Color::hex(0xA9A9A9FF) },
|
||||
{ "DARK_GREEN", Color::hex(0x006400FF) },
|
||||
{ "DARK_KHAKI", Color::hex(0xBDB76BFF) },
|
||||
{ "DARK_MAGENTA", Color::hex(0x8B008BFF) },
|
||||
{ "DARK_OLIVE_GREEN", Color::hex(0x556B2FFF) },
|
||||
{ "DARK_ORANGE", Color::hex(0xFF8C00FF) },
|
||||
{ "DARK_ORCHID", Color::hex(0x9932CCFF) },
|
||||
{ "DARK_RED", Color::hex(0x8B0000FF) },
|
||||
{ "DARK_SALMON", Color::hex(0xE9967AFF) },
|
||||
{ "DARK_SEA_GREEN", Color::hex(0x8FBC8FFF) },
|
||||
{ "DARK_SLATE_BLUE", Color::hex(0x483D8BFF) },
|
||||
{ "DARK_SLATE_GRAY", Color::hex(0x2F4F4FFF) },
|
||||
{ "DARK_TURQUOISE", Color::hex(0x00CED1FF) },
|
||||
{ "DARK_VIOLET", Color::hex(0x9400D3FF) },
|
||||
{ "DEEP_PINK", Color::hex(0xFF1493FF) },
|
||||
{ "DEEP_SKY_BLUE", Color::hex(0x00BFFFFF) },
|
||||
{ "DIM_GRAY", Color::hex(0x696969FF) },
|
||||
{ "DODGER_BLUE", Color::hex(0x1E90FFFF) },
|
||||
{ "FIREBRICK", Color::hex(0xB22222FF) },
|
||||
{ "FLORAL_WHITE", Color::hex(0xFFFAF0FF) },
|
||||
{ "FOREST_GREEN", Color::hex(0x228B22FF) },
|
||||
{ "FUCHSIA", Color::hex(0xFF00FFFF) },
|
||||
{ "GAINSBORO", Color::hex(0xDCDCDCFF) },
|
||||
{ "GHOST_WHITE", Color::hex(0xF8F8FFFF) },
|
||||
{ "GOLD", Color::hex(0xFFD700FF) },
|
||||
{ "GOLDENROD", Color::hex(0xDAA520FF) },
|
||||
{ "GRAY", Color::hex(0xBEBEBEFF) },
|
||||
{ "GREEN", Color::hex(0x00FF00FF) },
|
||||
{ "GREEN_YELLOW", Color::hex(0xADFF2FFF) },
|
||||
{ "HONEYDEW", Color::hex(0xF0FFF0FF) },
|
||||
{ "HOT_PINK", Color::hex(0xFF69B4FF) },
|
||||
{ "INDIAN_RED", Color::hex(0xCD5C5CFF) },
|
||||
{ "INDIGO", Color::hex(0x4B0082FF) },
|
||||
{ "IVORY", Color::hex(0xFFFFF0FF) },
|
||||
{ "KHAKI", Color::hex(0xF0E68CFF) },
|
||||
{ "LAVENDER", Color::hex(0xE6E6FAFF) },
|
||||
{ "LAVENDER_BLUSH", Color::hex(0xFFF0F5FF) },
|
||||
{ "LAWN_GREEN", Color::hex(0x7CFC00FF) },
|
||||
{ "LEMON_CHIFFON", Color::hex(0xFFFACDFF) },
|
||||
{ "LIGHT_BLUE", Color::hex(0xADD8E6FF) },
|
||||
{ "LIGHT_CORAL", Color::hex(0xF08080FF) },
|
||||
{ "LIGHT_CYAN", Color::hex(0xE0FFFFFF) },
|
||||
{ "LIGHT_GOLDENROD", Color::hex(0xFAFAD2FF) },
|
||||
{ "LIGHT_GRAY", Color::hex(0xD3D3D3FF) },
|
||||
{ "LIGHT_GREEN", Color::hex(0x90EE90FF) },
|
||||
{ "LIGHT_PINK", Color::hex(0xFFB6C1FF) },
|
||||
{ "LIGHT_SALMON", Color::hex(0xFFA07AFF) },
|
||||
{ "LIGHT_SEA_GREEN", Color::hex(0x20B2AAFF) },
|
||||
{ "LIGHT_SKY_BLUE", Color::hex(0x87CEFAFF) },
|
||||
{ "LIGHT_SLATE_GRAY", Color::hex(0x778899FF) },
|
||||
{ "LIGHT_STEEL_BLUE", Color::hex(0xB0C4DEFF) },
|
||||
{ "LIGHT_YELLOW", Color::hex(0xFFFFE0FF) },
|
||||
{ "LIME", Color::hex(0x00FF00FF) },
|
||||
{ "LIME_GREEN", Color::hex(0x32CD32FF) },
|
||||
{ "LINEN", Color::hex(0xFAF0E6FF) },
|
||||
{ "MAGENTA", Color::hex(0xFF00FFFF) },
|
||||
{ "MAROON", Color::hex(0xB03060FF) },
|
||||
{ "MEDIUM_AQUAMARINE", Color::hex(0x66CDAAFF) },
|
||||
{ "MEDIUM_BLUE", Color::hex(0x0000CDFF) },
|
||||
{ "MEDIUM_ORCHID", Color::hex(0xBA55D3FF) },
|
||||
{ "MEDIUM_PURPLE", Color::hex(0x9370DBFF) },
|
||||
{ "MEDIUM_SEA_GREEN", Color::hex(0x3CB371FF) },
|
||||
{ "MEDIUM_SLATE_BLUE", Color::hex(0x7B68EEFF) },
|
||||
{ "MEDIUM_SPRING_GREEN", Color::hex(0x00FA9AFF) },
|
||||
{ "MEDIUM_TURQUOISE", Color::hex(0x48D1CCFF) },
|
||||
{ "MEDIUM_VIOLET_RED", Color::hex(0xC71585FF) },
|
||||
{ "MIDNIGHT_BLUE", Color::hex(0x191970FF) },
|
||||
{ "MINT_CREAM", Color::hex(0xF5FFFAFF) },
|
||||
{ "MISTY_ROSE", Color::hex(0xFFE4E1FF) },
|
||||
{ "MOCCASIN", Color::hex(0xFFE4B5FF) },
|
||||
{ "NAVAJO_WHITE", Color::hex(0xFFDEADFF) },
|
||||
{ "NAVY_BLUE", Color::hex(0x000080FF) },
|
||||
{ "OLD_LACE", Color::hex(0xFDF5E6FF) },
|
||||
{ "OLIVE", Color::hex(0x808000FF) },
|
||||
{ "OLIVE_DRAB", Color::hex(0x6B8E23FF) },
|
||||
{ "ORANGE", Color::hex(0xFFA500FF) },
|
||||
{ "ORANGE_RED", Color::hex(0xFF4500FF) },
|
||||
{ "ORCHID", Color::hex(0xDA70D6FF) },
|
||||
{ "PALE_GOLDENROD", Color::hex(0xEEE8AAFF) },
|
||||
{ "PALE_GREEN", Color::hex(0x98FB98FF) },
|
||||
{ "PALE_TURQUOISE", Color::hex(0xAFEEEEFF) },
|
||||
{ "PALE_VIOLET_RED", Color::hex(0xDB7093FF) },
|
||||
{ "PAPAYA_WHIP", Color::hex(0xFFEFD5FF) },
|
||||
{ "PEACH_PUFF", Color::hex(0xFFDAB9FF) },
|
||||
{ "PERU", Color::hex(0xCD853FFF) },
|
||||
{ "PINK", Color::hex(0xFFC0CBFF) },
|
||||
{ "PLUM", Color::hex(0xDDA0DDFF) },
|
||||
{ "POWDER_BLUE", Color::hex(0xB0E0E6FF) },
|
||||
{ "PURPLE", Color::hex(0xA020F0FF) },
|
||||
{ "REBECCA_PURPLE", Color::hex(0x663399FF) },
|
||||
{ "RED", Color::hex(0xFF0000FF) },
|
||||
{ "ROSY_BROWN", Color::hex(0xBC8F8FFF) },
|
||||
{ "ROYAL_BLUE", Color::hex(0x4169E1FF) },
|
||||
{ "SADDLE_BROWN", Color::hex(0x8B4513FF) },
|
||||
{ "SALMON", Color::hex(0xFA8072FF) },
|
||||
{ "SANDY_BROWN", Color::hex(0xF4A460FF) },
|
||||
{ "SEA_GREEN", Color::hex(0x2E8B57FF) },
|
||||
{ "SEASHELL", Color::hex(0xFFF5EEFF) },
|
||||
{ "SIENNA", Color::hex(0xA0522DFF) },
|
||||
{ "SILVER", Color::hex(0xC0C0C0FF) },
|
||||
{ "SKY_BLUE", Color::hex(0x87CEEBFF) },
|
||||
{ "SLATE_BLUE", Color::hex(0x6A5ACDFF) },
|
||||
{ "SLATE_GRAY", Color::hex(0x708090FF) },
|
||||
{ "SNOW", Color::hex(0xFFFAFAFF) },
|
||||
{ "SPRING_GREEN", Color::hex(0x00FF7FFF) },
|
||||
{ "STEEL_BLUE", Color::hex(0x4682B4FF) },
|
||||
{ "TAN", Color::hex(0xD2B48CFF) },
|
||||
{ "TEAL", Color::hex(0x008080FF) },
|
||||
{ "THISTLE", Color::hex(0xD8BFD8FF) },
|
||||
{ "TOMATO", Color::hex(0xFF6347FF) },
|
||||
{ "TRANSPARENT", Color::hex(0xFFFFFF00) },
|
||||
{ "TURQUOISE", Color::hex(0x40E0D0FF) },
|
||||
{ "VIOLET", Color::hex(0xEE82EEFF) },
|
||||
{ "WEB_GRAY", Color::hex(0x808080FF) },
|
||||
{ "WEB_GREEN", Color::hex(0x008000FF) },
|
||||
{ "WEB_MAROON", Color::hex(0x800000FF) },
|
||||
{ "WEB_PURPLE", Color::hex(0x800080FF) },
|
||||
{ "WHEAT", Color::hex(0xF5DEB3FF) },
|
||||
{ "WHITE", Color::hex(0xFFFFFFFF) },
|
||||
{ "WHITE_SMOKE", Color::hex(0xF5F5F5FF) },
|
||||
{ "YELLOW", Color::hex(0xFFFF00FF) },
|
||||
{ "YELLOW_GREEN", Color::hex(0x9ACD32FF) },
|
||||
{ nullptr, Color() },
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
@@ -1,140 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* plane.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_PLANE_HPP
|
||||
#define GODOT_PLANE_HPP
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Variant;
|
||||
|
||||
struct _NO_DISCARD_ Plane {
|
||||
Vector3 normal;
|
||||
real_t d = 0;
|
||||
|
||||
void set_normal(const Vector3 &p_normal);
|
||||
_FORCE_INLINE_ Vector3 get_normal() const { return normal; }
|
||||
|
||||
void normalize();
|
||||
Plane normalized() const;
|
||||
|
||||
/* Plane-Point operations */
|
||||
|
||||
_FORCE_INLINE_ Vector3 center() const { return normal * d; }
|
||||
Vector3 get_any_perpendicular_normal() const;
|
||||
|
||||
_FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
|
||||
_FORCE_INLINE_ real_t distance_to(const Vector3 &p_point) const;
|
||||
_FORCE_INLINE_ bool has_point(const Vector3 &p_point, real_t p_tolerance = CMP_EPSILON) const;
|
||||
|
||||
/* intersections */
|
||||
|
||||
bool intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result = nullptr) const;
|
||||
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const;
|
||||
bool intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 *p_intersection) const;
|
||||
|
||||
// For Variant bindings.
|
||||
Variant intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) const;
|
||||
Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
|
||||
Variant intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const;
|
||||
|
||||
_FORCE_INLINE_ Vector3 project(const Vector3 &p_point) const {
|
||||
return p_point - normal * distance_to(p_point);
|
||||
}
|
||||
|
||||
/* misc */
|
||||
|
||||
Plane operator-() const { return Plane(-normal, -d); }
|
||||
bool is_equal_approx(const Plane &p_plane) const;
|
||||
bool is_equal_approx_any_side(const Plane &p_plane) const;
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
|
||||
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
|
||||
operator String() const;
|
||||
|
||||
_FORCE_INLINE_ Plane() {}
|
||||
_FORCE_INLINE_ Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
|
||||
normal(p_a, p_b, p_c),
|
||||
d(p_d) {}
|
||||
|
||||
_FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d = 0.0);
|
||||
_FORCE_INLINE_ Plane(const Vector3 &p_normal, const Vector3 &p_point);
|
||||
_FORCE_INLINE_ Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE);
|
||||
};
|
||||
|
||||
bool Plane::is_point_over(const Vector3 &p_point) const {
|
||||
return (normal.dot(p_point) > d);
|
||||
}
|
||||
|
||||
real_t Plane::distance_to(const Vector3 &p_point) const {
|
||||
return (normal.dot(p_point) - d);
|
||||
}
|
||||
|
||||
bool Plane::has_point(const Vector3 &p_point, real_t p_tolerance) const {
|
||||
real_t dist = normal.dot(p_point) - d;
|
||||
dist = Math::abs(dist);
|
||||
return (dist <= p_tolerance);
|
||||
}
|
||||
|
||||
Plane::Plane(const Vector3 &p_normal, real_t p_d) :
|
||||
normal(p_normal),
|
||||
d(p_d) {
|
||||
}
|
||||
|
||||
Plane::Plane(const Vector3 &p_normal, const Vector3 &p_point) :
|
||||
normal(p_normal),
|
||||
d(p_normal.dot(p_point)) {
|
||||
}
|
||||
|
||||
Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir) {
|
||||
if (p_dir == CLOCKWISE) {
|
||||
normal = (p_point1 - p_point3).cross(p_point1 - p_point2);
|
||||
} else {
|
||||
normal = (p_point1 - p_point2).cross(p_point1 - p_point3);
|
||||
}
|
||||
|
||||
normal.normalize();
|
||||
d = normal.dot(p_point1);
|
||||
}
|
||||
|
||||
bool Plane::operator==(const Plane &p_plane) const {
|
||||
return normal == p_plane.normal && d == p_plane.d;
|
||||
}
|
||||
|
||||
bool Plane::operator!=(const Plane &p_plane) const {
|
||||
return normal != p_plane.normal || d != p_plane.d;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_PLANE_HPP
|
||||
@@ -1,171 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* projection.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_PROJECTION_HPP
|
||||
#define GODOT_PROJECTION_HPP
|
||||
|
||||
#include <godot_cpp/core/math.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
#include <godot_cpp/variant/vector4.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class Array;
|
||||
struct AABB;
|
||||
struct Plane;
|
||||
struct Rect2;
|
||||
struct Transform3D;
|
||||
struct Vector2;
|
||||
|
||||
struct _NO_DISCARD_ Projection {
|
||||
enum Planes {
|
||||
PLANE_NEAR,
|
||||
PLANE_FAR,
|
||||
PLANE_LEFT,
|
||||
PLANE_TOP,
|
||||
PLANE_RIGHT,
|
||||
PLANE_BOTTOM
|
||||
};
|
||||
|
||||
Vector4 columns[4];
|
||||
|
||||
_FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const {
|
||||
DEV_ASSERT((unsigned int)p_axis < 4);
|
||||
return columns[p_axis];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector4 &operator[](const int p_axis) {
|
||||
DEV_ASSERT((unsigned int)p_axis < 4);
|
||||
return columns[p_axis];
|
||||
}
|
||||
|
||||
float determinant() const;
|
||||
void set_identity();
|
||||
void set_zero();
|
||||
void set_light_bias();
|
||||
void set_depth_correction(bool p_flip_y = true);
|
||||
|
||||
void set_light_atlas_rect(const Rect2 &p_rect);
|
||||
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
|
||||
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);
|
||||
void set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far);
|
||||
void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar);
|
||||
void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
|
||||
void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
|
||||
void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
|
||||
void adjust_perspective_znear(real_t p_new_znear);
|
||||
|
||||
static Projection create_depth_correction(bool p_flip_y);
|
||||
static Projection create_light_atlas_rect(const Rect2 &p_rect);
|
||||
static Projection create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
|
||||
static Projection create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);
|
||||
static Projection create_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far);
|
||||
static Projection create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar);
|
||||
static Projection create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
|
||||
static Projection create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
|
||||
static Projection create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
|
||||
static Projection create_fit_aabb(const AABB &p_aabb);
|
||||
Projection perspective_znear_adjusted(real_t p_new_znear) const;
|
||||
Plane get_projection_plane(Planes p_plane) const;
|
||||
Projection flipped_y() const;
|
||||
Projection jitter_offseted(const Vector2 &p_offset) const;
|
||||
|
||||
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
|
||||
return Math::rad_to_deg(Math::atan(p_aspect * Math::tan(Math::deg_to_rad(p_fovx) * 0.5)) * 2.0);
|
||||
}
|
||||
|
||||
real_t get_z_far() const;
|
||||
real_t get_z_near() const;
|
||||
real_t get_aspect() const;
|
||||
real_t get_fov() const;
|
||||
bool is_orthogonal() const;
|
||||
|
||||
Array get_projection_planes(const Transform3D &p_transform) const;
|
||||
|
||||
bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const;
|
||||
Vector2 get_viewport_half_extents() const;
|
||||
Vector2 get_far_plane_half_extents() const;
|
||||
|
||||
void invert();
|
||||
Projection inverse() const;
|
||||
|
||||
Projection operator*(const Projection &p_matrix) const;
|
||||
|
||||
Plane xform4(const Plane &p_vec4) const;
|
||||
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const;
|
||||
|
||||
Vector4 xform(const Vector4 &p_vec4) const;
|
||||
Vector4 xform_inv(const Vector4 &p_vec4) const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
void scale_translate_to_fit(const AABB &p_aabb);
|
||||
void add_jitter_offset(const Vector2 &p_offset);
|
||||
void make_scale(const Vector3 &p_scale);
|
||||
int get_pixels_per_meter(int p_for_pixel_width) const;
|
||||
operator Transform3D() const;
|
||||
|
||||
void flip_y();
|
||||
|
||||
bool operator==(const Projection &p_cam) const {
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
for (uint32_t j = 0; j < 4; j++) {
|
||||
if (columns[i][j] != p_cam.columns[i][j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const Projection &p_cam) const {
|
||||
return !(*this == p_cam);
|
||||
}
|
||||
|
||||
float get_lod_multiplier() const;
|
||||
|
||||
Projection();
|
||||
Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w);
|
||||
Projection(const Transform3D &p_transform);
|
||||
~Projection();
|
||||
};
|
||||
|
||||
Vector3 Projection::xform(const Vector3 &p_vec3) const {
|
||||
Vector3 ret;
|
||||
ret.x = columns[0][0] * p_vec3.x + columns[1][0] * p_vec3.y + columns[2][0] * p_vec3.z + columns[3][0];
|
||||
ret.y = columns[0][1] * p_vec3.x + columns[1][1] * p_vec3.y + columns[2][1] * p_vec3.z + columns[3][1];
|
||||
ret.z = columns[0][2] * p_vec3.x + columns[1][2] * p_vec3.y + columns[2][2] * p_vec3.z + columns[3][2];
|
||||
real_t w = columns[0][3] * p_vec3.x + columns[1][3] * p_vec3.y + columns[2][3] * p_vec3.z + columns[3][3];
|
||||
return ret / w;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_PROJECTION_HPP
|
||||
@@ -1,237 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* quaternion.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_QUATERNION_HPP
|
||||
#define GODOT_QUATERNION_HPP
|
||||
|
||||
#include <godot_cpp/core/math.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct _NO_DISCARD_ Quaternion {
|
||||
union {
|
||||
struct {
|
||||
real_t x;
|
||||
real_t y;
|
||||
real_t z;
|
||||
real_t w;
|
||||
};
|
||||
real_t components[4] = { 0, 0, 0, 1.0 };
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ real_t &operator[](int idx) {
|
||||
return components[idx];
|
||||
}
|
||||
_FORCE_INLINE_ const real_t &operator[](int idx) const {
|
||||
return components[idx];
|
||||
}
|
||||
_FORCE_INLINE_ real_t length_squared() const;
|
||||
bool is_equal_approx(const Quaternion &p_quaternion) const;
|
||||
real_t length() const;
|
||||
void normalize();
|
||||
Quaternion normalized() const;
|
||||
bool is_normalized() const;
|
||||
Quaternion inverse() const;
|
||||
Quaternion log() const;
|
||||
Quaternion exp() const;
|
||||
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
|
||||
real_t angle_to(const Quaternion &p_to) const;
|
||||
|
||||
Vector3 get_euler_xyz() const;
|
||||
Vector3 get_euler_yxz() const;
|
||||
Vector3 get_euler() const { return get_euler_yxz(); }
|
||||
|
||||
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
|
||||
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
|
||||
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
|
||||
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
|
||||
|
||||
Vector3 get_axis() const;
|
||||
real_t get_angle() const;
|
||||
|
||||
_FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
|
||||
r_angle = 2 * Math::acos(w);
|
||||
real_t r = ((real_t)1) / Math::sqrt(1 - w * w);
|
||||
r_axis.x = x * r;
|
||||
r_axis.y = y * r;
|
||||
r_axis.z = z * r;
|
||||
}
|
||||
|
||||
void operator*=(const Quaternion &p_q);
|
||||
Quaternion operator*(const Quaternion &p_q) const;
|
||||
|
||||
_FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized.");
|
||||
#endif
|
||||
Vector3 u(x, y, z);
|
||||
Vector3 uv = u.cross(v);
|
||||
return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
|
||||
return inverse().xform(v);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void operator+=(const Quaternion &p_q);
|
||||
_FORCE_INLINE_ void operator-=(const Quaternion &p_q);
|
||||
_FORCE_INLINE_ void operator*=(const real_t &s);
|
||||
_FORCE_INLINE_ void operator/=(const real_t &s);
|
||||
_FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const;
|
||||
_FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const;
|
||||
_FORCE_INLINE_ Quaternion operator-() const;
|
||||
_FORCE_INLINE_ Quaternion operator*(const real_t &s) const;
|
||||
_FORCE_INLINE_ Quaternion operator/(const real_t &s) const;
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const;
|
||||
_FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
_FORCE_INLINE_ Quaternion() {}
|
||||
|
||||
_FORCE_INLINE_ Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) :
|
||||
x(p_x),
|
||||
y(p_y),
|
||||
z(p_z),
|
||||
w(p_w) {
|
||||
}
|
||||
|
||||
Quaternion(const Vector3 &p_axis, real_t p_angle);
|
||||
|
||||
Quaternion(const Vector3 &p_euler);
|
||||
|
||||
Quaternion(const Quaternion &p_q) :
|
||||
x(p_q.x),
|
||||
y(p_q.y),
|
||||
z(p_q.z),
|
||||
w(p_q.w) {
|
||||
}
|
||||
|
||||
void operator=(const Quaternion &p_q) {
|
||||
x = p_q.x;
|
||||
y = p_q.y;
|
||||
z = p_q.z;
|
||||
w = p_q.w;
|
||||
}
|
||||
|
||||
Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
|
||||
Vector3 c = v0.cross(v1);
|
||||
real_t d = v0.dot(v1);
|
||||
|
||||
if (d < -1.0f + (real_t)CMP_EPSILON) {
|
||||
x = 0;
|
||||
y = 1;
|
||||
z = 0;
|
||||
w = 0;
|
||||
} else {
|
||||
real_t s = Math::sqrt((1.0f + d) * 2.0f);
|
||||
real_t rs = 1.0f / s;
|
||||
|
||||
x = c.x * rs;
|
||||
y = c.y * rs;
|
||||
z = c.z * rs;
|
||||
w = s * 0.5f;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
real_t Quaternion::dot(const Quaternion &p_q) const {
|
||||
return x * p_q.x + y * p_q.y + z * p_q.z + w * p_q.w;
|
||||
}
|
||||
|
||||
real_t Quaternion::length_squared() const {
|
||||
return dot(*this);
|
||||
}
|
||||
|
||||
void Quaternion::operator+=(const Quaternion &p_q) {
|
||||
x += p_q.x;
|
||||
y += p_q.y;
|
||||
z += p_q.z;
|
||||
w += p_q.w;
|
||||
}
|
||||
|
||||
void Quaternion::operator-=(const Quaternion &p_q) {
|
||||
x -= p_q.x;
|
||||
y -= p_q.y;
|
||||
z -= p_q.z;
|
||||
w -= p_q.w;
|
||||
}
|
||||
|
||||
void Quaternion::operator*=(const real_t &s) {
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
w *= s;
|
||||
}
|
||||
|
||||
void Quaternion::operator/=(const real_t &s) {
|
||||
*this *= 1.0f / s;
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator+(const Quaternion &q2) const {
|
||||
const Quaternion &q1 = *this;
|
||||
return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator-(const Quaternion &q2) const {
|
||||
const Quaternion &q1 = *this;
|
||||
return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator-() const {
|
||||
const Quaternion &q2 = *this;
|
||||
return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator*(const real_t &s) const {
|
||||
return Quaternion(x * s, y * s, z * s, w * s);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator/(const real_t &s) const {
|
||||
return *this * (1.0f / s);
|
||||
}
|
||||
|
||||
bool Quaternion::operator==(const Quaternion &p_quaternion) const {
|
||||
return x == p_quaternion.x && y == p_quaternion.y && z == p_quaternion.z && w == p_quaternion.w;
|
||||
}
|
||||
|
||||
bool Quaternion::operator!=(const Quaternion &p_quaternion) const {
|
||||
return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) {
|
||||
return p_quaternion * p_real;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_QUATERNION_HPP
|
||||
@@ -1,376 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* rect2.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_RECT2_HPP
|
||||
#define GODOT_RECT2_HPP
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/variant/vector2.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
struct Rect2i;
|
||||
struct Transform2D;
|
||||
|
||||
struct _NO_DISCARD_ Rect2 {
|
||||
Point2 position;
|
||||
Size2 size;
|
||||
|
||||
const Vector2 &get_position() const { return position; }
|
||||
void set_position(const Vector2 &p_pos) { position = p_pos; }
|
||||
const Vector2 &get_size() const { return size; }
|
||||
void set_size(const Vector2 &p_size) { size = p_size; }
|
||||
|
||||
real_t get_area() const { return size.width * size.height; }
|
||||
|
||||
_FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5f); }
|
||||
|
||||
inline bool intersects(const Rect2 &p_rect, const bool p_include_borders = false) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
|
||||
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (p_include_borders) {
|
||||
if (position.x > (p_rect.position.x + p_rect.size.width)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.x + size.width) < p_rect.position.x) {
|
||||
return false;
|
||||
}
|
||||
if (position.y > (p_rect.position.y + p_rect.size.height)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.y + size.height) < p_rect.position.y) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (position.x >= (p_rect.position.x + p_rect.size.width)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.x + size.width) <= p_rect.position.x) {
|
||||
return false;
|
||||
}
|
||||
if (position.y >= (p_rect.position.y + p_rect.size.height)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.y + size.height) <= p_rect.position.y) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline real_t distance_to(const Vector2 &p_point) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0)) {
|
||||
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
|
||||
}
|
||||
#endif
|
||||
real_t dist = 0.0;
|
||||
bool inside = true;
|
||||
|
||||
if (p_point.x < position.x) {
|
||||
real_t d = position.x - p_point.x;
|
||||
dist = d;
|
||||
inside = false;
|
||||
}
|
||||
if (p_point.y < position.y) {
|
||||
real_t d = position.y - p_point.y;
|
||||
dist = inside ? d : Math::min(dist, d);
|
||||
inside = false;
|
||||
}
|
||||
if (p_point.x >= (position.x + size.x)) {
|
||||
real_t d = p_point.x - (position.x + size.x);
|
||||
dist = inside ? d : Math::min(dist, d);
|
||||
inside = false;
|
||||
}
|
||||
if (p_point.y >= (position.y + size.y)) {
|
||||
real_t d = p_point.y - (position.y + size.y);
|
||||
dist = inside ? d : Math::min(dist, d);
|
||||
inside = false;
|
||||
}
|
||||
|
||||
if (inside) {
|
||||
return 0;
|
||||
} else {
|
||||
return dist;
|
||||
}
|
||||
}
|
||||
|
||||
bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const;
|
||||
|
||||
bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = nullptr, Point2 *r_normal = nullptr) const;
|
||||
|
||||
inline bool encloses(const Rect2 &p_rect) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
|
||||
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
|
||||
}
|
||||
#endif
|
||||
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
|
||||
((p_rect.position.x + p_rect.size.x) <= (position.x + size.x)) &&
|
||||
((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool has_area() const {
|
||||
return size.x > 0.0f && size.y > 0.0f;
|
||||
}
|
||||
|
||||
// Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
|
||||
inline Rect2 intersection(const Rect2 &p_rect) const {
|
||||
Rect2 new_rect = p_rect;
|
||||
|
||||
if (!intersects(new_rect)) {
|
||||
return Rect2();
|
||||
}
|
||||
|
||||
new_rect.position.x = Math::max(p_rect.position.x, position.x);
|
||||
new_rect.position.y = Math::max(p_rect.position.y, position.y);
|
||||
|
||||
Point2 p_rect_end = p_rect.position + p_rect.size;
|
||||
Point2 end = position + size;
|
||||
|
||||
new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
|
||||
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
|
||||
|
||||
return new_rect;
|
||||
}
|
||||
|
||||
inline Rect2 merge(const Rect2 &p_rect) const { ///< return a merged rect
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
|
||||
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
|
||||
}
|
||||
#endif
|
||||
Rect2 new_rect;
|
||||
|
||||
new_rect.position.x = Math::min(p_rect.position.x, position.x);
|
||||
new_rect.position.y = Math::min(p_rect.position.y, position.y);
|
||||
|
||||
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
|
||||
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
|
||||
|
||||
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
|
||||
|
||||
return new_rect;
|
||||
}
|
||||
|
||||
inline bool has_point(const Point2 &p_point) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0)) {
|
||||
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (p_point.x < position.x) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.y < position.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_point.x >= (position.x + size.x)) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.y >= (position.y + size.y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_equal_approx(const Rect2 &p_rect) const;
|
||||
|
||||
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
|
||||
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
|
||||
|
||||
inline Rect2 grow(real_t p_amount) const {
|
||||
Rect2 g = *this;
|
||||
g.grow_by(p_amount);
|
||||
return g;
|
||||
}
|
||||
|
||||
inline void grow_by(real_t p_amount) {
|
||||
position.x -= p_amount;
|
||||
position.y -= p_amount;
|
||||
size.width += p_amount * 2;
|
||||
size.height += p_amount * 2;
|
||||
}
|
||||
|
||||
inline Rect2 grow_side(Side p_side, real_t p_amount) const {
|
||||
Rect2 g = *this;
|
||||
g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0,
|
||||
(SIDE_TOP == p_side) ? p_amount : 0,
|
||||
(SIDE_RIGHT == p_side) ? p_amount : 0,
|
||||
(SIDE_BOTTOM == p_side) ? p_amount : 0);
|
||||
return g;
|
||||
}
|
||||
|
||||
inline Rect2 grow_side_bind(uint32_t p_side, real_t p_amount) const {
|
||||
return grow_side(Side(p_side), p_amount);
|
||||
}
|
||||
|
||||
inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const {
|
||||
Rect2 g = *this;
|
||||
g.position.x -= p_left;
|
||||
g.position.y -= p_top;
|
||||
g.size.width += p_left + p_right;
|
||||
g.size.height += p_top + p_bottom;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Rect2 expand(const Vector2 &p_vector) const {
|
||||
Rect2 r = *this;
|
||||
r.expand_to(p_vector);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void expand_to(const Vector2 &p_vector) { // In place function for speed.
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0)) {
|
||||
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
|
||||
}
|
||||
#endif
|
||||
Vector2 begin = position;
|
||||
Vector2 end = position + size;
|
||||
|
||||
if (p_vector.x < begin.x) {
|
||||
begin.x = p_vector.x;
|
||||
}
|
||||
if (p_vector.y < begin.y) {
|
||||
begin.y = p_vector.y;
|
||||
}
|
||||
|
||||
if (p_vector.x > end.x) {
|
||||
end.x = p_vector.x;
|
||||
}
|
||||
if (p_vector.y > end.y) {
|
||||
end.y = p_vector.y;
|
||||
}
|
||||
|
||||
position = begin;
|
||||
size = end - begin;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Rect2 abs() const {
|
||||
return Rect2(Point2(position.x + Math::min(size.x, (real_t)0), position.y + Math::min(size.y, (real_t)0)), size.abs());
|
||||
}
|
||||
|
||||
Vector2 get_support(const Vector2 &p_normal) const {
|
||||
Vector2 half_extents = size * 0.5f;
|
||||
Vector2 ofs = position + half_extents;
|
||||
return Vector2(
|
||||
(p_normal.x > 0) ? -half_extents.x : half_extents.x,
|
||||
(p_normal.y > 0) ? -half_extents.y : half_extents.y) +
|
||||
ofs;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
|
||||
Vector2 center = get_center();
|
||||
int side_plus = 0;
|
||||
int side_minus = 0;
|
||||
Vector2 end = position + size;
|
||||
|
||||
int i_f = p_point_count - 1;
|
||||
for (int i = 0; i < p_point_count; i++) {
|
||||
const Vector2 &a = p_points[i_f];
|
||||
const Vector2 &b = p_points[i];
|
||||
i_f = i;
|
||||
|
||||
Vector2 r = (b - a);
|
||||
float l = r.length();
|
||||
if (l == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check inside.
|
||||
Vector2 tg = r.orthogonal();
|
||||
float s = tg.dot(center) - tg.dot(a);
|
||||
if (s < 0.0f) {
|
||||
side_plus++;
|
||||
} else {
|
||||
side_minus++;
|
||||
}
|
||||
|
||||
// Check ray box.
|
||||
r /= l;
|
||||
Vector2 ir(1.0f / r.x, 1.0f / r.y);
|
||||
|
||||
// lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
|
||||
// r.org is origin of ray
|
||||
Vector2 t13 = (position - a) * ir;
|
||||
Vector2 t24 = (end - a) * ir;
|
||||
|
||||
float tmin = Math::max(Math::min(t13.x, t24.x), Math::min(t13.y, t24.y));
|
||||
float tmax = Math::min(Math::max(t13.x, t24.x), Math::max(t13.y, t24.y));
|
||||
|
||||
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
|
||||
if (tmax < 0 || tmin > tmax || tmin >= l) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (side_plus * side_minus == 0) {
|
||||
return true; // All inside.
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void set_end(const Vector2 &p_end) {
|
||||
size = p_end - position;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector2 get_end() const {
|
||||
return position + size;
|
||||
}
|
||||
|
||||
operator String() const;
|
||||
operator Rect2i() const;
|
||||
|
||||
Rect2() {}
|
||||
Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) :
|
||||
position(Point2(p_x, p_y)),
|
||||
size(Size2(p_width, p_height)) {
|
||||
}
|
||||
Rect2(const Point2 &p_pos, const Size2 &p_size) :
|
||||
position(p_pos),
|
||||
size(p_size) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_RECT2_HPP
|
||||
@@ -1,249 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* rect2i.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_RECT2I_HPP
|
||||
#define GODOT_RECT2I_HPP
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/variant/vector2i.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
struct Rect2;
|
||||
|
||||
struct _NO_DISCARD_ Rect2i {
|
||||
Point2i position;
|
||||
Size2i size;
|
||||
|
||||
const Point2i &get_position() const { return position; }
|
||||
void set_position(const Point2i &p_position) { position = p_position; }
|
||||
const Size2i &get_size() const { return size; }
|
||||
void set_size(const Size2i &p_size) { size = p_size; }
|
||||
|
||||
int get_area() const { return size.width * size.height; }
|
||||
|
||||
_FORCE_INLINE_ Vector2i get_center() const { return position + (size / 2); }
|
||||
|
||||
inline bool intersects(const Rect2i &p_rect) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
|
||||
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (position.x >= (p_rect.position.x + p_rect.size.width)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.x + size.width) <= p_rect.position.x) {
|
||||
return false;
|
||||
}
|
||||
if (position.y >= (p_rect.position.y + p_rect.size.height)) {
|
||||
return false;
|
||||
}
|
||||
if ((position.y + size.height) <= p_rect.position.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool encloses(const Rect2i &p_rect) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
|
||||
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
|
||||
}
|
||||
#endif
|
||||
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
|
||||
((p_rect.position.x + p_rect.size.x) <= (position.x + size.x)) &&
|
||||
((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool has_area() const {
|
||||
return size.x > 0 && size.y > 0;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
if (!intersects(new_rect)) {
|
||||
return Rect2i();
|
||||
}
|
||||
|
||||
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.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
|
||||
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
|
||||
|
||||
return new_rect;
|
||||
}
|
||||
|
||||
inline Rect2i merge(const Rect2i &p_rect) const { ///< return a merged rect
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
|
||||
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
|
||||
}
|
||||
#endif
|
||||
Rect2i new_rect;
|
||||
|
||||
new_rect.position.x = Math::min(p_rect.position.x, position.x);
|
||||
new_rect.position.y = Math::min(p_rect.position.y, position.y);
|
||||
|
||||
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
|
||||
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
|
||||
|
||||
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
|
||||
|
||||
return new_rect;
|
||||
}
|
||||
bool has_point(const Point2i &p_point) const {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0)) {
|
||||
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
|
||||
}
|
||||
#endif
|
||||
if (p_point.x < position.x) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.y < position.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_point.x >= (position.x + size.x)) {
|
||||
return false;
|
||||
}
|
||||
if (p_point.y >= (position.y + size.y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; }
|
||||
bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; }
|
||||
|
||||
Rect2i grow(int p_amount) const {
|
||||
Rect2i g = *this;
|
||||
g.position.x -= p_amount;
|
||||
g.position.y -= p_amount;
|
||||
g.size.width += p_amount * 2;
|
||||
g.size.height += p_amount * 2;
|
||||
return g;
|
||||
}
|
||||
|
||||
inline Rect2i grow_side(Side p_side, int p_amount) const {
|
||||
Rect2i g = *this;
|
||||
g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0,
|
||||
(SIDE_TOP == p_side) ? p_amount : 0,
|
||||
(SIDE_RIGHT == p_side) ? p_amount : 0,
|
||||
(SIDE_BOTTOM == p_side) ? p_amount : 0);
|
||||
return g;
|
||||
}
|
||||
|
||||
inline Rect2i grow_side_bind(uint32_t p_side, int p_amount) const {
|
||||
return grow_side(Side(p_side), p_amount);
|
||||
}
|
||||
|
||||
inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const {
|
||||
Rect2i g = *this;
|
||||
g.position.x -= p_left;
|
||||
g.position.y -= p_top;
|
||||
g.size.width += p_left + p_right;
|
||||
g.size.height += p_top + p_bottom;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Rect2i expand(const Vector2i &p_vector) const {
|
||||
Rect2i r = *this;
|
||||
r.expand_to(p_vector);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void expand_to(const Point2i &p_vector) {
|
||||
#ifdef MATH_CHECKS
|
||||
if (unlikely(size.x < 0 || size.y < 0)) {
|
||||
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
|
||||
}
|
||||
#endif
|
||||
Point2i begin = position;
|
||||
Point2i end = position + size;
|
||||
|
||||
if (p_vector.x < begin.x) {
|
||||
begin.x = p_vector.x;
|
||||
}
|
||||
if (p_vector.y < begin.y) {
|
||||
begin.y = p_vector.y;
|
||||
}
|
||||
|
||||
if (p_vector.x > end.x) {
|
||||
end.x = p_vector.x;
|
||||
}
|
||||
if (p_vector.y > end.y) {
|
||||
end.y = p_vector.y;
|
||||
}
|
||||
|
||||
position = begin;
|
||||
size = end - begin;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Rect2i abs() const {
|
||||
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) {
|
||||
size = p_end - position;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector2i get_end() const {
|
||||
return position + size;
|
||||
}
|
||||
|
||||
operator String() const;
|
||||
operator Rect2() const;
|
||||
|
||||
Rect2i() {}
|
||||
Rect2i(int p_x, int p_y, int p_width, int p_height) :
|
||||
position(Point2i(p_x, p_y)),
|
||||
size(Size2i(p_width, p_height)) {
|
||||
}
|
||||
Rect2i(const Point2i &p_pos, const Size2i &p_size) :
|
||||
position(p_pos),
|
||||
size(p_size) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_RECT2I_HPP
|
||||
@@ -1,250 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* transform2d.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_TRANSFORM2D_HPP
|
||||
#define GODOT_TRANSFORM2D_HPP
|
||||
|
||||
#include <godot_cpp/variant/packed_vector2_array.hpp>
|
||||
#include <godot_cpp/variant/rect2.hpp>
|
||||
#include <godot_cpp/variant/vector2.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
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 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 #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 &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]; }
|
||||
|
||||
void invert();
|
||||
Transform2D inverse() const;
|
||||
|
||||
void affine_invert();
|
||||
Transform2D affine_inverse() const;
|
||||
|
||||
void set_rotation(const real_t p_rot);
|
||||
real_t get_rotation() const;
|
||||
real_t get_skew() const;
|
||||
void set_skew(const real_t p_angle);
|
||||
_FORCE_INLINE_ void set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale);
|
||||
_FORCE_INLINE_ void set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew);
|
||||
void rotate(const real_t p_angle);
|
||||
|
||||
void scale(const Size2 &p_scale);
|
||||
void scale_basis(const Size2 &p_scale);
|
||||
void translate_local(const real_t p_tx, const real_t p_ty);
|
||||
void translate_local(const Vector2 &p_translation);
|
||||
|
||||
real_t basis_determinant() const;
|
||||
|
||||
Size2 get_scale() const;
|
||||
void set_scale(const Size2 &p_scale);
|
||||
|
||||
_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
|
||||
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
|
||||
|
||||
Transform2D basis_scaled(const Size2 &p_scale) const;
|
||||
Transform2D scaled(const Size2 &p_scale) const;
|
||||
Transform2D scaled_local(const Size2 &p_scale) const;
|
||||
Transform2D translated(const Vector2 &p_offset) const;
|
||||
Transform2D translated_local(const Vector2 &p_offset) const;
|
||||
Transform2D rotated(const real_t p_angle) const;
|
||||
Transform2D rotated_local(const real_t p_angle) const;
|
||||
|
||||
Transform2D untranslated() const;
|
||||
|
||||
void orthonormalize();
|
||||
Transform2D orthonormalized() const;
|
||||
bool is_equal_approx(const Transform2D &p_transform) const;
|
||||
|
||||
Transform2D looking_at(const Vector2 &p_target) const;
|
||||
|
||||
bool operator==(const Transform2D &p_transform) const;
|
||||
bool operator!=(const Transform2D &p_transform) const;
|
||||
|
||||
void operator*=(const Transform2D &p_transform);
|
||||
Transform2D operator*(const Transform2D &p_transform) const;
|
||||
void operator*=(const real_t p_val);
|
||||
Transform2D operator*(const real_t p_val) 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;
|
||||
_FORCE_INLINE_ Vector2 xform(const Vector2 &p_vec) const;
|
||||
_FORCE_INLINE_ Vector2 xform_inv(const Vector2 &p_vec) const;
|
||||
_FORCE_INLINE_ Rect2 xform(const Rect2 &p_rect) const;
|
||||
_FORCE_INLINE_ Rect2 xform_inv(const Rect2 &p_rect) const;
|
||||
_FORCE_INLINE_ PackedVector2Array xform(const PackedVector2Array &p_array) const;
|
||||
_FORCE_INLINE_ PackedVector2Array xform_inv(const PackedVector2Array &p_array) const;
|
||||
|
||||
operator String() const;
|
||||
|
||||
Transform2D(const real_t xx, const real_t xy, const real_t yx, const real_t yy, const real_t ox, const real_t oy) {
|
||||
columns[0][0] = xx;
|
||||
columns[0][1] = xy;
|
||||
columns[1][0] = yx;
|
||||
columns[1][1] = yy;
|
||||
columns[2][0] = ox;
|
||||
columns[2][1] = oy;
|
||||
}
|
||||
|
||||
Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) {
|
||||
columns[0] = p_x;
|
||||
columns[1] = p_y;
|
||||
columns[2] = p_origin;
|
||||
}
|
||||
|
||||
Transform2D(const real_t p_rot, const Vector2 &p_pos);
|
||||
|
||||
Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos);
|
||||
|
||||
Transform2D() {
|
||||
columns[0][0] = 1.0;
|
||||
columns[1][1] = 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
Vector2 Transform2D::basis_xform(const Vector2 &p_vec) const {
|
||||
return Vector2(
|
||||
tdotx(p_vec),
|
||||
tdoty(p_vec));
|
||||
}
|
||||
|
||||
Vector2 Transform2D::basis_xform_inv(const Vector2 &p_vec) const {
|
||||
return Vector2(
|
||||
columns[0].dot(p_vec),
|
||||
columns[1].dot(p_vec));
|
||||
}
|
||||
|
||||
Vector2 Transform2D::xform(const Vector2 &p_vec) const {
|
||||
return Vector2(
|
||||
tdotx(p_vec),
|
||||
tdoty(p_vec)) +
|
||||
columns[2];
|
||||
}
|
||||
|
||||
Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const {
|
||||
Vector2 v = p_vec - columns[2];
|
||||
|
||||
return Vector2(
|
||||
columns[0].dot(v),
|
||||
columns[1].dot(v));
|
||||
}
|
||||
|
||||
Rect2 Transform2D::xform(const Rect2 &p_rect) const {
|
||||
Vector2 x = columns[0] * p_rect.size.x;
|
||||
Vector2 y = columns[1] * p_rect.size.y;
|
||||
Vector2 pos = xform(p_rect.position);
|
||||
|
||||
Rect2 new_rect;
|
||||
new_rect.position = pos;
|
||||
new_rect.expand_to(pos + x);
|
||||
new_rect.expand_to(pos + y);
|
||||
new_rect.expand_to(pos + x + y);
|
||||
return new_rect;
|
||||
}
|
||||
|
||||
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(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;
|
||||
columns[0][1] = Math::sin(p_rot) * p_scale.x;
|
||||
}
|
||||
|
||||
Rect2 Transform2D::xform_inv(const Rect2 &p_rect) const {
|
||||
Vector2 ends[4] = {
|
||||
xform_inv(p_rect.position),
|
||||
xform_inv(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)),
|
||||
xform_inv(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)),
|
||||
xform_inv(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y))
|
||||
};
|
||||
|
||||
Rect2 new_rect;
|
||||
new_rect.position = ends[0];
|
||||
new_rect.expand_to(ends[1]);
|
||||
new_rect.expand_to(ends[2]);
|
||||
new_rect.expand_to(ends[3]);
|
||||
|
||||
return new_rect;
|
||||
}
|
||||
|
||||
PackedVector2Array Transform2D::xform(const PackedVector2Array &p_array) const {
|
||||
PackedVector2Array array;
|
||||
array.resize(p_array.size());
|
||||
|
||||
const Vector2 *r = p_array.ptr();
|
||||
Vector2 *w = array.ptrw();
|
||||
|
||||
for (int i = 0; i < p_array.size(); ++i) {
|
||||
w[i] = xform(r[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
PackedVector2Array Transform2D::xform_inv(const PackedVector2Array &p_array) const {
|
||||
PackedVector2Array array;
|
||||
array.resize(p_array.size());
|
||||
|
||||
const Vector2 *r = p_array.ptr();
|
||||
Vector2 *w = array.ptrw();
|
||||
|
||||
for (int i = 0; i < p_array.size(); ++i) {
|
||||
w[i] = xform_inv(r[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_TRANSFORM2D_HPP
|
||||
@@ -1,275 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* transform3d.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_TRANSFORM3D_HPP
|
||||
#define GODOT_TRANSFORM3D_HPP
|
||||
|
||||
#include <godot_cpp/core/math.hpp>
|
||||
#include <godot_cpp/variant/aabb.hpp>
|
||||
#include <godot_cpp/variant/basis.hpp>
|
||||
#include <godot_cpp/variant/packed_vector3_array.hpp>
|
||||
#include <godot_cpp/variant/plane.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct _NO_DISCARD_ Transform3D {
|
||||
Basis basis;
|
||||
Vector3 origin;
|
||||
|
||||
void invert();
|
||||
Transform3D inverse() const;
|
||||
|
||||
void affine_invert();
|
||||
Transform3D affine_inverse() const;
|
||||
|
||||
Transform3D rotated(const Vector3 &p_axis, real_t p_angle) const;
|
||||
Transform3D rotated_local(const Vector3 &p_axis, real_t p_angle) const;
|
||||
|
||||
void rotate(const Vector3 &p_axis, real_t p_angle);
|
||||
void rotate_basis(const Vector3 &p_axis, real_t p_angle);
|
||||
|
||||
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
|
||||
Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const;
|
||||
|
||||
void scale(const Vector3 &p_scale);
|
||||
Transform3D scaled(const Vector3 &p_scale) const;
|
||||
Transform3D scaled_local(const Vector3 &p_scale) const;
|
||||
void scale_basis(const Vector3 &p_scale);
|
||||
void translate_local(real_t p_tx, real_t p_ty, real_t p_tz);
|
||||
void translate_local(const Vector3 &p_translation);
|
||||
Transform3D translated(const Vector3 &p_translation) const;
|
||||
Transform3D translated_local(const Vector3 &p_translation) const;
|
||||
|
||||
const Basis &get_basis() const { return basis; }
|
||||
void set_basis(const Basis &p_basis) { basis = p_basis; }
|
||||
|
||||
const Vector3 &get_origin() const { return origin; }
|
||||
void set_origin(const Vector3 &p_origin) { origin = p_origin; }
|
||||
|
||||
void orthonormalize();
|
||||
Transform3D orthonormalized() const;
|
||||
void orthogonalize();
|
||||
Transform3D orthogonalized() const;
|
||||
bool is_equal_approx(const Transform3D &p_transform) const;
|
||||
|
||||
bool operator==(const Transform3D &p_transform) const;
|
||||
bool operator!=(const Transform3D &p_transform) const;
|
||||
|
||||
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const;
|
||||
_FORCE_INLINE_ AABB xform(const AABB &p_aabb) const;
|
||||
_FORCE_INLINE_ PackedVector3Array xform(const PackedVector3Array &p_array) const;
|
||||
|
||||
// NOTE: These are UNSAFE with non-uniform scaling, and will produce incorrect results.
|
||||
// They use the transpose.
|
||||
// For safe inverse transforms, xform by the affine_inverse.
|
||||
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const;
|
||||
_FORCE_INLINE_ AABB xform_inv(const AABB &p_aabb) const;
|
||||
_FORCE_INLINE_ PackedVector3Array xform_inv(const PackedVector3Array &p_array) const;
|
||||
|
||||
// Safe with non-uniform scaling (uses affine_inverse).
|
||||
_FORCE_INLINE_ Plane xform(const Plane &p_plane) const;
|
||||
_FORCE_INLINE_ Plane xform_inv(const Plane &p_plane) const;
|
||||
|
||||
// These fast versions use precomputed affine inverse, and should be used in bottleneck areas where
|
||||
// multiple planes are to be transformed.
|
||||
_FORCE_INLINE_ Plane xform_fast(const Plane &p_plane, const Basis &p_basis_inverse_transpose) const;
|
||||
static _FORCE_INLINE_ Plane xform_inv_fast(const Plane &p_plane, const Transform3D &p_inverse, const Basis &p_basis_transpose);
|
||||
|
||||
void operator*=(const Transform3D &p_transform);
|
||||
Transform3D operator*(const Transform3D &p_transform) const;
|
||||
void operator*=(const real_t p_val);
|
||||
Transform3D operator*(const real_t p_val) const;
|
||||
|
||||
Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const;
|
||||
|
||||
_FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const {
|
||||
Vector3 v = t.origin - origin;
|
||||
return Transform3D(basis.transpose_xform(t.basis),
|
||||
basis.xform(v));
|
||||
}
|
||||
|
||||
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) {
|
||||
basis.set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
|
||||
origin.x = tx;
|
||||
origin.y = ty;
|
||||
origin.z = tz;
|
||||
}
|
||||
|
||||
operator String() const;
|
||||
|
||||
Transform3D() {}
|
||||
Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3());
|
||||
Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin);
|
||||
Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz);
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const {
|
||||
return Vector3(
|
||||
basis[0].dot(p_vector) + origin.x,
|
||||
basis[1].dot(p_vector) + origin.y,
|
||||
basis[2].dot(p_vector) + origin.z);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 Transform3D::xform_inv(const Vector3 &p_vector) const {
|
||||
Vector3 v = p_vector - origin;
|
||||
|
||||
return Vector3(
|
||||
(basis.rows[0][0] * v.x) + (basis.rows[1][0] * v.y) + (basis.rows[2][0] * v.z),
|
||||
(basis.rows[0][1] * v.x) + (basis.rows[1][1] * v.y) + (basis.rows[2][1] * v.z),
|
||||
(basis.rows[0][2] * v.x) + (basis.rows[1][2] * v.y) + (basis.rows[2][2] * v.z));
|
||||
}
|
||||
|
||||
// Neither the plane regular xform or xform_inv are particularly efficient,
|
||||
// as they do a basis inverse. For xforming a large number
|
||||
// of planes it is better to pre-calculate the inverse transpose basis once
|
||||
// and reuse it for each plane, by using the 'fast' version of the functions.
|
||||
_FORCE_INLINE_ Plane Transform3D::xform(const Plane &p_plane) const {
|
||||
Basis b = basis.inverse();
|
||||
b.transpose();
|
||||
return xform_fast(p_plane, b);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Plane Transform3D::xform_inv(const Plane &p_plane) const {
|
||||
Transform3D inv = affine_inverse();
|
||||
Basis basis_transpose = basis.transposed();
|
||||
return xform_inv_fast(p_plane, inv, basis_transpose);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ AABB Transform3D::xform(const AABB &p_aabb) const {
|
||||
/* https://dev.theomader.com/transform-bounding-boxes/ */
|
||||
Vector3 min = p_aabb.position;
|
||||
Vector3 max = p_aabb.position + p_aabb.size;
|
||||
Vector3 tmin, tmax;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
tmin[i] = tmax[i] = origin[i];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
real_t e = basis[i][j] * min[j];
|
||||
real_t f = basis[i][j] * max[j];
|
||||
if (e < f) {
|
||||
tmin[i] += e;
|
||||
tmax[i] += f;
|
||||
} else {
|
||||
tmin[i] += f;
|
||||
tmax[i] += e;
|
||||
}
|
||||
}
|
||||
}
|
||||
AABB r_aabb;
|
||||
r_aabb.position = tmin;
|
||||
r_aabb.size = tmax - tmin;
|
||||
return r_aabb;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ AABB Transform3D::xform_inv(const AABB &p_aabb) const {
|
||||
/* define vertices */
|
||||
Vector3 vertices[8] = {
|
||||
Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z),
|
||||
Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z),
|
||||
Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z),
|
||||
Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z),
|
||||
Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z),
|
||||
Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z),
|
||||
Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z),
|
||||
Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z)
|
||||
};
|
||||
|
||||
AABB ret;
|
||||
|
||||
ret.position = xform_inv(vertices[0]);
|
||||
|
||||
for (int i = 1; i < 8; i++) {
|
||||
ret.expand_to(xform_inv(vertices[i]));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PackedVector3Array Transform3D::xform(const PackedVector3Array &p_array) const {
|
||||
PackedVector3Array array;
|
||||
array.resize(p_array.size());
|
||||
|
||||
const Vector3 *r = p_array.ptr();
|
||||
Vector3 *w = array.ptrw();
|
||||
|
||||
for (int i = 0; i < p_array.size(); ++i) {
|
||||
w[i] = xform(r[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
PackedVector3Array Transform3D::xform_inv(const PackedVector3Array &p_array) const {
|
||||
PackedVector3Array array;
|
||||
array.resize(p_array.size());
|
||||
|
||||
const Vector3 *r = p_array.ptr();
|
||||
Vector3 *w = array.ptrw();
|
||||
|
||||
for (int i = 0; i < p_array.size(); ++i) {
|
||||
w[i] = xform_inv(r[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Plane Transform3D::xform_fast(const Plane &p_plane, const Basis &p_basis_inverse_transpose) const {
|
||||
// Transform a single point on the plane.
|
||||
Vector3 point = p_plane.normal * p_plane.d;
|
||||
point = xform(point);
|
||||
|
||||
// Use inverse transpose for correct normals with non-uniform scaling.
|
||||
Vector3 normal = p_basis_inverse_transpose.xform(p_plane.normal);
|
||||
normal.normalize();
|
||||
|
||||
real_t d = normal.dot(point);
|
||||
return Plane(normal, d);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Plane Transform3D::xform_inv_fast(const Plane &p_plane, const Transform3D &p_inverse, const Basis &p_basis_transpose) {
|
||||
// Transform a single point on the plane.
|
||||
Vector3 point = p_plane.normal * p_plane.d;
|
||||
point = p_inverse.xform(point);
|
||||
|
||||
// Note that instead of precalculating the transpose, an alternative
|
||||
// would be to use the transpose for the basis transform.
|
||||
// However that would be less SIMD friendly (requiring a swizzle).
|
||||
// So the cost is one extra precalced value in the calling code.
|
||||
// This is probably worth it, as this could be used in bottleneck areas. And
|
||||
// where it is not a bottleneck, the non-fast method is fine.
|
||||
|
||||
// Use transpose for correct normals with non-uniform scaling.
|
||||
Vector3 normal = p_basis_transpose.xform(p_plane.normal);
|
||||
normal.normalize();
|
||||
|
||||
real_t d = normal.dot(point);
|
||||
return Plane(normal, d);
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_TRANSFORM3D_HPP
|
||||
@@ -1,122 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* typed_array.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_TYPED_ARRAY_HPP
|
||||
#define GODOT_TYPED_ARRAY_HPP
|
||||
|
||||
#include <godot_cpp/variant/array.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
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.");
|
||||
_ref(p_array);
|
||||
}
|
||||
_FORCE_INLINE_ TypedArray(const Variant &p_variant) :
|
||||
Array(p_variant.operator Array(), Variant::OBJECT, T::get_class_static(), Variant()) {
|
||||
}
|
||||
_FORCE_INLINE_ TypedArray(const Array &p_array) :
|
||||
Array(p_array, Variant::OBJECT, T::get_class_static(), Variant()) {
|
||||
}
|
||||
_FORCE_INLINE_ TypedArray() {
|
||||
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
|
||||
}
|
||||
};
|
||||
|
||||
// specialization for the rest of variant types
|
||||
|
||||
#define MAKE_TYPED_ARRAY(m_type, m_variant_type) \
|
||||
template <> \
|
||||
class TypedArray<m_type> : 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."); \
|
||||
_ref(p_array); \
|
||||
} \
|
||||
_FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
|
||||
Array(p_variant.operator Array(), m_variant_type, StringName(), Variant()) { \
|
||||
} \
|
||||
_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()); \
|
||||
} \
|
||||
};
|
||||
|
||||
MAKE_TYPED_ARRAY(bool, Variant::BOOL)
|
||||
MAKE_TYPED_ARRAY(uint8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(int8_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(uint16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(int16_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(uint32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(int32_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(uint64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(int64_t, Variant::INT)
|
||||
MAKE_TYPED_ARRAY(float, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY(double, Variant::FLOAT)
|
||||
MAKE_TYPED_ARRAY(String, Variant::STRING)
|
||||
MAKE_TYPED_ARRAY(Vector2, Variant::VECTOR2)
|
||||
MAKE_TYPED_ARRAY(Vector2i, Variant::VECTOR2I)
|
||||
MAKE_TYPED_ARRAY(Rect2, Variant::RECT2)
|
||||
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(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(Color, Variant::COLOR)
|
||||
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
|
||||
MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
|
||||
MAKE_TYPED_ARRAY(RID, Variant::RID)
|
||||
MAKE_TYPED_ARRAY(Callable, Variant::CALLABLE)
|
||||
MAKE_TYPED_ARRAY(Signal, Variant::SIGNAL)
|
||||
MAKE_TYPED_ARRAY(Dictionary, Variant::DICTIONARY)
|
||||
MAKE_TYPED_ARRAY(Array, Variant::ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
|
||||
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(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_TYPED_ARRAY_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user