mirror of
https://github.com/godotengine/godot-cpp.git
synced 2026-01-01 05:48:37 +03:00
Compare commits
61 Commits
godot-4.3-
...
4.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5cc777a89 | ||
|
|
b1e2ac5cbb | ||
|
|
53caa6adbc | ||
|
|
a9abdb5f0c | ||
|
|
9892f63abb | ||
|
|
7b4ca64761 | ||
|
|
6cdac999c2 | ||
|
|
48544896ee | ||
|
|
443c075fa3 | ||
|
|
52937a3850 | ||
|
|
888f46bbcc | ||
|
|
de7e5b9145 | ||
|
|
8fffe3b558 | ||
|
|
dcd0842fab | ||
|
|
dacaa81f2f | ||
|
|
40e65753f9 | ||
|
|
2dee0cc4de | ||
|
|
3f454d142d | ||
|
|
f3a1a2fd45 | ||
|
|
08e4c89da9 | ||
|
|
86d0dbe695 | ||
|
|
dc87cb6b97 | ||
|
|
4b9cd6ae9d | ||
|
|
fba9ecd0da | ||
|
|
59ad323dd1 | ||
|
|
9dc2e15d90 | ||
|
|
2d96b62774 | ||
|
|
2cd6221286 | ||
|
|
d6a47a28c7 | ||
|
|
f2303ba0cc | ||
|
|
c9da56cca2 | ||
|
|
3449c4e1d3 | ||
|
|
0899cf6098 | ||
|
|
06fbf3ce95 | ||
|
|
d5bdde9509 | ||
|
|
9ded2402dc | ||
|
|
575f317bf1 | ||
|
|
56571dc584 | ||
|
|
94d74979ce | ||
|
|
bf26191ead | ||
|
|
af78f2778f | ||
|
|
30a395bf43 | ||
|
|
a3d5d6d4d3 | ||
|
|
e751531290 | ||
|
|
2de650b82a | ||
|
|
5fe58bcd1e | ||
|
|
daf8ac1c33 | ||
|
|
b12aeb1b38 | ||
|
|
fa0b4cffc0 | ||
|
|
e52b4ea4fd | ||
|
|
20459da676 | ||
|
|
1cce4d15ab | ||
|
|
17ca325aeb | ||
|
|
e298f430b5 | ||
|
|
1ac33c906e | ||
|
|
842a7f621f | ||
|
|
37d255af6c | ||
|
|
762db4e4d6 | ||
|
|
c823e84ff2 | ||
|
|
26cb3292a0 | ||
|
|
150e45071b |
25
.github/actions/godot-cache-restore/action.yml
vendored
25
.github/actions/godot-cache-restore/action.yml
vendored
@@ -3,19 +3,22 @@ description: Restore Godot build cache.
|
||||
inputs:
|
||||
cache-name:
|
||||
description: The cache base name (job name by default).
|
||||
default: "${{github.job}}"
|
||||
default: ${{ github.job }}
|
||||
scons-cache:
|
||||
description: The scons cache path.
|
||||
default: "${{github.workspace}}/.scons-cache/"
|
||||
description: The SCons cache path.
|
||||
default: ${{ github.workspace }}/.scons-cache/
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
using: composite
|
||||
steps:
|
||||
- name: Restore .scons_cache directory
|
||||
uses: actions/cache/restore@v3
|
||||
- name: Restore SCons cache directory
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ${{inputs.scons-cache}}
|
||||
key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
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}}
|
||||
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
|
||||
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}
|
||||
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-refs/heads/${{ env.GODOT_BASE_BRANCH }}
|
||||
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}
|
||||
|
||||
11
.github/actions/godot-cache-save/action.yml
vendored
11
.github/actions/godot-cache-save/action.yml
vendored
@@ -3,15 +3,16 @@ description: Save Godot build cache.
|
||||
inputs:
|
||||
cache-name:
|
||||
description: The cache base name (job name by default).
|
||||
default: "${{github.job}}"
|
||||
default: ${{ github.job }}
|
||||
scons-cache:
|
||||
description: The SCons cache path.
|
||||
default: "${{github.workspace}}/.scons-cache/"
|
||||
default: ${{ github.workspace }}/.scons-cache/
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
using: composite
|
||||
steps:
|
||||
- name: Save SCons cache directory
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{inputs.scons-cache}}
|
||||
key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
path: ${{ inputs.scons-cache }}
|
||||
key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
|
||||
|
||||
62
.github/actions/setup-godot-cpp/action.yml
vendored
Normal file
62
.github/actions/setup-godot-cpp/action.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Setup godot-cpp
|
||||
description: Setup build dependencies for godot-cpp.
|
||||
|
||||
inputs:
|
||||
platform:
|
||||
required: true
|
||||
description: Target platform.
|
||||
em-version:
|
||||
default: 3.1.62
|
||||
description: Emscripten version.
|
||||
windows-compiler:
|
||||
required: true
|
||||
description: The compiler toolchain to use on Windows ('mingw' or 'msvc').
|
||||
type: choice
|
||||
options:
|
||||
- mingw
|
||||
- msvc
|
||||
default: mingw
|
||||
mingw-version:
|
||||
default: 12.2.0
|
||||
description: MinGW version.
|
||||
ndk-version:
|
||||
default: r23c
|
||||
description: Android NDK version.
|
||||
scons-version:
|
||||
default: 4.4.0
|
||||
description: SCons version.
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup Python (for SCons)
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Setup Android dependencies
|
||||
if: inputs.platform == 'android'
|
||||
uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
ndk-version: ${{ inputs.ndk-version }}
|
||||
link-to-sdk: true
|
||||
|
||||
- name: Setup Web dependencies
|
||||
if: inputs.platform == 'web'
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{ inputs.em-version }}
|
||||
no-cache: true
|
||||
|
||||
- name: Setup MinGW for Windows/MinGW build
|
||||
if: inputs.platform == 'windows' && inputs.windows-compiler == 'mingw'
|
||||
uses: egor-tensin/setup-mingw@v2
|
||||
with:
|
||||
version: ${{ inputs.mingw-version }}
|
||||
|
||||
- name: Setup SCons
|
||||
shell: bash
|
||||
run: |
|
||||
python -c "import sys; print(sys.version)"
|
||||
python -m pip install scons==${{ inputs.scons-version }}
|
||||
scons --version
|
||||
75
.github/workflows/ci.yml
vendored
75
.github/workflows/ci.yml
vendored
@@ -1,14 +1,15 @@
|
||||
name: Continuous integration
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
# Only used for the cache key. Increment version to force clean build.
|
||||
GODOT_BASE_BRANCH: master
|
||||
# Used to select the version of Godot to run the tests with.
|
||||
GODOT_TEST_VERSION: master
|
||||
GODOT_TEST_VERSION: 4.3-stable
|
||||
|
||||
concurrency:
|
||||
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
|
||||
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
@@ -20,7 +21,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- name: 🐧 Linux (GCC)
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
platform: linux
|
||||
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
|
||||
@@ -28,7 +29,7 @@ jobs:
|
||||
cache-name: linux-x86_64
|
||||
|
||||
- name: 🐧 Linux (GCC, Double Precision)
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.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
|
||||
@@ -37,7 +38,7 @@ jobs:
|
||||
cache-name: linux-x86_64-f64
|
||||
|
||||
- name: 🏁 Windows (x86_64, MSVC)
|
||||
os: windows-2019
|
||||
os: windows-2022
|
||||
platform: windows
|
||||
artifact-name: godot-cpp-windows-msvc2019-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.lib
|
||||
@@ -45,7 +46,7 @@ jobs:
|
||||
cache-name: windows-x86_64-msvc
|
||||
|
||||
- name: 🏁 Windows (x86_64, MinGW)
|
||||
os: windows-2019
|
||||
os: windows-2022
|
||||
platform: windows
|
||||
artifact-name: godot-cpp-linux-mingw-x86_64-release
|
||||
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.a
|
||||
@@ -63,7 +64,7 @@ jobs:
|
||||
cache-name: macos-universal
|
||||
|
||||
- name: 🤖 Android (arm64)
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
platform: android
|
||||
artifact-name: godot-cpp-android-arm64-release
|
||||
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
|
||||
@@ -81,7 +82,7 @@ jobs:
|
||||
cache-name: ios-arm64
|
||||
|
||||
- name: 🌐 Web (wasm32)
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
platform: web
|
||||
artifact-name: godot-cpp-web-wasm32-release
|
||||
artifact-path: bin/libgodot-cpp.web.template_release.wasm32.a
|
||||
@@ -91,7 +92,6 @@ jobs:
|
||||
env:
|
||||
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
|
||||
EM_VERSION: 3.1.39
|
||||
EM_CACHE_FOLDER: "emsdk-cache"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -105,34 +105,11 @@ jobs:
|
||||
cache-name: ${{ matrix.cache-name }}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Set up Python (for SCons)
|
||||
uses: actions/setup-python@v5
|
||||
- name: Setup godot-cpp
|
||||
uses: ./.github/actions/setup-godot-cpp
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Android dependencies
|
||||
if: ${{ matrix.platform == 'android' }}
|
||||
uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
ndk-version: r23c
|
||||
link-to-sdk: true
|
||||
|
||||
- name: Web dependencies
|
||||
if: ${{ matrix.platform == 'web' }}
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{env.EM_VERSION}}
|
||||
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
||||
|
||||
- name: Setup MinGW for Windows/MinGW build
|
||||
if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }}
|
||||
uses: egor-tensin/setup-mingw@v2
|
||||
with:
|
||||
version: 12.2.0
|
||||
|
||||
- name: Install scons
|
||||
run: |
|
||||
python -m pip install scons==4.0.0
|
||||
platform: ${{ matrix.platform }}
|
||||
windows-compiler: ${{ contains(matrix.flags, 'use_mingw=yes') && 'mingw' || 'msvc' }}
|
||||
|
||||
- name: Generate godot-cpp sources only
|
||||
run: |
|
||||
@@ -161,7 +138,7 @@ jobs:
|
||||
|
||||
- name: Download latest Godot artifacts
|
||||
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
|
||||
if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }}
|
||||
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
|
||||
with:
|
||||
repo: godotengine/godot
|
||||
branch: master
|
||||
@@ -175,13 +152,13 @@ jobs:
|
||||
path: godot-artifacts
|
||||
|
||||
- name: Prepare Godot artifacts for testing
|
||||
if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }}
|
||||
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
|
||||
run: |
|
||||
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
|
||||
echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
|
||||
|
||||
- name: Download requested Godot version for testing
|
||||
if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION != 'master' }}
|
||||
if: matrix.run-tests && env.GODOT_TEST_VERSION != 'master'
|
||||
run: |
|
||||
wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
|
||||
unzip -a Godot.zip
|
||||
@@ -189,7 +166,7 @@ jobs:
|
||||
echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
|
||||
|
||||
- name: Run tests
|
||||
if: ${{ matrix.run-tests }}
|
||||
if: matrix.run-tests
|
||||
run: |
|
||||
$GODOT --headless --version
|
||||
cd test
|
||||
@@ -198,7 +175,7 @@ jobs:
|
||||
./run-tests.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: ${{ matrix.artifact-path }}
|
||||
@@ -206,7 +183,7 @@ jobs:
|
||||
|
||||
linux-cmake:
|
||||
name: 🐧 Build (Linux, GCC, CMake)
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -230,7 +207,7 @@ jobs:
|
||||
|
||||
linux-cmake-ninja:
|
||||
name: 🐧 Build (Linux, GCC, CMake Ninja)
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -254,7 +231,7 @@ jobs:
|
||||
|
||||
windows-msvc-cmake:
|
||||
name: 🏁 Build (Windows, MSVC, CMake)
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -263,10 +240,10 @@ jobs:
|
||||
|
||||
- name: Build godot-cpp
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 16 2019" .
|
||||
cmake --build . --verbose
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 17 2022" .
|
||||
cmake --build . --verbose --config Release
|
||||
|
||||
- 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
|
||||
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -G"Visual Studio 17 2022" .
|
||||
cmake --build . --verbose --config Release
|
||||
|
||||
21
.github/workflows/runner.yml
vendored
Normal file
21
.github/workflows/runner.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: 🔗 GHA
|
||||
on: [push, pull_request, merge_group]
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# First stage: Only static checks, fast and prevent expensive builds from running.
|
||||
|
||||
static-checks:
|
||||
if: '!vars.DISABLE_GODOT_CI'
|
||||
name: 📊 Static Checks
|
||||
uses: ./.github/workflows/static_checks.yml
|
||||
|
||||
# Second stage: Run all the builds and some of the tests.
|
||||
|
||||
ci:
|
||||
name: 🛠️ Continuous Integration
|
||||
needs: static-checks
|
||||
uses: ./.github/workflows/ci.yml
|
||||
9
.github/workflows/static_checks.yml
vendored
9
.github/workflows/static_checks.yml
vendored
@@ -1,8 +1,9 @@
|
||||
name: 📊 Static Checks
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
|
||||
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
@@ -31,3 +32,7 @@ jobs:
|
||||
uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
extra_args: --verbose --hook-stage manual --files ${{ env.CHANGED_FILES }}
|
||||
|
||||
- name: Check generated files consistency
|
||||
run:
|
||||
python misc/scripts/check_get_file_list.py
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -195,3 +195,7 @@ compile_commands.json
|
||||
# Python development
|
||||
.venv
|
||||
venv
|
||||
|
||||
# Clion Configuration
|
||||
.idea/
|
||||
cmake-build-*
|
||||
|
||||
234
CMakeLists.txt
234
CMakeLists.txt
@@ -1,228 +1,24 @@
|
||||
# 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 suppress warnings in projects including this one.
|
||||
# GODOT_CPP_WARNING_AS_ERROR Treat any warnings as errors
|
||||
# GODOT_ENABLE_HOT_RELOAD Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds.
|
||||
# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)
|
||||
# FLOAT_PRECISION: Floating-point precision level ("single", "double")
|
||||
#
|
||||
# Android cmake arguments
|
||||
# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake)
|
||||
# ANDROID_NDK: The path to the android ndk root folder
|
||||
# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9)
|
||||
# ANDROID_PLATFORM: The android platform version (android-23)
|
||||
# More info here: https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# Builds a debug version:
|
||||
# cmake .
|
||||
# cmake --build .
|
||||
#
|
||||
# Builds a release version with clang
|
||||
# CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .
|
||||
# cmake --build .
|
||||
#
|
||||
# Builds an android armeabi-v7a debug version:
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \
|
||||
# -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug .
|
||||
# cmake --build .
|
||||
#
|
||||
# Protip
|
||||
# Generate the buildfiles in a sub directory to not clutter the root directory with build files:
|
||||
# mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
|
||||
#
|
||||
# Todo
|
||||
# Test build for Windows, Mac and mingw.
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(godot-cpp LANGUAGES CXX)
|
||||
|
||||
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
|
||||
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/" )
|
||||
|
||||
# Set some helper variables for readability
|
||||
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
|
||||
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
|
||||
set( compiler_is_msvc "$<CXX_COMPILER_ID:MSVC>" )
|
||||
|
||||
# Default build type is Debug in the SConstruct
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
# Hot reload is enabled by default in Debug-builds
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
option(GODOT_ENABLE_HOT_RELOAD "Build with hot reload support" ON)
|
||||
else()
|
||||
option(GODOT_ENABLE_HOT_RELOAD "Build with hot reload support" OFF)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED BITS)
|
||||
set(BITS 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(BITS 64)
|
||||
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
endif()
|
||||
|
||||
# Input from user for GDExtension interface header and the API JSON file
|
||||
set(GODOT_GDEXTENSION_DIR "gdextension" CACHE STRING "")
|
||||
set(GODOT_CUSTOM_API_FILE "" CACHE STRING "")
|
||||
|
||||
set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json")
|
||||
if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override.
|
||||
set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}")
|
||||
endif()
|
||||
|
||||
set(FLOAT_PRECISION "single" CACHE STRING "")
|
||||
if ("${FLOAT_PRECISION}" STREQUAL "double")
|
||||
add_definitions(-DREAL_T_IS_DOUBLE)
|
||||
endif()
|
||||
|
||||
set(GODOT_COMPILE_FLAGS )
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy
|
||||
STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
||||
add_definitions(-DNOMINMAX)
|
||||
else() # GCC/Clang
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
endif()
|
||||
|
||||
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
|
||||
# saves around 20% of binary size and very significant build time (GH-80513).
|
||||
option(GODOT_DISABLE_EXCEPTIONS ON "Force disabling exception handling code")
|
||||
if (GODOT_DISABLE_EXCEPTIONS)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions")
|
||||
endif()
|
||||
else()
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (GODOT_ENABLE_HOT_RELOAD)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D HOT_RELOAD_ENABLED")
|
||||
endif()
|
||||
|
||||
# Generate source from the bindings file
|
||||
find_package(Python3 3.4 REQUIRED) # pathlib should be present
|
||||
if(GENERATE_TEMPLATE_GET_NODE)
|
||||
set(GENERATE_BINDING_PARAMETERS "True")
|
||||
else()
|
||||
set(GENERATE_BINDING_PARAMETERS "False")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GENERATED_FILES_LIST
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
|
||||
COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${FLOAT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")"
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py
|
||||
COMMENT "Generating bindings"
|
||||
)
|
||||
|
||||
# Get Sources
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**)
|
||||
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**)
|
||||
|
||||
# Define our godot-cpp library
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
${SOURCES}
|
||||
${HEADERS}
|
||||
${GENERATED_FILES_LIST}
|
||||
)
|
||||
add_library(godot::cpp ALIAS ${PROJECT_NAME})
|
||||
|
||||
include(GodotCompilerWarnings)
|
||||
|
||||
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)
|
||||
# Configure CMake
|
||||
# https://discourse.cmake.org/t/how-do-i-remove-compile-options-from-target/5965
|
||||
# https://stackoverflow.com/questions/74426638/how-to-remove-rtc1-from-specific-target-or-file-in-cmake
|
||||
if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} ${GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
|
||||
include
|
||||
${CMAKE_CURRENT_BINARY_DIR}/gen/include
|
||||
${GODOT_GDEXTENSION_DIR}
|
||||
)
|
||||
include( ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake )
|
||||
|
||||
# Add the compile flags
|
||||
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
|
||||
# I know this doesn't look like a typical CMakeLists.txt, but as we are
|
||||
# attempting mostly feature parity with SCons, and easy maintenance, the closer
|
||||
# the two build systems look the easier they will be to keep in lockstep.
|
||||
|
||||
# Create the correct name (godot.os.build_type.system_bits)
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
|
||||
# The typical target definitions are in ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake
|
||||
|
||||
if(ANDROID)
|
||||
# Added the android abi after system name
|
||||
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
|
||||
godotcpp_options()
|
||||
|
||||
# Android does not have the bits at the end if you look at the main godot repo build
|
||||
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
|
||||
else()
|
||||
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
CXX_EXTENSIONS OFF
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
|
||||
OUTPUT_NAME "${OUTPUT_NAME}"
|
||||
)
|
||||
godotcpp_generate()
|
||||
|
||||
28
README.md
28
README.md
@@ -7,6 +7,8 @@
|
||||
> from Godot's `master` branch.
|
||||
>
|
||||
> For users of stable branches, switch to the branch matching your target Godot version:
|
||||
> - [`4.4`](https://github.com/godotengine/godot-cpp/tree/4.4)
|
||||
> - [`4.3`](https://github.com/godotengine/godot-cpp/tree/4.3)
|
||||
> - [`4.2`](https://github.com/godotengine/godot-cpp/tree/4.2)
|
||||
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
|
||||
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
|
||||
@@ -49,20 +51,13 @@ Godot version.**
|
||||
|
||||
## 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-cpp/issues)
|
||||
> for a list of known issues, and be sure to provide feedback on issues and PRs
|
||||
> which affect your use of this extension.
|
||||
GDExtensions targeting an earlier version of Godot should work in later minor versions,
|
||||
but not vice-versa. For example, a GDExtension targeting Godot 4.2 should work just fine
|
||||
in Godot 4.3, but one targeting Godot 4.3 won't work in Godot 4.2.
|
||||
|
||||
There is one exception to this: extensions targeting Godot 4.0 will _not_ work with
|
||||
Godot 4.1 and later.
|
||||
See [Updating your GDExtension for 4.1](https://docs.godotengine.org/en/latest/tutorials/migrating/upgrading_to_godot_4.1.html#updating-your-gdextension-for-godot-4-1).
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -71,8 +66,7 @@ wish to help out, ensure you have an account on GitHub and create a "fork" of
|
||||
this repository. See [Pull request workflow](https://docs.godotengine.org/en/stable/community/contributing/pr_workflow.html)
|
||||
for instructions.
|
||||
|
||||
Please install clang-format and copy the files in `misc/hooks` into `.git/hooks`
|
||||
so formatting is done before your changes are submitted.
|
||||
Please install clang-format and the [pre-commit](https://pre-commit.com/) Python framework so formatting is done before your changes are submitted. See the [code style guidelines](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html#pre-commit-hook) for instructions.
|
||||
|
||||
## Getting started
|
||||
|
||||
@@ -146,4 +140,4 @@ See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template)
|
||||
generic reusable template.
|
||||
|
||||
Or checkout the code for the [Summator example](https://github.com/paddy-exe/GDExtensionSummator)
|
||||
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/gdextension/gdextension_cpp_example.html).
|
||||
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/cpp/gdextension_cpp_example.html).
|
||||
|
||||
@@ -197,13 +197,16 @@ def generate_virtuals(target):
|
||||
f.write(txt)
|
||||
|
||||
|
||||
def get_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
|
||||
def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
api = {}
|
||||
files = []
|
||||
with open(api_filepath, encoding="utf-8") as api_file:
|
||||
api = json.load(api_file)
|
||||
|
||||
build_profile = parse_build_profile(profile_filepath, api)
|
||||
return _get_file_list(api, output_dir, headers, sources)
|
||||
|
||||
|
||||
def _get_file_list(api, output_dir, headers=False, sources=False):
|
||||
files = []
|
||||
|
||||
core_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp" / "core"
|
||||
include_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp"
|
||||
@@ -235,7 +238,7 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False, profil
|
||||
source_filename = source_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".cpp")
|
||||
if headers:
|
||||
files.append(str(header_filename.as_posix()))
|
||||
if sources and is_class_included(engine_class["name"], build_profile):
|
||||
if sources:
|
||||
files.append(str(source_filename.as_posix()))
|
||||
|
||||
for native_struct in api["native_structures"]:
|
||||
@@ -267,131 +270,27 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False, profil
|
||||
return files
|
||||
|
||||
|
||||
def print_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
|
||||
print(*get_file_list(api_filepath, output_dir, headers, sources, profile_filepath), sep=";", end=None)
|
||||
|
||||
|
||||
def parse_build_profile(profile_filepath, api):
|
||||
if profile_filepath == "":
|
||||
return {}
|
||||
print("Using feature build profile: " + profile_filepath)
|
||||
|
||||
with open(profile_filepath, encoding="utf-8") as profile_file:
|
||||
profile = json.load(profile_file)
|
||||
|
||||
api_dict = {}
|
||||
parents = {}
|
||||
children = {}
|
||||
for engine_class in api["classes"]:
|
||||
api_dict[engine_class["name"]] = engine_class
|
||||
parent = engine_class.get("inherits", "")
|
||||
child = engine_class["name"]
|
||||
parents[child] = parent
|
||||
if parent == "":
|
||||
continue
|
||||
children[parent] = children.get(parent, [])
|
||||
children[parent].append(child)
|
||||
|
||||
# Parse methods dependencies
|
||||
deps = {}
|
||||
reverse_deps = {}
|
||||
for name, engine_class in api_dict.items():
|
||||
ref_cls = set()
|
||||
for method in engine_class.get("methods", []):
|
||||
rtype = method.get("return_value", {}).get("type", "")
|
||||
args = [a["type"] for a in method.get("arguments", [])]
|
||||
if rtype in api_dict:
|
||||
ref_cls.add(rtype)
|
||||
elif is_enum(rtype) and get_enum_class(rtype) in api_dict:
|
||||
ref_cls.add(get_enum_class(rtype))
|
||||
for arg in args:
|
||||
if arg in api_dict:
|
||||
ref_cls.add(arg)
|
||||
elif is_enum(arg) and get_enum_class(arg) in api_dict:
|
||||
ref_cls.add(get_enum_class(arg))
|
||||
deps[engine_class["name"]] = set(filter(lambda x: x != name, ref_cls))
|
||||
for acls in ref_cls:
|
||||
if acls == name:
|
||||
continue
|
||||
reverse_deps[acls] = reverse_deps.get(acls, set())
|
||||
reverse_deps[acls].add(name)
|
||||
|
||||
included = []
|
||||
front = list(profile.get("enabled_classes", []))
|
||||
if front:
|
||||
# These must always be included
|
||||
front.append("WorkerThreadPool")
|
||||
front.append("ClassDB")
|
||||
front.append("ClassDBSingleton")
|
||||
while front:
|
||||
cls = front.pop()
|
||||
if cls in included:
|
||||
continue
|
||||
included.append(cls)
|
||||
parent = parents.get(cls, "")
|
||||
if parent:
|
||||
front.append(parent)
|
||||
for rcls in deps.get(cls, set()):
|
||||
if rcls in included or rcls in front:
|
||||
continue
|
||||
front.append(rcls)
|
||||
|
||||
excluded = []
|
||||
front = list(profile.get("disabled_classes", []))
|
||||
while front:
|
||||
cls = front.pop()
|
||||
if cls in excluded:
|
||||
continue
|
||||
excluded.append(cls)
|
||||
front += children.get(cls, [])
|
||||
for rcls in reverse_deps.get(cls, set()):
|
||||
if rcls in excluded or rcls in front:
|
||||
continue
|
||||
front.append(rcls)
|
||||
|
||||
if included and excluded:
|
||||
print(
|
||||
"WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
|
||||
)
|
||||
|
||||
return {
|
||||
"enabled_classes": included,
|
||||
"disabled_classes": excluded,
|
||||
}
|
||||
|
||||
|
||||
def scons_emit_files(target, source, env):
|
||||
profile_filepath = env.get("build_profile", "")
|
||||
if profile_filepath and not Path(profile_filepath).is_absolute():
|
||||
profile_filepath = str((Path(env.Dir("#").abspath) / profile_filepath).as_posix())
|
||||
|
||||
files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True, profile_filepath)]
|
||||
env.Clean(target, files)
|
||||
env["godot_cpp_gen_dir"] = target[0].abspath
|
||||
return files, source
|
||||
|
||||
|
||||
def scons_generate_bindings(target, source, env):
|
||||
generate_bindings(
|
||||
str(source[0]),
|
||||
env["generate_template_get_node"],
|
||||
"32" if "32" in env["arch"] else "64",
|
||||
env["precision"],
|
||||
env["godot_cpp_gen_dir"],
|
||||
)
|
||||
return None
|
||||
def print_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
print(*get_file_list(api_filepath, output_dir, headers, sources), sep=";", end=None)
|
||||
|
||||
|
||||
def generate_bindings(api_filepath, use_template_get_node, bits="64", precision="single", output_dir="."):
|
||||
api = None
|
||||
api = {}
|
||||
with open(api_filepath, encoding="utf-8") as api_file:
|
||||
api = json.load(api_file)
|
||||
_generate_bindings(api, api_filepath, use_template_get_node, bits, precision, output_dir)
|
||||
|
||||
|
||||
def _generate_bindings(api, api_filepath, use_template_get_node, bits="64", precision="single", output_dir="."):
|
||||
if "precision" in api["header"] and precision != api["header"]["precision"]:
|
||||
raise Exception(
|
||||
f"Cannot do a precision={precision} build using '{api_filepath}' which was generated by Godot built with precision={api['header']['precision']}"
|
||||
)
|
||||
|
||||
target_dir = Path(output_dir) / "gen"
|
||||
|
||||
with open(api_filepath, encoding="utf-8") as api_file:
|
||||
api = json.load(api_file)
|
||||
|
||||
shutil.rmtree(target_dir, ignore_errors=True)
|
||||
target_dir.mkdir(parents=True)
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
real_t = "double" if precision == "double" else "float"
|
||||
print("Built-in type config: " + real_t + "_" + bits)
|
||||
@@ -852,14 +751,14 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
|
||||
if "operators" in builtin_api:
|
||||
for operator in builtin_api["operators"]:
|
||||
if operator["name"] not in ["in", "xor"]:
|
||||
if is_valid_cpp_operator(operator["name"]):
|
||||
if "right_type" in operator:
|
||||
result.append(
|
||||
f'\t{correct_type(operator["return_type"])} operator{operator["name"]}({type_for_parameter(operator["right_type"])}p_other) const;'
|
||||
f'\t{correct_type(operator["return_type"])} operator{get_operator_cpp_name(operator["name"])}({type_for_parameter(operator["right_type"])}p_other) const;'
|
||||
)
|
||||
else:
|
||||
result.append(
|
||||
f'\t{correct_type(operator["return_type"])} operator{operator["name"].replace("unary", "")}() const;'
|
||||
f'\t{correct_type(operator["return_type"])} operator{get_operator_cpp_name(operator["name"])}() const;'
|
||||
)
|
||||
|
||||
# Copy assignment.
|
||||
@@ -1291,10 +1190,10 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
|
||||
|
||||
if "operators" in builtin_api:
|
||||
for operator in builtin_api["operators"]:
|
||||
if operator["name"] not in ["in", "xor"]:
|
||||
if is_valid_cpp_operator(operator["name"]):
|
||||
if "right_type" in operator:
|
||||
result.append(
|
||||
f'{correct_type(operator["return_type"])} {class_name}::operator{operator["name"]}({type_for_parameter(operator["right_type"])}p_other) const {{'
|
||||
f'{correct_type(operator["return_type"])} {class_name}::operator{get_operator_cpp_name(operator["name"])}({type_for_parameter(operator["right_type"])}p_other) const {{'
|
||||
)
|
||||
(encode, arg_name) = get_encoded_arg("other", operator["right_type"], None)
|
||||
result += encode
|
||||
@@ -1304,7 +1203,7 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
|
||||
result.append("}")
|
||||
else:
|
||||
result.append(
|
||||
f'{correct_type(operator["return_type"])} {class_name}::operator{operator["name"].replace("unary", "")}() const {{'
|
||||
f'{correct_type(operator["return_type"])} {class_name}::operator{get_operator_cpp_name(operator["name"])}() const {{'
|
||||
)
|
||||
result.append(
|
||||
f'\treturn internal::_call_builtin_operator_ptr<{get_gdextension_type(correct_type(operator["return_type"]))}>(_method_bindings.operator_{get_operator_id_name(operator["name"])}, (GDExtensionConstTypePtr)&opaque, (GDExtensionConstTypePtr)nullptr);'
|
||||
@@ -1692,6 +1591,16 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
||||
result.append(f"\t~{class_name}();")
|
||||
result.append("")
|
||||
|
||||
if class_name == "Object":
|
||||
result.append('\tString _to_string() const { return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; }')
|
||||
result.append("")
|
||||
|
||||
if class_name == "Node":
|
||||
result.append(
|
||||
'\tString _to_string() const { return (!get_name().is_empty() ? String(get_name()) + ":" : "") + Object::_to_string(); }'
|
||||
)
|
||||
result.append("")
|
||||
|
||||
result.append("public:")
|
||||
|
||||
# Special cases.
|
||||
@@ -2166,12 +2075,6 @@ def generate_utility_functions(api, output_dir):
|
||||
header.append("public:")
|
||||
|
||||
for function in api["utility_functions"]:
|
||||
if function["name"] == "is_instance_valid":
|
||||
# The `is_instance_valid()` function doesn't work as developers expect, and unless used very
|
||||
# carefully will cause crashes. Instead, developers should use `ObjectDB::get_instance()`
|
||||
# with object ids to ensure that an instance is still valid.
|
||||
continue
|
||||
|
||||
vararg = "is_vararg" in function and function["is_vararg"]
|
||||
|
||||
function_signature = "\t"
|
||||
@@ -2206,9 +2109,6 @@ def generate_utility_functions(api, output_dir):
|
||||
source.append("")
|
||||
|
||||
for function in api["utility_functions"]:
|
||||
if function["name"] == "is_instance_valid":
|
||||
continue
|
||||
|
||||
vararg = "is_vararg" in function and function["is_vararg"]
|
||||
|
||||
function_signature = make_signature("UtilityFunctions", function)
|
||||
@@ -2339,6 +2239,10 @@ def get_encoded_arg(arg_name, type_name, type_meta):
|
||||
result.append(f"\t{get_gdextension_type(arg_type)} {name}_encoded;")
|
||||
result.append(f"\tPtrToArg<{correct_type(type_name)}>::encode({name}, &{name}_encoded);")
|
||||
name = f"&{name}_encoded"
|
||||
elif is_enum(type_name) and not is_bitfield(type_name):
|
||||
result.append(f"\tint64_t {name}_encoded;")
|
||||
result.append(f"\tPtrToArg<int64_t>::encode({name}, &{name}_encoded);")
|
||||
name = f"&{name}_encoded"
|
||||
elif is_engine_class(type_name):
|
||||
# `{name}` is a C++ wrapper, it contains a field which is the object's pointer Godot expects.
|
||||
# We have to check `nullptr` because when the caller sends `nullptr`, the wrapper itself will be null.
|
||||
@@ -2655,20 +2559,6 @@ def is_refcounted(type_name):
|
||||
return type_name in engine_classes and engine_classes[type_name]
|
||||
|
||||
|
||||
def is_class_included(class_name, build_profile):
|
||||
"""
|
||||
Check if an engine class should be included.
|
||||
This removes classes according to a build profile of enabled or disabled classes.
|
||||
"""
|
||||
included = build_profile.get("enabled_classes", [])
|
||||
excluded = build_profile.get("disabled_classes", [])
|
||||
if included:
|
||||
return class_name in included
|
||||
if excluded:
|
||||
return class_name not in excluded
|
||||
return True
|
||||
|
||||
|
||||
def is_included(type_name, current_type):
|
||||
"""
|
||||
Check if a builtin type should be included.
|
||||
@@ -2719,8 +2609,8 @@ def correct_type(type_name, meta=None, use_alias=True):
|
||||
if meta is not None:
|
||||
if "int" in meta:
|
||||
return f"{meta}_t"
|
||||
elif meta in type_conversion:
|
||||
return type_conversion[type_name]
|
||||
elif "char" in meta:
|
||||
return f"{meta}_t"
|
||||
else:
|
||||
return meta
|
||||
if type_name in type_conversion:
|
||||
@@ -2832,6 +2722,38 @@ def get_operator_id_name(op):
|
||||
return op_id_map[op]
|
||||
|
||||
|
||||
def get_operator_cpp_name(op):
|
||||
op_cpp_map = {
|
||||
"==": "==",
|
||||
"!=": "!=",
|
||||
"<": "<",
|
||||
"<=": "<=",
|
||||
">": ">",
|
||||
">=": ">=",
|
||||
"+": "+",
|
||||
"-": "-",
|
||||
"*": "*",
|
||||
"/": "/",
|
||||
"unary-": "-",
|
||||
"unary+": "+",
|
||||
"%": "%",
|
||||
"<<": "<<",
|
||||
">>": ">>",
|
||||
"&": "&",
|
||||
"|": "|",
|
||||
"^": "^",
|
||||
"~": "~",
|
||||
"and": "&&",
|
||||
"or": "||",
|
||||
"not": "!",
|
||||
}
|
||||
return op_cpp_map[op]
|
||||
|
||||
|
||||
def is_valid_cpp_operator(op):
|
||||
return op not in ["**", "xor", "in"]
|
||||
|
||||
|
||||
def get_default_value_for_type(type_name):
|
||||
if type_name == "int":
|
||||
return "0"
|
||||
|
||||
183
build_profile.py
Normal file
183
build_profile.py
Normal file
@@ -0,0 +1,183 @@
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
||||
def parse_build_profile(profile_filepath, api):
|
||||
if profile_filepath == "":
|
||||
return {}
|
||||
|
||||
with open(profile_filepath, encoding="utf-8") as profile_file:
|
||||
profile = json.load(profile_file)
|
||||
|
||||
api_dict = {}
|
||||
parents = {}
|
||||
children = {}
|
||||
for engine_class in api["classes"]:
|
||||
api_dict[engine_class["name"]] = engine_class
|
||||
parent = engine_class.get("inherits", "")
|
||||
child = engine_class["name"]
|
||||
parents[child] = parent
|
||||
if parent == "":
|
||||
continue
|
||||
children[parent] = children.get(parent, [])
|
||||
children[parent].append(child)
|
||||
|
||||
included = []
|
||||
front = list(profile.get("enabled_classes", []))
|
||||
if front:
|
||||
# These must always be included
|
||||
front.append("WorkerThreadPool")
|
||||
front.append("ClassDB")
|
||||
front.append("ClassDBSingleton")
|
||||
# In src/classes/low_level.cpp
|
||||
front.append("FileAccess")
|
||||
front.append("Image")
|
||||
front.append("XMLParser")
|
||||
# In include/godot_cpp/templates/thread_work_pool.hpp
|
||||
front.append("Semaphore")
|
||||
while front:
|
||||
cls = front.pop()
|
||||
if cls in included:
|
||||
continue
|
||||
included.append(cls)
|
||||
parent = parents.get(cls, "")
|
||||
if parent:
|
||||
front.append(parent)
|
||||
|
||||
excluded = []
|
||||
front = list(profile.get("disabled_classes", []))
|
||||
while front:
|
||||
cls = front.pop()
|
||||
if cls in excluded:
|
||||
continue
|
||||
excluded.append(cls)
|
||||
front += children.get(cls, [])
|
||||
|
||||
if included and excluded:
|
||||
print(
|
||||
"WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
|
||||
)
|
||||
|
||||
return {
|
||||
"enabled_classes": included,
|
||||
"disabled_classes": excluded,
|
||||
}
|
||||
|
||||
|
||||
def generate_trimmed_api(source_api_filepath, profile_filepath):
|
||||
with open(source_api_filepath, encoding="utf-8") as api_file:
|
||||
api = json.load(api_file)
|
||||
|
||||
if profile_filepath == "":
|
||||
return api
|
||||
|
||||
build_profile = parse_build_profile(profile_filepath, api)
|
||||
|
||||
engine_classes = {}
|
||||
for class_api in api["classes"]:
|
||||
engine_classes[class_api["name"]] = class_api["is_refcounted"]
|
||||
for native_struct in api["native_structures"]:
|
||||
if native_struct["name"] == "ObjectID":
|
||||
continue
|
||||
engine_classes[native_struct["name"]] = False
|
||||
|
||||
classes = []
|
||||
for class_api in api["classes"]:
|
||||
if not is_class_included(class_api["name"], build_profile):
|
||||
continue
|
||||
if "methods" in class_api:
|
||||
methods = []
|
||||
for method in class_api["methods"]:
|
||||
if not is_method_included(method, build_profile, engine_classes):
|
||||
continue
|
||||
methods.append(method)
|
||||
class_api["methods"] = methods
|
||||
classes.append(class_api)
|
||||
api["classes"] = classes
|
||||
|
||||
return api
|
||||
|
||||
|
||||
def is_class_included(class_name, build_profile):
|
||||
"""
|
||||
Check if an engine class should be included.
|
||||
This removes classes according to a build profile of enabled or disabled classes.
|
||||
"""
|
||||
included = build_profile.get("enabled_classes", [])
|
||||
excluded = build_profile.get("disabled_classes", [])
|
||||
if included:
|
||||
return class_name in included
|
||||
if excluded:
|
||||
return class_name not in excluded
|
||||
return True
|
||||
|
||||
|
||||
def is_method_included(method, build_profile, engine_classes):
|
||||
"""
|
||||
Check if an engine class method should be included.
|
||||
This removes methods according to a build profile of enabled or disabled classes.
|
||||
"""
|
||||
included = build_profile.get("enabled_classes", [])
|
||||
excluded = build_profile.get("disabled_classes", [])
|
||||
ref_cls = set()
|
||||
rtype = get_base_type(method.get("return_value", {}).get("type", ""))
|
||||
args = [get_base_type(a["type"]) for a in method.get("arguments", [])]
|
||||
if rtype in engine_classes:
|
||||
ref_cls.add(rtype)
|
||||
elif is_enum(rtype) and get_enum_class(rtype) in engine_classes:
|
||||
ref_cls.add(get_enum_class(rtype))
|
||||
for arg in args:
|
||||
if arg in engine_classes:
|
||||
ref_cls.add(arg)
|
||||
elif is_enum(arg) and get_enum_class(arg) in engine_classes:
|
||||
ref_cls.add(get_enum_class(arg))
|
||||
for acls in ref_cls:
|
||||
if len(included) > 0 and acls not in included:
|
||||
return False
|
||||
elif len(excluded) > 0 and acls in excluded:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_enum(type_name):
|
||||
return type_name.startswith("enum::") or type_name.startswith("bitfield::")
|
||||
|
||||
|
||||
def get_enum_class(enum_name: str):
|
||||
if "." in enum_name:
|
||||
if is_bitfield(enum_name):
|
||||
return enum_name.replace("bitfield::", "").split(".")[0]
|
||||
else:
|
||||
return enum_name.replace("enum::", "").split(".")[0]
|
||||
else:
|
||||
return "GlobalConstants"
|
||||
|
||||
|
||||
def get_base_type(type_name):
|
||||
if type_name.startswith("const "):
|
||||
type_name = type_name[6:]
|
||||
if type_name.endswith("*"):
|
||||
type_name = type_name[:-1]
|
||||
if type_name.startswith("typedarray::"):
|
||||
type_name = type_name.replace("typedarray::", "")
|
||||
return type_name
|
||||
|
||||
|
||||
def is_bitfield(type_name):
|
||||
return type_name.startswith("bitfield::")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3 or len(sys.argv) > 4:
|
||||
print("Usage: %s BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]" % (sys.argv[0]))
|
||||
sys.exit(1)
|
||||
profile = sys.argv[1]
|
||||
infile = sys.argv[2]
|
||||
outfile = sys.argv[3] if len(sys.argv) > 3 else ""
|
||||
api = generate_trimmed_api(infile, profile)
|
||||
|
||||
if outfile:
|
||||
with open(outfile, "w", encoding="utf-8") as f:
|
||||
json.dump(api, f)
|
||||
else:
|
||||
json.dump(api, sys.stdout)
|
||||
@@ -89,6 +89,6 @@ function( set_warning_as_error )
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if ( GODOT_CPP_WARNING_AS_ERROR )
|
||||
if ( GODOT_WARNING_AS_ERROR )
|
||||
set_warning_as_error()
|
||||
endif()
|
||||
240
cmake/godotcpp.cmake
Normal file
240
cmake/godotcpp.cmake
Normal file
@@ -0,0 +1,240 @@
|
||||
function( godotcpp_options )
|
||||
|
||||
#TODO platform
|
||||
#TODO target
|
||||
|
||||
# Input from user for GDExtension interface header and the API JSON file
|
||||
set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH
|
||||
"Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" )
|
||||
set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH
|
||||
"Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) ( /path/to/custom_api_file )")
|
||||
|
||||
#TODO generate_bindings
|
||||
|
||||
option(GODOT_GENERATE_TEMPLATE_GET_NODE
|
||||
"Generate a template version of the Node class's get_node. (ON|OFF)" ON)
|
||||
|
||||
#TODO build_library
|
||||
|
||||
set(GODOT_PRECISION "single" CACHE STRING
|
||||
"Set the floating-point precision level (single|double)")
|
||||
|
||||
#TODO arch
|
||||
#TODO threads
|
||||
#TODO compiledb
|
||||
#TODO compiledb_file
|
||||
#TODO build_profile aka cmake preset
|
||||
|
||||
set(GODOT_USE_HOT_RELOAD "" CACHE BOOL
|
||||
"Enable the extra accounting required to support hot reload. (ON|OFF)")
|
||||
|
||||
option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON )
|
||||
|
||||
set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING
|
||||
"Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)")
|
||||
set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" )
|
||||
|
||||
#TODO optimize
|
||||
#TODO debug_symbols
|
||||
#TODO dev_build
|
||||
|
||||
# FIXME These options are not present in SCons, and perhaps should be added there.
|
||||
option(GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." ON)
|
||||
option(GODOT_WARNING_AS_ERROR "Treat warnings as errors" OFF)
|
||||
|
||||
# Run options commands on the following to populate cache for all platforms.
|
||||
# This type of thing is typically done conditionally
|
||||
# But as scons shows all options so shall we.
|
||||
#TODO ios_options()
|
||||
#TODO linux_options()
|
||||
#TODO macos_options()
|
||||
#TODO web_options()
|
||||
#TODO windows_options()
|
||||
endfunction()
|
||||
|
||||
|
||||
function( godotcpp_generate )
|
||||
# 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>" )
|
||||
|
||||
# CXX_VISIBILITY_PRESET supported values are: default, hidden, protected, and internal
|
||||
# which is inline with the gcc -fvisibility=
|
||||
# https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
|
||||
# To match the scons options we need to change the text to match the -fvisibility flag
|
||||
# it is probably worth another PR which changes both to use the flag options
|
||||
if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" )
|
||||
set( GODOT_SYMBOL_VISIBILITY "default" )
|
||||
endif ()
|
||||
|
||||
# Default build type is Debug in the SConstruct
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
# Hot reload is enabled by default in Debug-builds
|
||||
if( GODOT_USE_HOT_RELOAD STREQUAL "" AND NOT CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(GODOT_USE_HOT_RELOAD ON)
|
||||
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()
|
||||
|
||||
|
||||
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()
|
||||
|
||||
if ("${GODOT_PRECISION}" STREQUAL "double")
|
||||
add_definitions(-DREAL_T_IS_DOUBLE)
|
||||
endif()
|
||||
|
||||
set( GODOT_COMPILE_FLAGS )
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
||||
add_definitions(-DNOMINMAX)
|
||||
else() # GCC/Clang
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
endif()
|
||||
|
||||
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
|
||||
# saves around 20% of binary size and very significant build time (GH-80513).
|
||||
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(GODOT_GENERATE_TEMPLATE_GET_NODE)
|
||||
set(GENERATE_BINDING_PARAMETERS "True")
|
||||
else()
|
||||
set(GENERATE_BINDING_PARAMETERS "False")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GENERATED_FILES_LIST
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
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}\", \"${GODOT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")"
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py
|
||||
COMMENT "Generating bindings"
|
||||
)
|
||||
|
||||
# Get Sources
|
||||
# As this cmake file was added using 'include(godotcpp)' from the root CMakeLists.txt,
|
||||
# the ${CMAKE_CURRENT_SOURCE_DIR} is still the root dir.
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**)
|
||||
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**)
|
||||
|
||||
# Define our godot-cpp library
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
${SOURCES}
|
||||
${HEADERS}
|
||||
${GENERATED_FILES_LIST}
|
||||
)
|
||||
add_library(godot::cpp ALIAS ${PROJECT_NAME})
|
||||
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/common_compiler_flags.cmake)
|
||||
|
||||
target_compile_features(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
cxx_std_17
|
||||
)
|
||||
|
||||
if(GODOT_USE_HOT_RELOAD)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED)
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>)
|
||||
endif()
|
||||
|
||||
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_SYSTEM_HEADERS_ATTRIBUTE "")
|
||||
if (GODOT_SYSTEM_HEADERS)
|
||||
set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
|
||||
endif ()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
|
||||
include
|
||||
${CMAKE_CURRENT_BINARY_DIR}/gen/include
|
||||
${GODOT_GDEXTENSION_DIR}
|
||||
)
|
||||
|
||||
# Add the compile flags
|
||||
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
|
||||
|
||||
# Create the correct name (godot.os.build_type.system_bits)
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
|
||||
|
||||
if(ANDROID)
|
||||
# Added the android abi after system name
|
||||
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
|
||||
|
||||
# Android does not have the bits at the end if you look at the main godot repo build
|
||||
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
|
||||
else()
|
||||
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
CXX_EXTENSIONS OFF
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY}
|
||||
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}"
|
||||
)
|
||||
|
||||
endfunction()
|
||||
57
doc/cmake.md
Normal file
57
doc/cmake.md
Normal file
@@ -0,0 +1,57 @@
|
||||
## CMake
|
||||
|
||||
### 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_SYSTEM_HEADERS`: Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one.
|
||||
- `GODOT_WARNING_AS_ERROR`: Treat any warnings as errors
|
||||
- `GODOT_USE_HOT_RELOAD`: Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds.
|
||||
- `GODOT_CUSTOM_API_FILE`: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)
|
||||
- `GODOT_PRECISION`: Floating-point precision level ("single", "double")
|
||||
|
||||
### Android cmake arguments
|
||||
- `CMAKE_TOOLCHAIN_FILE`: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake)
|
||||
- `ANDROID_NDK`: The path to the android ndk root folder
|
||||
- `ANDROID_TOOLCHAIN_NAME`: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9)
|
||||
- `ANDROID_PLATFORM`: The android platform version (android-23)
|
||||
|
||||
- More info [here](https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html)
|
||||
|
||||
## Examples
|
||||
```shell
|
||||
Builds a debug version:
|
||||
cmake .
|
||||
cmake --build .
|
||||
```
|
||||
Builds a release version with clang
|
||||
|
||||
```shell
|
||||
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:
|
||||
|
||||
``` shell
|
||||
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:
|
||||
|
||||
```shell
|
||||
mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
|
||||
```
|
||||
|
||||
Ensure that you avoid exposing godot-cpp symbols - this might lead to hard to debug errors if you ever load multiple
|
||||
plugins using difference godot-cpp versions. Use visibility hidden whenever possible:
|
||||
```cmake
|
||||
set_target_properties(<all-my-plugin-related-targets> PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
```
|
||||
|
||||
## Todo
|
||||
Test build for Windows, Mac and mingw.
|
||||
@@ -230,7 +230,9 @@ template <typename 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>());
|
||||
if (unlikely(!p_ptr)) {
|
||||
return Ref<T>();
|
||||
}
|
||||
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
|
||||
}
|
||||
|
||||
@@ -254,7 +256,9 @@ struct PtrToArg<const Ref<T> &> {
|
||||
|
||||
_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>());
|
||||
if (unlikely(!p_ptr)) {
|
||||
return Ref<T>();
|
||||
}
|
||||
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -40,6 +40,14 @@
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#if defined(MACOS_ENABLED) && defined(HOT_RELOAD_ENABLED)
|
||||
#include <mutex>
|
||||
#define _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
#define _GODOT_CPP_THREAD_LOCAL
|
||||
#else
|
||||
#define _GODOT_CPP_THREAD_LOCAL thread_local
|
||||
#endif
|
||||
|
||||
namespace godot {
|
||||
|
||||
class ClassDB;
|
||||
@@ -58,8 +66,16 @@ class Wrapped {
|
||||
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
|
||||
friend _ALWAYS_INLINE_ void _pre_initialize();
|
||||
|
||||
thread_local static const StringName *_constructing_extension_class_name;
|
||||
thread_local static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
|
||||
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
static std::recursive_mutex _constructing_mutex;
|
||||
#endif
|
||||
|
||||
_GODOT_CPP_THREAD_LOCAL static const StringName *_constructing_extension_class_name;
|
||||
_GODOT_CPP_THREAD_LOCAL static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
|
||||
|
||||
#ifdef HOT_RELOAD_ENABLED
|
||||
_GODOT_CPP_THREAD_LOCAL static GDExtensionObjectPtr _constructing_recreate_owner;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
_ALWAYS_INLINE_ static void _set_construct_info() {
|
||||
@@ -71,15 +87,6 @@ protected:
|
||||
virtual bool _is_extension_class() const { return false; }
|
||||
static const StringName *_get_extension_class_name(); // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
|
||||
|
||||
#ifdef HOT_RELOAD_ENABLED
|
||||
struct RecreateInstance {
|
||||
GDExtensionClassInstancePtr wrapper;
|
||||
GDExtensionObjectPtr owner;
|
||||
RecreateInstance *next;
|
||||
};
|
||||
inline static RecreateInstance *recreate_instance = nullptr;
|
||||
#endif
|
||||
|
||||
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; }
|
||||
@@ -87,7 +94,7 @@ protected:
|
||||
bool _property_can_revert(const StringName &p_name) const { return false; }
|
||||
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }
|
||||
void _validate_property(PropertyInfo &p_property) const {}
|
||||
String _to_string() const { return "[" + String(get_class_static()) + ":" + itos(get_instance_id()) + "]"; }
|
||||
String _to_string() const { return "<Wrapped#0>"; }
|
||||
|
||||
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) {}
|
||||
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { return false; }
|
||||
@@ -116,16 +123,15 @@ public:
|
||||
return string_name;
|
||||
}
|
||||
|
||||
uint64_t get_instance_id() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Must be public but you should not touch this.
|
||||
GodotObject *_owner = nullptr;
|
||||
};
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
|
||||
_ALWAYS_INLINE_ void _pre_initialize() {
|
||||
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
Wrapped::_constructing_mutex.lock();
|
||||
#endif
|
||||
Wrapped::_set_construct_info<T>();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
#include <godot_cpp/core/method_bind.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/core/print_string.hpp>
|
||||
|
||||
#include <godot_cpp/classes/class_db_singleton.hpp>
|
||||
|
||||
@@ -129,9 +130,11 @@ private:
|
||||
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
|
||||
if constexpr (!std::is_abstract_v<T>) {
|
||||
#ifdef HOT_RELOAD_ENABLED
|
||||
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
std::lock_guard<std::recursive_mutex> lk(Wrapped::_constructing_mutex);
|
||||
#endif
|
||||
Wrapped::_constructing_recreate_owner = obj;
|
||||
T *new_instance = (T *)memalloc(sizeof(T));
|
||||
Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance };
|
||||
Wrapped::recreate_instance = &recreate_data;
|
||||
memnew_placement(new_instance, T);
|
||||
return new_instance;
|
||||
#else
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace godot {
|
||||
|
||||
#if !defined(GDE_EXPORT)
|
||||
#if defined(_WIN32)
|
||||
#define GDE_EXPORT __declspec(dllexport)
|
||||
@@ -72,10 +74,6 @@
|
||||
#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
|
||||
@@ -127,4 +125,10 @@ struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {};
|
||||
template <size_t... Is>
|
||||
struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
|
||||
|
||||
} //namespace godot
|
||||
|
||||
// To maintain compatibility an alias is defined outside the namespace.
|
||||
// Consider it deprecated.
|
||||
using real_t = godot::real_t;
|
||||
|
||||
#endif // GODOT_DEFS_HPP
|
||||
|
||||
@@ -56,10 +56,10 @@ O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, co
|
||||
|
||||
template <typename R, typename... Args>
|
||||
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
|
||||
R ret;
|
||||
typename PtrToArg<R>::EncodeT 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;
|
||||
return static_cast<R>(ret);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@@ -70,10 +70,10 @@ void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, c
|
||||
|
||||
template <typename R, typename... Args>
|
||||
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
|
||||
R ret;
|
||||
typename PtrToArg<R>::EncodeT ret;
|
||||
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
|
||||
func(&ret, mb_args.data(), mb_args.size());
|
||||
return ret;
|
||||
return static_cast<R>(ret);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
|
||||
@@ -48,14 +48,14 @@
|
||||
namespace godot {
|
||||
|
||||
class MethodBind {
|
||||
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
|
||||
StringName name;
|
||||
StringName instance_class;
|
||||
int argument_count = 0;
|
||||
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
|
||||
|
||||
bool _static = false;
|
||||
bool _is_const = false;
|
||||
bool _has_return = false;
|
||||
bool _const = false;
|
||||
bool _returns = false;
|
||||
bool _vararg = false;
|
||||
|
||||
std::vector<StringName> argument_names;
|
||||
@@ -63,20 +63,20 @@ class MethodBind {
|
||||
std::vector<Variant> default_arguments;
|
||||
|
||||
protected:
|
||||
void _set_const(bool p_const);
|
||||
void _set_static(bool p_static);
|
||||
void _set_returns(bool p_returns);
|
||||
void _set_vararg(bool p_vararg);
|
||||
virtual GDExtensionVariantType gen_argument_type(int p_arg) const = 0;
|
||||
virtual PropertyInfo gen_argument_type_info(int p_arg) const = 0;
|
||||
void generate_argument_types(int p_count);
|
||||
void set_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);
|
||||
void _generate_argument_types(int p_count);
|
||||
|
||||
void set_argument_count(int p_count) { argument_count = 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_ int get_default_argument_count() const { return (int)default_arguments.size(); }
|
||||
|
||||
_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);
|
||||
@@ -97,19 +97,6 @@ public:
|
||||
return default_arguments[idx];
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
|
||||
_FORCE_INLINE_ void set_instance_class(StringName p_class) { instance_class = p_class; }
|
||||
|
||||
_FORCE_INLINE_ int get_argument_count() const { return argument_count; }
|
||||
_FORCE_INLINE_ bool is_const() const { return _is_const; }
|
||||
_FORCE_INLINE_ bool is_static() const { return _static; }
|
||||
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
|
||||
_FORCE_INLINE_ bool has_return() const { return _has_return; }
|
||||
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDEXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDEXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDEXTENSION_METHOD_FLAG_STATIC : 0); }
|
||||
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
|
||||
void set_argument_names(const std::vector<StringName> &p_names);
|
||||
std::vector<StringName> get_argument_names() const;
|
||||
void set_default_arguments(const std::vector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
|
||||
|
||||
_FORCE_INLINE_ GDExtensionVariantType get_argument_type(int p_argument) const {
|
||||
ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, GDEXTENSION_VARIANT_TYPE_NIL);
|
||||
@@ -117,7 +104,6 @@ public:
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -128,6 +114,31 @@ public:
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
void set_argument_names(const std::vector<StringName> &p_names);
|
||||
std::vector<StringName> get_argument_names() const;
|
||||
|
||||
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
|
||||
|
||||
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
|
||||
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDEXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDEXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDEXTENSION_METHOD_FLAG_STATIC : 0); }
|
||||
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
|
||||
_FORCE_INLINE_ void set_instance_class(StringName p_class) { instance_class = p_class; }
|
||||
|
||||
_FORCE_INLINE_ int get_argument_count() const { return argument_count; }
|
||||
|
||||
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const = 0;
|
||||
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const = 0;
|
||||
|
||||
StringName get_name() const;
|
||||
void set_name(const StringName &p_name);
|
||||
_FORCE_INLINE_ bool is_const() const { return _const; }
|
||||
_FORCE_INLINE_ bool is_static() const { return _static; }
|
||||
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
|
||||
_FORCE_INLINE_ bool has_return() const { return _returns; }
|
||||
|
||||
void set_default_arguments(const std::vector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
|
||||
|
||||
std::vector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
|
||||
std::vector<GDExtensionClassMethodArgumentMetadata> vec;
|
||||
// First element is return value
|
||||
@@ -138,9 +149,6 @@ public:
|
||||
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);
|
||||
|
||||
@@ -182,8 +190,8 @@ public:
|
||||
const MethodInfo &p_method_info,
|
||||
bool p_return_nil_is_variant) :
|
||||
method(p_method) {
|
||||
set_vararg(true);
|
||||
set_const(true);
|
||||
_set_vararg(true);
|
||||
_set_const(true);
|
||||
set_argument_count(p_method_info.arguments.size());
|
||||
if (p_method_info.arguments.size()) {
|
||||
arguments = p_method_info.arguments;
|
||||
@@ -196,8 +204,8 @@ public:
|
||||
set_argument_names(names);
|
||||
}
|
||||
|
||||
generate_argument_types((int)p_method_info.arguments.size());
|
||||
set_return(should_returns);
|
||||
_generate_argument_types((int)p_method_info.arguments.size());
|
||||
_set_returns(should_returns);
|
||||
}
|
||||
|
||||
~MethodBindVarArgBase() {}
|
||||
@@ -334,7 +342,7 @@ public:
|
||||
|
||||
MethodBindT(void (MB_T::*p_method)(P...)) {
|
||||
method = p_method;
|
||||
generate_argument_types(sizeof...(P));
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
}
|
||||
};
|
||||
@@ -410,9 +418,9 @@ public:
|
||||
|
||||
MethodBindTC(void (MB_T::*p_method)(P...) const) {
|
||||
method = p_method;
|
||||
generate_argument_types(sizeof...(P));
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_const(true);
|
||||
_set_const(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -493,9 +501,9 @@ public:
|
||||
|
||||
MethodBindTR(R (MB_T::*p_method)(P...)) {
|
||||
method = p_method;
|
||||
generate_argument_types(sizeof...(P));
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_return(true);
|
||||
_set_returns(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -576,10 +584,10 @@ public:
|
||||
|
||||
MethodBindTRC(R (MB_T::*p_method)(P...) const) {
|
||||
method = p_method;
|
||||
generate_argument_types(sizeof...(P));
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_return(true);
|
||||
set_const(true);
|
||||
_set_returns(true);
|
||||
_set_const(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -648,9 +656,9 @@ public:
|
||||
|
||||
MethodBindTS(void (*p_function)(P...)) {
|
||||
function = p_function;
|
||||
generate_argument_types(sizeof...(P));
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_static(true);
|
||||
_set_static(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -717,10 +725,10 @@ public:
|
||||
|
||||
MethodBindTRS(R (*p_function)(P...)) {
|
||||
function = p_function;
|
||||
generate_argument_types(sizeof...(P));
|
||||
_generate_argument_types(sizeof...(P));
|
||||
set_argument_count(sizeof...(P));
|
||||
set_static(true);
|
||||
set_return(true);
|
||||
_set_static(true);
|
||||
_set_returns(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -122,6 +122,9 @@ MAKE_PTRARGCONV(uint16_t, int64_t);
|
||||
MAKE_PTRARGCONV(int16_t, int64_t);
|
||||
MAKE_PTRARGCONV(uint32_t, int64_t);
|
||||
MAKE_PTRARGCONV(int32_t, int64_t);
|
||||
MAKE_PTRARGCONV(char16_t, int64_t);
|
||||
MAKE_PTRARGCONV(char32_t, int64_t);
|
||||
MAKE_PTRARGCONV(wchar_t, int64_t);
|
||||
MAKE_PTRARG(int64_t);
|
||||
MAKE_PTRARG(uint64_t);
|
||||
// Float types
|
||||
|
||||
73
include/godot_cpp/core/print_string.hpp
Normal file
73
include/godot_cpp/core/print_string.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/**************************************************************************/
|
||||
/* print_string.hpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GODOT_PRINT_STRING_HPP
|
||||
#define GODOT_PRINT_STRING_HPP
|
||||
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
|
||||
namespace godot {
|
||||
inline void print_error(const Variant &p_variant) {
|
||||
UtilityFunctions::printerr(p_variant);
|
||||
}
|
||||
|
||||
inline void print_line(const Variant &p_variant) {
|
||||
UtilityFunctions::print(p_variant);
|
||||
}
|
||||
|
||||
inline void print_line_rich(const Variant &p_variant) {
|
||||
UtilityFunctions::print_rich(p_variant);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_error(const Variant &p_variant, Args... p_args) {
|
||||
UtilityFunctions::printerr(p_variant, p_args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_line(const Variant &p_variant, Args... p_args) {
|
||||
UtilityFunctions::print(p_variant, p_args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_line_rich(const Variant &p_variant, Args... p_args) {
|
||||
UtilityFunctions::print_rich(p_variant, p_args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void print_verbose(const Variant &p_variant, Args... p_args) {
|
||||
UtilityFunctions::print_verbose(p_variant, p_args...);
|
||||
}
|
||||
|
||||
bool is_print_verbose_enabled();
|
||||
|
||||
} // namespace godot
|
||||
|
||||
#endif // GODOT_PRINT_STRING_HPP
|
||||
@@ -397,16 +397,17 @@ MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
|
||||
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
|
||||
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
|
||||
MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
|
||||
MAKE_TYPED_ARRAY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
|
||||
/*
|
||||
MAKE_TYPED_ARRAY_INFO(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)
|
||||
MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
|
||||
*/
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
|
||||
_ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast<T>(0)) {
|
||||
set(p_value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace godot {
|
||||
|
||||
class Variant;
|
||||
|
||||
struct _NO_DISCARD_ AABB {
|
||||
struct [[nodiscard]] AABB {
|
||||
Vector3 position;
|
||||
Vector3 size;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct _NO_DISCARD_ Basis {
|
||||
struct [[nodiscard]] Basis {
|
||||
Vector3 rows[3] = {
|
||||
Vector3(1, 0, 0),
|
||||
Vector3(0, 1, 0),
|
||||
@@ -224,7 +224,7 @@ struct _NO_DISCARD_ Basis {
|
||||
|
||||
operator Quaternion() const { return get_quaternion(); }
|
||||
|
||||
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
|
||||
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
|
||||
|
||||
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); }
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
struct _NO_DISCARD_ Color {
|
||||
struct [[nodiscard]] Color {
|
||||
union {
|
||||
struct {
|
||||
float r;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace godot {
|
||||
|
||||
class Variant;
|
||||
|
||||
struct _NO_DISCARD_ Plane {
|
||||
struct [[nodiscard]] Plane {
|
||||
Vector3 normal;
|
||||
real_t d = 0;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ struct Rect2;
|
||||
struct Transform3D;
|
||||
struct Vector2;
|
||||
|
||||
struct _NO_DISCARD_ Projection {
|
||||
struct [[nodiscard]] Projection {
|
||||
enum Planes {
|
||||
PLANE_NEAR,
|
||||
PLANE_FAR,
|
||||
@@ -153,6 +153,7 @@ struct _NO_DISCARD_ Projection {
|
||||
|
||||
Projection();
|
||||
Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w);
|
||||
Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww);
|
||||
Projection(const Transform3D &p_transform);
|
||||
~Projection();
|
||||
};
|
||||
|
||||
@@ -31,12 +31,13 @@
|
||||
#ifndef GODOT_QUATERNION_HPP
|
||||
#define GODOT_QUATERNION_HPP
|
||||
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/core/math.hpp>
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct _NO_DISCARD_ Quaternion {
|
||||
struct [[nodiscard]] Quaternion {
|
||||
union {
|
||||
struct {
|
||||
real_t x;
|
||||
@@ -47,11 +48,11 @@ struct _NO_DISCARD_ Quaternion {
|
||||
real_t components[4] = { 0, 0, 0, 1.0 };
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ real_t &operator[](int idx) {
|
||||
return components[idx];
|
||||
_FORCE_INLINE_ real_t &operator[](int p_idx) {
|
||||
return components[p_idx];
|
||||
}
|
||||
_FORCE_INLINE_ const real_t &operator[](int idx) const {
|
||||
return components[idx];
|
||||
_FORCE_INLINE_ const real_t &operator[](int p_idx) const {
|
||||
return components[p_idx];
|
||||
}
|
||||
_FORCE_INLINE_ real_t length_squared() const;
|
||||
bool is_equal_approx(const Quaternion &p_quaternion) const;
|
||||
@@ -66,14 +67,13 @@ struct _NO_DISCARD_ Quaternion {
|
||||
_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(); }
|
||||
Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
|
||||
static Quaternion from_euler(const Vector3 &p_euler);
|
||||
|
||||
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;
|
||||
Quaternion slerp(const Quaternion &p_to, real_t p_weight) const;
|
||||
Quaternion slerpni(const Quaternion &p_to, real_t p_weight) const;
|
||||
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight) const;
|
||||
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const;
|
||||
|
||||
Vector3 get_axis() const;
|
||||
real_t get_angle() const;
|
||||
@@ -89,28 +89,28 @@ struct _NO_DISCARD_ Quaternion {
|
||||
void operator*=(const Quaternion &p_q);
|
||||
Quaternion operator*(const Quaternion &p_q) const;
|
||||
|
||||
_FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
|
||||
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_v) const {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), p_v, "The quaternion " + operator String() + " must be normalized.");
|
||||
#endif
|
||||
Vector3 u(x, y, z);
|
||||
Vector3 uv = u.cross(v);
|
||||
return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
|
||||
Vector3 uv = u.cross(p_v);
|
||||
return p_v + ((uv * w) + u.cross(uv)) * ((real_t)2);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
|
||||
return inverse().xform(v);
|
||||
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_v) const {
|
||||
return inverse().xform(p_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_ void operator*=(real_t p_s);
|
||||
_FORCE_INLINE_ void operator/=(real_t p_s);
|
||||
_FORCE_INLINE_ Quaternion operator+(const Quaternion &p_q2) const;
|
||||
_FORCE_INLINE_ Quaternion operator-(const Quaternion &p_q2) const;
|
||||
_FORCE_INLINE_ Quaternion operator-() const;
|
||||
_FORCE_INLINE_ Quaternion operator*(const real_t &s) const;
|
||||
_FORCE_INLINE_ Quaternion operator/(const real_t &s) const;
|
||||
_FORCE_INLINE_ Quaternion operator*(real_t p_s) const;
|
||||
_FORCE_INLINE_ Quaternion operator/(real_t p_s) const;
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const;
|
||||
_FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const;
|
||||
@@ -128,8 +128,6 @@ struct _NO_DISCARD_ Quaternion {
|
||||
|
||||
Quaternion(const Vector3 &p_axis, real_t p_angle);
|
||||
|
||||
Quaternion(const Vector3 &p_euler);
|
||||
|
||||
Quaternion(const Quaternion &p_q) :
|
||||
x(p_q.x),
|
||||
y(p_q.y),
|
||||
@@ -144,9 +142,9 @@ struct _NO_DISCARD_ Quaternion {
|
||||
w = p_q.w;
|
||||
}
|
||||
|
||||
Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
|
||||
Vector3 c = v0.cross(v1);
|
||||
real_t d = v0.dot(v1);
|
||||
Quaternion(const Vector3 &p_v0, const Vector3 &p_v1) { // Shortest arc.
|
||||
Vector3 c = p_v0.cross(p_v1);
|
||||
real_t d = p_v0.dot(p_v1);
|
||||
|
||||
if (d < -1.0f + (real_t)CMP_EPSILON) {
|
||||
x = 0;
|
||||
@@ -187,25 +185,25 @@ void Quaternion::operator-=(const Quaternion &p_q) {
|
||||
w -= p_q.w;
|
||||
}
|
||||
|
||||
void Quaternion::operator*=(const real_t &s) {
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
w *= s;
|
||||
void Quaternion::operator*=(real_t p_s) {
|
||||
x *= p_s;
|
||||
y *= p_s;
|
||||
z *= p_s;
|
||||
w *= p_s;
|
||||
}
|
||||
|
||||
void Quaternion::operator/=(const real_t &s) {
|
||||
*this *= 1.0f / s;
|
||||
void Quaternion::operator/=(real_t p_s) {
|
||||
*this *= 1.0f / p_s;
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator+(const Quaternion &q2) const {
|
||||
Quaternion Quaternion::operator+(const Quaternion &p_q2) const {
|
||||
const Quaternion &q1 = *this;
|
||||
return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
|
||||
return Quaternion(q1.x + p_q2.x, q1.y + p_q2.y, q1.z + p_q2.z, q1.w + p_q2.w);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator-(const Quaternion &q2) const {
|
||||
Quaternion Quaternion::operator-(const Quaternion &p_q2) const {
|
||||
const Quaternion &q1 = *this;
|
||||
return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
|
||||
return Quaternion(q1.x - p_q2.x, q1.y - p_q2.y, q1.z - p_q2.z, q1.w - p_q2.w);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator-() const {
|
||||
@@ -213,12 +211,12 @@ Quaternion Quaternion::operator-() const {
|
||||
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*(real_t p_s) const {
|
||||
return Quaternion(x * p_s, y * p_s, z * p_s, w * p_s);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator/(const real_t &s) const {
|
||||
return *this * (1.0f / s);
|
||||
Quaternion Quaternion::operator/(real_t p_s) const {
|
||||
return *this * (1.0f / p_s);
|
||||
}
|
||||
|
||||
bool Quaternion::operator==(const Quaternion &p_quaternion) const {
|
||||
@@ -229,7 +227,7 @@ bool Quaternion::operator!=(const Quaternion &p_quaternion) const {
|
||||
return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) {
|
||||
_FORCE_INLINE_ Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) {
|
||||
return p_quaternion * p_real;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class String;
|
||||
struct Rect2i;
|
||||
struct Transform2D;
|
||||
|
||||
struct _NO_DISCARD_ Rect2 {
|
||||
struct [[nodiscard]] Rect2 {
|
||||
Point2 position;
|
||||
Size2 size;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace godot {
|
||||
class String;
|
||||
struct Rect2;
|
||||
|
||||
struct _NO_DISCARD_ Rect2i {
|
||||
struct [[nodiscard]] Rect2i {
|
||||
Point2i position;
|
||||
Size2i size;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
struct _NO_DISCARD_ Transform2D {
|
||||
struct [[nodiscard]] 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])
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
struct _NO_DISCARD_ Transform3D {
|
||||
struct [[nodiscard]] Transform3D {
|
||||
Basis basis;
|
||||
Vector3 origin;
|
||||
|
||||
|
||||
@@ -327,8 +327,6 @@ public:
|
||||
bool booleanize() const;
|
||||
String stringify() const;
|
||||
Variant duplicate(bool deep = false) const;
|
||||
static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
|
||||
static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
|
||||
|
||||
static String get_type_name(Variant::Type type);
|
||||
static bool can_convert(Variant::Type from, Variant::Type to);
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace godot {
|
||||
class String;
|
||||
struct Vector2i;
|
||||
|
||||
struct _NO_DISCARD_ Vector2 {
|
||||
struct [[nodiscard]] Vector2 {
|
||||
static const int AXIS_COUNT = 2;
|
||||
|
||||
enum Axis {
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace godot {
|
||||
class String;
|
||||
struct Vector2;
|
||||
|
||||
struct _NO_DISCARD_ Vector2i {
|
||||
struct [[nodiscard]] Vector2i {
|
||||
static const int AXIS_COUNT = 2;
|
||||
|
||||
enum Axis {
|
||||
|
||||
@@ -41,7 +41,7 @@ struct Basis;
|
||||
struct Vector2;
|
||||
struct Vector3i;
|
||||
|
||||
struct _NO_DISCARD_ Vector3 {
|
||||
struct [[nodiscard]] Vector3 {
|
||||
static const int AXIS_COUNT = 3;
|
||||
|
||||
enum Axis {
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace godot {
|
||||
class String;
|
||||
struct Vector3;
|
||||
|
||||
struct _NO_DISCARD_ Vector3i {
|
||||
struct [[nodiscard]] Vector3i {
|
||||
static const int AXIS_COUNT = 3;
|
||||
|
||||
enum Axis {
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace godot {
|
||||
|
||||
class String;
|
||||
|
||||
struct _NO_DISCARD_ Vector4 {
|
||||
struct [[nodiscard]] Vector4 {
|
||||
static const int AXIS_COUNT = 4;
|
||||
|
||||
enum Axis {
|
||||
@@ -55,16 +55,17 @@ struct _NO_DISCARD_ Vector4 {
|
||||
real_t z;
|
||||
real_t w;
|
||||
};
|
||||
real_t components[4] = { 0, 0, 0, 0 };
|
||||
[[deprecated("Use coord instead")]] real_t components[4];
|
||||
real_t coord[4] = { 0, 0, 0, 0 };
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ real_t &operator[](const int p_axis) {
|
||||
DEV_ASSERT((unsigned int)p_axis < 4);
|
||||
return components[p_axis];
|
||||
return coord[p_axis];
|
||||
}
|
||||
_FORCE_INLINE_ const real_t &operator[](const int p_axis) const {
|
||||
DEV_ASSERT((unsigned int)p_axis < 4);
|
||||
return components[p_axis];
|
||||
return coord[p_axis];
|
||||
}
|
||||
|
||||
Vector4::Axis min_axis_index() const;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace godot {
|
||||
class String;
|
||||
struct Vector4;
|
||||
|
||||
struct _NO_DISCARD_ Vector4i {
|
||||
struct [[nodiscard]] Vector4i {
|
||||
static const int AXIS_COUNT = 4;
|
||||
|
||||
enum Axis {
|
||||
|
||||
@@ -6,26 +6,41 @@ from pathlib import Path
|
||||
|
||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
|
||||
from binding_generator import generate_bindings, get_file_list
|
||||
from binding_generator import _generate_bindings, _get_file_list
|
||||
from build_profile import generate_trimmed_api
|
||||
|
||||
api_filepath = "gdextension/extension_api.json"
|
||||
bits = "64"
|
||||
precision = "single"
|
||||
output_dir = "self_test"
|
||||
|
||||
generate_bindings(api_filepath, use_template_get_node=False, bits=bits, precision=precision, output_dir=output_dir)
|
||||
flist = get_file_list(api_filepath, output_dir, headers=True, sources=True)
|
||||
|
||||
p = Path(output_dir) / "gen"
|
||||
allfiles = [str(f.as_posix()) for f in p.glob("**/*.*")]
|
||||
missing = list(filter((lambda f: f not in flist), allfiles))
|
||||
extras = list(filter((lambda f: f not in allfiles), flist))
|
||||
if len(missing) > 0 or len(extras) > 0:
|
||||
print("Error!")
|
||||
for f in missing:
|
||||
print("MISSING: " + str(f))
|
||||
for f in extras:
|
||||
print("EXTRA: " + str(f))
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("OK!")
|
||||
def test(profile_filepath=""):
|
||||
api = generate_trimmed_api(api_filepath, profile_filepath)
|
||||
_generate_bindings(
|
||||
api,
|
||||
api_filepath,
|
||||
use_template_get_node=False,
|
||||
bits=bits,
|
||||
precision=precision,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
flist = _get_file_list(api, output_dir, headers=True, sources=True)
|
||||
|
||||
p = Path(output_dir) / "gen"
|
||||
allfiles = [str(f.as_posix()) for f in p.glob("**/*.*")]
|
||||
missing = list(filter((lambda f: f not in flist), allfiles))
|
||||
extras = list(filter((lambda f: f not in allfiles), flist))
|
||||
if len(missing) > 0 or len(extras) > 0:
|
||||
print("Error!")
|
||||
for f in missing:
|
||||
print("MISSING: " + str(f))
|
||||
for f in extras:
|
||||
print("EXTRA: " + str(f))
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("OK!")
|
||||
|
||||
|
||||
test()
|
||||
test("test/build_profile.json")
|
||||
|
||||
@@ -39,14 +39,27 @@
|
||||
#include <godot_cpp/core/class_db.hpp>
|
||||
|
||||
namespace godot {
|
||||
thread_local const StringName *Wrapped::_constructing_extension_class_name = nullptr;
|
||||
thread_local const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr;
|
||||
|
||||
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
std::recursive_mutex Wrapped::_constructing_mutex;
|
||||
#endif
|
||||
|
||||
_GODOT_CPP_THREAD_LOCAL const StringName *Wrapped::_constructing_extension_class_name = nullptr;
|
||||
_GODOT_CPP_THREAD_LOCAL const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr;
|
||||
|
||||
#ifdef HOT_RELOAD_ENABLED
|
||||
_GODOT_CPP_THREAD_LOCAL GDExtensionObjectPtr Wrapped::_constructing_recreate_owner = nullptr;
|
||||
#endif
|
||||
|
||||
const StringName *Wrapped::_get_extension_class_name() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Wrapped::_postinitialize() {
|
||||
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
|
||||
Wrapped::_constructing_mutex.unlock();
|
||||
#endif
|
||||
|
||||
// Only send NOTIFICATION_POSTINITIALIZE for extension classes.
|
||||
if (_is_extension_class()) {
|
||||
_notificationv(Object::NOTIFICATION_POSTINITIALIZE);
|
||||
@@ -55,25 +68,14 @@ void Wrapped::_postinitialize() {
|
||||
|
||||
Wrapped::Wrapped(const StringName p_godot_class) {
|
||||
#ifdef HOT_RELOAD_ENABLED
|
||||
if (unlikely(Wrapped::recreate_instance)) {
|
||||
RecreateInstance *recreate_data = Wrapped::recreate_instance;
|
||||
RecreateInstance *previous = nullptr;
|
||||
while (recreate_data) {
|
||||
if (recreate_data->wrapper == this) {
|
||||
_owner = recreate_data->owner;
|
||||
if (previous) {
|
||||
previous->next = recreate_data->next;
|
||||
} else {
|
||||
Wrapped::recreate_instance = recreate_data->next;
|
||||
}
|
||||
return;
|
||||
}
|
||||
previous = recreate_data;
|
||||
recreate_data = recreate_data->next;
|
||||
}
|
||||
}
|
||||
if (unlikely(Wrapped::_constructing_recreate_owner)) {
|
||||
_owner = Wrapped::_constructing_recreate_owner;
|
||||
Wrapped::_constructing_recreate_owner = nullptr;
|
||||
} else
|
||||
#endif
|
||||
_owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
|
||||
{
|
||||
_owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
|
||||
}
|
||||
|
||||
if (_constructing_extension_class_name) {
|
||||
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(_constructing_extension_class_name), this);
|
||||
|
||||
@@ -353,9 +353,14 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
|
||||
if (mi.argument_count > 0) {
|
||||
mi.arguments = (GDExtensionPropertyInfo *)memalloc(sizeof(GDExtensionPropertyInfo) * mi.argument_count);
|
||||
mi.arguments_metadata = (GDExtensionClassMethodArgumentMetadata *)memalloc(sizeof(GDExtensionClassMethodArgumentMetadata) * mi.argument_count);
|
||||
if (mi.argument_count != p_method.arguments_metadata.size()) {
|
||||
WARN_PRINT("Mismatch argument metadata count for virtual method: " + String(p_class) + "::" + p_method.name);
|
||||
}
|
||||
for (uint32_t i = 0; i < mi.argument_count; i++) {
|
||||
mi.arguments[i] = p_method.arguments[i]._to_gdextension();
|
||||
mi.arguments_metadata[i] = p_method.arguments_metadata[i];
|
||||
if (i < p_method.arguments_metadata.size()) {
|
||||
mi.arguments_metadata[i] = p_method.arguments_metadata[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mi.arguments = nullptr;
|
||||
@@ -384,7 +389,7 @@ void ClassDB::initialize_class(const ClassInfo &p_cl) {
|
||||
}
|
||||
|
||||
void ClassDB::initialize(GDExtensionInitializationLevel p_level) {
|
||||
for (const std::pair<StringName, ClassInfo> pair : classes) {
|
||||
for (const std::pair<const StringName, ClassInfo> &pair : classes) {
|
||||
const ClassInfo &cl = pair.second;
|
||||
if (cl.level != p_level) {
|
||||
continue;
|
||||
|
||||
@@ -32,6 +32,22 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
void MethodBind::_set_const(bool p_const) {
|
||||
_const = p_const;
|
||||
}
|
||||
|
||||
void MethodBind::_set_static(bool p_static) {
|
||||
_static = p_static;
|
||||
}
|
||||
|
||||
void MethodBind::_set_returns(bool p_returns) {
|
||||
_returns = p_returns;
|
||||
}
|
||||
|
||||
void MethodBind::_set_vararg(bool p_vararg) {
|
||||
_vararg = p_vararg;
|
||||
}
|
||||
|
||||
StringName MethodBind::get_name() const {
|
||||
return name;
|
||||
}
|
||||
@@ -40,26 +56,6 @@ void MethodBind::set_name(const StringName &p_name) {
|
||||
name = p_name;
|
||||
}
|
||||
|
||||
void MethodBind::set_argument_count(int p_count) {
|
||||
argument_count = p_count;
|
||||
}
|
||||
|
||||
void MethodBind::set_const(bool p_const) {
|
||||
_is_const = p_const;
|
||||
}
|
||||
|
||||
void MethodBind::set_return(bool p_return) {
|
||||
_has_return = p_return;
|
||||
}
|
||||
|
||||
void MethodBind::set_static(bool p_static) {
|
||||
_static = p_static;
|
||||
}
|
||||
|
||||
void MethodBind::set_vararg(bool p_vararg) {
|
||||
_vararg = p_vararg;
|
||||
}
|
||||
|
||||
void MethodBind::set_argument_names(const std::vector<StringName> &p_names) {
|
||||
argument_names = p_names;
|
||||
}
|
||||
@@ -68,7 +64,7 @@ std::vector<StringName> MethodBind::get_argument_names() const {
|
||||
return argument_names;
|
||||
}
|
||||
|
||||
void MethodBind::generate_argument_types(int p_count) {
|
||||
void MethodBind::_generate_argument_types(int p_count) {
|
||||
set_argument_count(p_count);
|
||||
|
||||
if (argument_types != nullptr) {
|
||||
|
||||
39
src/core/print_string.cpp
Normal file
39
src/core/print_string.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/**************************************************************************/
|
||||
/* print_string.cpp */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include <godot_cpp/core/print_string.hpp>
|
||||
|
||||
#include <godot_cpp/classes/os.hpp>
|
||||
|
||||
namespace godot {
|
||||
bool is_print_verbose_enabled() {
|
||||
return OS::get_singleton()->is_stdout_verbose();
|
||||
}
|
||||
} // namespace godot
|
||||
@@ -1037,12 +1037,15 @@ void Basis::rotate_sh(real_t *p_values) {
|
||||
p_values[8] = d4 * s_scale_dst4;
|
||||
}
|
||||
|
||||
Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) {
|
||||
Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(p_target.is_zero_approx(), Basis(), "The target vector can't be zero.");
|
||||
ERR_FAIL_COND_V_MSG(p_up.is_zero_approx(), Basis(), "The up vector can't be zero.");
|
||||
#endif
|
||||
Vector3 v_z = -p_target.normalized();
|
||||
Vector3 v_z = p_target.normalized();
|
||||
if (!p_use_model_front) {
|
||||
v_z = -v_z;
|
||||
}
|
||||
Vector3 v_x = p_up.cross(v_z);
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other.");
|
||||
|
||||
@@ -913,6 +913,13 @@ Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_
|
||||
columns[3] = p_w;
|
||||
}
|
||||
|
||||
Projection::Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww) {
|
||||
columns[0] = Vector4(p_xx, p_xy, p_xz, p_xw);
|
||||
columns[1] = Vector4(p_yx, p_yy, p_yz, p_yw);
|
||||
columns[2] = Vector4(p_zx, p_zy, p_zz, p_zw);
|
||||
columns[3] = Vector4(p_wx, p_wy, p_wz, p_ww);
|
||||
}
|
||||
|
||||
Projection::Projection(const Transform3D &p_transform) {
|
||||
const Transform3D &tr = p_transform;
|
||||
real_t *m = &columns[0][0];
|
||||
|
||||
@@ -37,28 +37,15 @@ namespace godot {
|
||||
|
||||
real_t Quaternion::angle_to(const Quaternion &p_to) const {
|
||||
real_t d = dot(p_to);
|
||||
return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
|
||||
// acos does clamping.
|
||||
return Math::acos(d * d * 2 - 1);
|
||||
}
|
||||
|
||||
// get_euler_xyz returns a vector containing the Euler angles in the format
|
||||
// (ax,ay,az), where ax is the angle of rotation around x axis,
|
||||
// and similar for other axes.
|
||||
// This implementation uses XYZ convention (Z is the first rotation).
|
||||
Vector3 Quaternion::get_euler_xyz() const {
|
||||
Basis m(*this);
|
||||
return m.get_euler(EULER_ORDER_XYZ);
|
||||
}
|
||||
|
||||
// get_euler_yxz returns a vector containing the Euler angles in the format
|
||||
// (ax,ay,az), where ax is the angle of rotation around x axis,
|
||||
// and similar for other axes.
|
||||
// This implementation uses YXZ convention (Z is the first rotation).
|
||||
Vector3 Quaternion::get_euler_yxz() const {
|
||||
Vector3 Quaternion::get_euler(EulerOrder p_order) const {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion " + operator String() + " must be normalized.");
|
||||
#endif
|
||||
Basis m(*this);
|
||||
return m.get_euler(EULER_ORDER_YXZ);
|
||||
return Basis(*this).get_euler(p_order);
|
||||
}
|
||||
|
||||
void Quaternion::operator*=(const Quaternion &p_q) {
|
||||
@@ -103,7 +90,7 @@ bool Quaternion::is_normalized() const {
|
||||
|
||||
Quaternion Quaternion::inverse() const {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion " + operator String() + " must be normalized.");
|
||||
#endif
|
||||
return Quaternion(-x, -y, -z, w);
|
||||
}
|
||||
@@ -125,10 +112,10 @@ Quaternion Quaternion::exp() const {
|
||||
return Quaternion(src_v, theta);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
|
||||
Quaternion Quaternion::slerp(const Quaternion &p_to, real_t p_weight) const {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion " + operator String() + " must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion " + p_to.operator String() + " must be normalized.");
|
||||
#endif
|
||||
Quaternion to1;
|
||||
real_t omega, cosom, sinom, scale0, scale1;
|
||||
@@ -166,10 +153,10 @@ Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) con
|
||||
scale0 * w + scale1 * to1.w);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) const {
|
||||
Quaternion Quaternion::slerpni(const Quaternion &p_to, real_t p_weight) const {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion " + operator String() + " must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion " + p_to.operator String() + " must be normalized.");
|
||||
#endif
|
||||
const Quaternion &from = *this;
|
||||
|
||||
@@ -190,10 +177,10 @@ Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) c
|
||||
invFactor * from.w + newFactor * p_to.w);
|
||||
}
|
||||
|
||||
Quaternion 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 Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight) const {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion " + operator String() + " must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion " + p_b.operator String() + " must be normalized.");
|
||||
#endif
|
||||
Quaternion from_q = *this;
|
||||
Quaternion pre_q = p_pre_a;
|
||||
@@ -236,15 +223,15 @@ Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const
|
||||
ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight);
|
||||
Quaternion q2 = to_q * ln.exp();
|
||||
|
||||
// To cancel error made by Expmap ambiguity, do blends.
|
||||
// To cancel error made by Expmap ambiguity, do blending.
|
||||
return q1.slerp(q2, p_weight);
|
||||
}
|
||||
|
||||
Quaternion 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 {
|
||||
Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight,
|
||||
real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion " + operator String() + " must be normalized.");
|
||||
ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion " + p_b.operator String() + " must be normalized.");
|
||||
#endif
|
||||
Quaternion from_q = *this;
|
||||
Quaternion pre_q = p_pre_a;
|
||||
@@ -287,7 +274,7 @@ Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b
|
||||
ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
|
||||
Quaternion q2 = to_q * ln.exp();
|
||||
|
||||
// To cancel error made by Expmap ambiguity, do blends.
|
||||
// To cancel error made by Expmap ambiguity, do blending.
|
||||
return q1.slerp(q2, p_weight);
|
||||
}
|
||||
|
||||
@@ -309,7 +296,7 @@ real_t Quaternion::get_angle() const {
|
||||
|
||||
Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
|
||||
#ifdef MATH_CHECKS
|
||||
ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized.");
|
||||
ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 " + p_axis.operator String() + " must be normalized.");
|
||||
#endif
|
||||
real_t d = p_axis.length();
|
||||
if (d == 0) {
|
||||
@@ -332,7 +319,7 @@ Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
|
||||
// (ax, ay, az), where ax is the angle of rotation around x axis,
|
||||
// and similar for other axes.
|
||||
// This implementation uses YXZ convention (Z is the first rotation).
|
||||
Quaternion::Quaternion(const Vector3 &p_euler) {
|
||||
Quaternion Quaternion::from_euler(const Vector3 &p_euler) {
|
||||
real_t half_a1 = p_euler.y * 0.5f;
|
||||
real_t half_a2 = p_euler.x * 0.5f;
|
||||
real_t half_a3 = p_euler.z * 0.5f;
|
||||
@@ -348,10 +335,11 @@ Quaternion::Quaternion(const Vector3 &p_euler) {
|
||||
real_t cos_a3 = Math::cos(half_a3);
|
||||
real_t sin_a3 = Math::sin(half_a3);
|
||||
|
||||
x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3;
|
||||
y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3;
|
||||
z = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3;
|
||||
w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
|
||||
return Quaternion(
|
||||
sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3,
|
||||
sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3,
|
||||
-sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3,
|
||||
sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3);
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
@@ -42,4 +42,5 @@ else:
|
||||
source=sources,
|
||||
)
|
||||
|
||||
env.NoCache(library)
|
||||
Default(library)
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"enabled_classes": [
|
||||
"Control",
|
||||
"InputEventKey",
|
||||
"Label",
|
||||
"MultiplayerAPI",
|
||||
"MultiplayerPeer",
|
||||
"OS",
|
||||
"TileMap",
|
||||
"InputEventKey"
|
||||
"TileSet",
|
||||
"Viewport"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ func _ready():
|
||||
|
||||
# To string.
|
||||
assert_equal(example.to_string(),'[ GDExtension::Example <--> Instance ID:%s ]' % example.get_instance_id())
|
||||
# It appears there's a bug with instance ids :-(
|
||||
#assert_equal($Example/ExampleMin.to_string(), 'ExampleMin:[Wrapped:%s]' % $Example/ExampleMin.get_instance_id())
|
||||
assert_equal($Example/ExampleMin.to_string(), 'ExampleMin:<ExampleMin#%s>' % $Example/ExampleMin.get_instance_id())
|
||||
|
||||
# Call static methods.
|
||||
assert_equal(Example.test_static(9, 100), 109);
|
||||
@@ -270,6 +269,12 @@ func _ready():
|
||||
assert_equal(example_child.get_value1(), 11)
|
||||
assert_equal(example_child.get_value2(), 22)
|
||||
|
||||
# Test that the extension's library path is absolute and valid.
|
||||
var library_path = Example.test_library_path()
|
||||
assert_equal(library_path.begins_with("res://"), false)
|
||||
assert_equal(library_path, ProjectSettings.globalize_path(library_path))
|
||||
assert_equal(FileAccess.file_exists(library_path), true)
|
||||
|
||||
exit_with_status()
|
||||
|
||||
func _on_Example_custom_signal(signal_name, value):
|
||||
|
||||
@@ -204,6 +204,7 @@ void Example::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("test_str_utility"), &Example::test_str_utility);
|
||||
ClassDB::bind_method(D_METHOD("test_string_is_forty_two"), &Example::test_string_is_forty_two);
|
||||
ClassDB::bind_method(D_METHOD("test_string_resize"), &Example::test_string_resize);
|
||||
ClassDB::bind_method(D_METHOD("test_typed_array_of_packed"), &Example::test_typed_array_of_packed);
|
||||
ClassDB::bind_method(D_METHOD("test_vector_ops"), &Example::test_vector_ops);
|
||||
ClassDB::bind_method(D_METHOD("test_vector_init_list"), &Example::test_vector_init_list);
|
||||
|
||||
@@ -248,6 +249,8 @@ void Example::_bind_methods() {
|
||||
ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static);
|
||||
ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2);
|
||||
|
||||
ClassDB::bind_static_method("Example", D_METHOD("test_library_path"), &Example::test_library_path);
|
||||
|
||||
{
|
||||
MethodInfo mi;
|
||||
mi.arguments.push_back(PropertyInfo(Variant::STRING, "some_argument"));
|
||||
@@ -424,6 +427,19 @@ String Example::test_string_resize(String p_string) const {
|
||||
return p_string;
|
||||
}
|
||||
|
||||
TypedArray<PackedInt32Array> Example::test_typed_array_of_packed() const {
|
||||
TypedArray<PackedInt32Array> arr;
|
||||
PackedInt32Array packed_arr1;
|
||||
packed_arr1.push_back(1);
|
||||
packed_arr1.push_back(2);
|
||||
arr.push_back(packed_arr1);
|
||||
PackedInt32Array packed_arr2;
|
||||
packed_arr2.push_back(3);
|
||||
packed_arr2.push_back(4);
|
||||
arr.push_back(packed_arr2);
|
||||
return arr;
|
||||
}
|
||||
|
||||
int Example::test_vector_ops() const {
|
||||
PackedInt32Array arr;
|
||||
arr.push_back(10);
|
||||
@@ -695,6 +711,12 @@ String Example::test_use_engine_singleton() const {
|
||||
return OS::get_singleton()->get_name();
|
||||
}
|
||||
|
||||
String Example::test_library_path() {
|
||||
String library_path;
|
||||
internal::gdextension_interface_get_library_path(internal::library, library_path._native_ptr());
|
||||
return library_path;
|
||||
}
|
||||
|
||||
void ExampleRuntime::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_prop_value", "value"), &ExampleRuntime::set_prop_value);
|
||||
ClassDB::bind_method(D_METHOD("get_prop_value"), &ExampleRuntime::get_prop_value);
|
||||
|
||||
@@ -134,6 +134,7 @@ public:
|
||||
String test_str_utility() const;
|
||||
bool test_string_is_forty_two(const String &p_str) const;
|
||||
String test_string_resize(String p_original) const;
|
||||
TypedArray<PackedInt32Array> test_typed_array_of_packed() const;
|
||||
int test_vector_ops() const;
|
||||
int test_vector_init_list() const;
|
||||
|
||||
@@ -194,6 +195,8 @@ public:
|
||||
GDVIRTUAL1(_do_something_virtual_with_control, Control *);
|
||||
|
||||
String test_use_engine_singleton() const;
|
||||
|
||||
static String test_library_path();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(Example::Constants);
|
||||
|
||||
@@ -11,6 +11,11 @@ def options(opts):
|
||||
"Target Android API level",
|
||||
"21",
|
||||
)
|
||||
opts.Add(
|
||||
"ndk_version",
|
||||
"Fully qualified version of ndk to use for compilation.",
|
||||
"23.2.8568313",
|
||||
)
|
||||
opts.Add(
|
||||
"ANDROID_HOME",
|
||||
"Path to your Android SDK installation. By default, uses ANDROID_HOME from your defined environment variables.",
|
||||
@@ -22,14 +27,9 @@ def exists(env):
|
||||
return get_android_ndk_root(env) is not None
|
||||
|
||||
|
||||
# This must be kept in sync with the value in https://github.com/godotengine/godot/blob/master/platform/android/detect.py#L58.
|
||||
def get_ndk_version():
|
||||
return "23.2.8568313"
|
||||
|
||||
|
||||
def get_android_ndk_root(env):
|
||||
if env["ANDROID_HOME"]:
|
||||
return env["ANDROID_HOME"] + "/ndk/" + get_ndk_version()
|
||||
return env["ANDROID_HOME"] + "/ndk/" + env["ndk_version"]
|
||||
else:
|
||||
return os.environ.get("ANDROID_NDK_ROOT")
|
||||
|
||||
@@ -68,7 +68,7 @@ def generate(env):
|
||||
|
||||
if not os.path.exists(toolchain):
|
||||
print("ERROR: Could not find NDK toolchain at " + toolchain + ".")
|
||||
print("Make sure NDK version " + get_ndk_version() + " is installed.")
|
||||
print("Make sure NDK version " + env["ndk_version"] + " is installed.")
|
||||
env.Exit(1)
|
||||
|
||||
env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways
|
||||
@@ -120,4 +120,9 @@ def generate(env):
|
||||
|
||||
env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
# Refer to https://github.com/godotengine/godot/blob/master/platform/android/detect.py
|
||||
# LTO benefits for Android (size, performance) haven't been clearly established yet.
|
||||
if env["lto"] == "auto":
|
||||
env["lto"] = "none"
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
@@ -22,6 +22,10 @@ def exists(env):
|
||||
|
||||
|
||||
def generate(env):
|
||||
assert env["lto"] in ["thin", "full", "none"], "Unrecognized lto: {}".format(env["lto"])
|
||||
if env["lto"] != "none":
|
||||
print("Using LTO: " + env["lto"])
|
||||
|
||||
# Require C++17
|
||||
if env.get("is_msvc", False):
|
||||
env.Append(CXXFLAGS=["/std:c++17"])
|
||||
@@ -64,6 +68,22 @@ def generate(env):
|
||||
env.Append(LINKFLAGS=["/OPT:REF"])
|
||||
elif env["optimize"] == "debug" or env["optimize"] == "none":
|
||||
env.Append(CCFLAGS=["/Od"])
|
||||
|
||||
if env["lto"] == "thin":
|
||||
if not env["use_llvm"]:
|
||||
print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
|
||||
env.Exit(255)
|
||||
|
||||
env.Append(CCFLAGS=["-flto=thin"])
|
||||
env.Append(LINKFLAGS=["-flto=thin"])
|
||||
elif env["lto"] == "full":
|
||||
if env["use_llvm"]:
|
||||
env.Append(CCFLAGS=["-flto"])
|
||||
env.Append(LINKFLAGS=["-flto"])
|
||||
else:
|
||||
env.AppendUnique(CCFLAGS=["/GL"])
|
||||
env.AppendUnique(ARFLAGS=["/LTCG"])
|
||||
env.AppendUnique(LINKFLAGS=["/LTCG"])
|
||||
else:
|
||||
if env["debug_symbols"]:
|
||||
# Adding dwarf-4 explicitly makes stacktraces work with clang builds,
|
||||
@@ -74,7 +94,7 @@ def generate(env):
|
||||
else:
|
||||
env.Append(CCFLAGS=["-g2"])
|
||||
else:
|
||||
if using_clang(env) and not is_vanilla_clang(env):
|
||||
if using_clang(env) and not is_vanilla_clang(env) and not env["use_mingw"]:
|
||||
# Apple Clang, its linker doesn't like -s.
|
||||
env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
|
||||
else:
|
||||
@@ -91,3 +111,13 @@ def generate(env):
|
||||
env.Append(CCFLAGS=["-Og"])
|
||||
elif env["optimize"] == "none":
|
||||
env.Append(CCFLAGS=["-O0"])
|
||||
|
||||
if env["lto"] == "thin":
|
||||
if (env["platform"] == "windows" or env["platform"] == "linux") and not env["use_llvm"]:
|
||||
print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
|
||||
env.Exit(255)
|
||||
env.Append(CCFLAGS=["-flto=thin"])
|
||||
env.Append(LINKFLAGS=["-flto=thin"])
|
||||
elif env["lto"] == "full":
|
||||
env.Append(CCFLAGS=["-flto"])
|
||||
env.Append(LINKFLAGS=["-flto"])
|
||||
|
||||
@@ -2,6 +2,7 @@ import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
from SCons import __version__ as scons_raw_version
|
||||
from SCons.Action import Action
|
||||
from SCons.Builder import Builder
|
||||
from SCons.Errors import UserError
|
||||
@@ -10,7 +11,8 @@ from SCons.Tool import Tool
|
||||
from SCons.Variables import BoolVariable, EnumVariable, PathVariable
|
||||
from SCons.Variables.BoolVariable import _text2bool
|
||||
|
||||
from binding_generator import scons_emit_files, scons_generate_bindings
|
||||
from binding_generator import _generate_bindings, _get_file_list, get_file_list
|
||||
from build_profile import generate_trimmed_api
|
||||
|
||||
|
||||
def add_sources(sources, dir, extension):
|
||||
@@ -129,6 +131,38 @@ def no_verbose(env):
|
||||
env.Append(GENCOMSTR=[generated_file_message])
|
||||
|
||||
|
||||
def scons_emit_files(target, source, env):
|
||||
profile_filepath = env.get("build_profile", "")
|
||||
if profile_filepath:
|
||||
profile_filepath = normalize_path(profile_filepath, env)
|
||||
|
||||
# Always clean all files
|
||||
env.Clean(target, [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True)])
|
||||
|
||||
api = generate_trimmed_api(str(source[0]), profile_filepath)
|
||||
files = [env.File(f) for f in _get_file_list(api, target[0].abspath, True, True)]
|
||||
env["godot_cpp_gen_dir"] = target[0].abspath
|
||||
return files, source
|
||||
|
||||
|
||||
def scons_generate_bindings(target, source, env):
|
||||
profile_filepath = env.get("build_profile", "")
|
||||
if profile_filepath:
|
||||
profile_filepath = normalize_path(profile_filepath, env)
|
||||
|
||||
api = generate_trimmed_api(str(source[0]), profile_filepath)
|
||||
|
||||
_generate_bindings(
|
||||
api,
|
||||
str(source[0]),
|
||||
env["generate_template_get_node"],
|
||||
"32" if "32" in env["arch"] else "64",
|
||||
env["precision"],
|
||||
env["godot_cpp_gen_dir"],
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
platforms = ["linux", "macos", "windows", "android", "ios", "web"]
|
||||
|
||||
# CPU architecture options.
|
||||
@@ -326,6 +360,14 @@ def options(opts, env):
|
||||
("none", "custom", "debug", "speed", "speed_trace", "size"),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
"lto",
|
||||
"Link-time optimization",
|
||||
"none",
|
||||
("none", "auto", "thin", "full"),
|
||||
)
|
||||
)
|
||||
opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", True))
|
||||
opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
|
||||
opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
|
||||
@@ -383,6 +425,8 @@ def make_doc_source(target, source, env):
|
||||
|
||||
|
||||
def generate(env):
|
||||
env.scons_version = env._get_major_minor_revision(scons_raw_version)
|
||||
|
||||
# Default num_jobs to local cpu count if not user specified.
|
||||
# SCons has a peculiarity where user-specified options won't be overridden
|
||||
# by SetOption, so we can rely on this to know if we should use our default.
|
||||
@@ -440,6 +484,17 @@ def generate(env):
|
||||
else: # Release
|
||||
opt_level = "speed"
|
||||
|
||||
# Allow marking includes as external/system to avoid raising warnings.
|
||||
if env.scons_version < (4, 2):
|
||||
env["_CPPEXTINCFLAGS"] = "${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}"
|
||||
else:
|
||||
env["_CPPEXTINCFLAGS"] = (
|
||||
"${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}"
|
||||
)
|
||||
env["CPPEXTPATH"] = []
|
||||
env["EXTINCPREFIX"] = "-isystem "
|
||||
env["EXTINCSUFFIX"] = ""
|
||||
|
||||
env["optimize"] = ARGUMENTS.get("optimize", opt_level)
|
||||
env["debug_symbols"] = get_cmdline_bool("debug_symbols", env.dev_build)
|
||||
|
||||
@@ -552,6 +607,7 @@ def _godot_cpp(env):
|
||||
|
||||
if env["build_library"]:
|
||||
library = env.StaticLibrary(target=env.File("bin/%s" % library_name), source=sources)
|
||||
env.NoCache(library)
|
||||
default_args = [library]
|
||||
|
||||
# Add compiledb if the option is set
|
||||
|
||||
@@ -36,9 +36,11 @@ def generate(env):
|
||||
if env["ios_simulator"]:
|
||||
sdk_name = "iphonesimulator"
|
||||
env.Append(CCFLAGS=["-mios-simulator-version-min=" + env["ios_min_version"]])
|
||||
env.Append(LINKFLAGS=["-mios-simulator-version-min=" + env["ios_min_version"]])
|
||||
else:
|
||||
sdk_name = "iphoneos"
|
||||
env.Append(CCFLAGS=["-miphoneos-version-min=" + env["ios_min_version"]])
|
||||
env.Append(LINKFLAGS=["-miphoneos-version-min=" + env["ios_min_version"]])
|
||||
|
||||
if sys.platform == "darwin":
|
||||
if env["IOS_SDK_PATH"] == "":
|
||||
@@ -97,4 +99,9 @@ def generate(env):
|
||||
|
||||
env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
# Refer to https://github.com/godotengine/godot/blob/master/platform/ios/detect.py:
|
||||
# Disable by default as it makes linking in Xcode very slow.
|
||||
if env["lto"] == "auto":
|
||||
env["lto"] = "none"
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
@@ -39,4 +39,8 @@ def generate(env):
|
||||
|
||||
env.Append(CPPDEFINES=["LINUX_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
# Refer to https://github.com/godotengine/godot/blob/master/platform/linuxbsd/detect.py
|
||||
if env["lto"] == "auto":
|
||||
env["lto"] = "full"
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
@@ -73,4 +73,9 @@ def generate(env):
|
||||
|
||||
env.Append(CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
# Refer to https://github.com/godotengine/godot/blob/master/platform/macos/detect.py
|
||||
# LTO benefits for macOS (size, performance) haven't been clearly established yet.
|
||||
if env["lto"] == "auto":
|
||||
env["lto"] = "none"
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
10
tools/web.py
10
tools/web.py
@@ -39,13 +39,21 @@ def generate(env):
|
||||
env.Append(LINKFLAGS=["-sUSE_PTHREADS=1"])
|
||||
|
||||
# Build as side module (shared library).
|
||||
env.Append(CPPFLAGS=["-sSIDE_MODULE=1"])
|
||||
env.Append(CCFLAGS=["-sSIDE_MODULE=1"])
|
||||
env.Append(LINKFLAGS=["-sSIDE_MODULE=1"])
|
||||
|
||||
# Enable WebAssembly BigInt <-> i64 conversion.
|
||||
# This must match the flag used to build Godot (true in official builds since 4.3)
|
||||
env.Append(LINKFLAGS=["-sWASM_BIGINT"])
|
||||
|
||||
# Force wasm longjmp mode.
|
||||
env.Append(CCFLAGS=["-sSUPPORT_LONGJMP='wasm'"])
|
||||
env.Append(LINKFLAGS=["-sSUPPORT_LONGJMP='wasm'"])
|
||||
|
||||
env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
# Refer to https://github.com/godotengine/godot/blob/master/platform/web/detect.py
|
||||
if env["lto"] == "auto":
|
||||
env["lto"] = "full"
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import common_compiler_flags
|
||||
@@ -72,10 +73,13 @@ def silence_msvc(env):
|
||||
|
||||
|
||||
def options(opts):
|
||||
mingw = os.getenv("MINGW_PREFIX", "")
|
||||
|
||||
opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler instead of MSVC - only effective on Windows", False))
|
||||
opts.Add(BoolVariable("use_clang_cl", "Use the clang driver instead of MSVC - only effective on Windows", False))
|
||||
opts.Add(BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True))
|
||||
opts.Add(BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting errors to stderr.", True))
|
||||
opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag)", False))
|
||||
opts.Add("mingw_prefix", "MinGW prefix", mingw)
|
||||
|
||||
|
||||
def exists(env):
|
||||
@@ -86,12 +90,22 @@ def generate(env):
|
||||
if not env["use_mingw"] and msvc.exists(env):
|
||||
if env["arch"] == "x86_64":
|
||||
env["TARGET_ARCH"] = "amd64"
|
||||
elif env["arch"] == "arm64":
|
||||
env["TARGET_ARCH"] = "arm64"
|
||||
elif env["arch"] == "arm32":
|
||||
env["TARGET_ARCH"] = "arm"
|
||||
elif env["arch"] == "x86_32":
|
||||
env["TARGET_ARCH"] = "x86"
|
||||
|
||||
env["MSVC_SETUP_RUN"] = False # Need to set this to re-run the tool
|
||||
env["MSVS_VERSION"] = None
|
||||
env["MSVC_VERSION"] = None
|
||||
|
||||
env["is_msvc"] = True
|
||||
|
||||
# MSVC, linker, and archiver.
|
||||
msvc.generate(env)
|
||||
env.Tool("msvc")
|
||||
env.Tool("mslib")
|
||||
env.Tool("mslink")
|
||||
|
||||
@@ -99,7 +113,7 @@ def generate(env):
|
||||
env.Append(CCFLAGS=["/utf-8"])
|
||||
env.Append(LINKFLAGS=["/WX"])
|
||||
|
||||
if env["use_clang_cl"]:
|
||||
if env["use_llvm"]:
|
||||
env["CC"] = "clang-cl"
|
||||
env["CXX"] = "clang-cl"
|
||||
|
||||
@@ -111,7 +125,12 @@ def generate(env):
|
||||
if env["silence_msvc"] and not env.GetOption("clean"):
|
||||
silence_msvc(env)
|
||||
|
||||
elif sys.platform == "win32" or sys.platform == "msys":
|
||||
if not env["use_llvm"]:
|
||||
env.AppendUnique(CCFLAGS=["/experimental:external", "/external:anglebrackets"])
|
||||
env.AppendUnique(CCFLAGS=["/external:W0"])
|
||||
env["EXTINCPREFIX"] = "/external:I"
|
||||
|
||||
elif (sys.platform == "win32" or sys.platform == "msys") and not env["mingw_prefix"]:
|
||||
env["use_mingw"] = True
|
||||
mingw.generate(env)
|
||||
# Don't want lib prefixes
|
||||
@@ -137,12 +156,32 @@ def generate(env):
|
||||
else:
|
||||
env["use_mingw"] = True
|
||||
# Cross-compilation using MinGW
|
||||
prefix = "i686" if env["arch"] == "x86_32" else env["arch"]
|
||||
env["CXX"] = prefix + "-w64-mingw32-g++"
|
||||
env["CC"] = prefix + "-w64-mingw32-gcc"
|
||||
env["AR"] = prefix + "-w64-mingw32-ar"
|
||||
env["RANLIB"] = prefix + "-w64-mingw32-ranlib"
|
||||
env["LINK"] = prefix + "-w64-mingw32-g++"
|
||||
prefix = ""
|
||||
if env["mingw_prefix"]:
|
||||
prefix = env["mingw_prefix"] + "/bin/"
|
||||
|
||||
if env["arch"] == "x86_64":
|
||||
prefix += "x86_64"
|
||||
elif env["arch"] == "arm64":
|
||||
prefix += "aarch64"
|
||||
elif env["arch"] == "arm32":
|
||||
prefix += "armv7"
|
||||
elif env["arch"] == "x86_32":
|
||||
prefix += "i686"
|
||||
|
||||
if env["use_llvm"]:
|
||||
env["CXX"] = prefix + "-w64-mingw32-clang++"
|
||||
env["CC"] = prefix + "-w64-mingw32-clang"
|
||||
env["AR"] = prefix + "-w64-mingw32-llvm-ar"
|
||||
env["RANLIB"] = prefix + "-w64-mingw32-ranlib"
|
||||
env["LINK"] = prefix + "-w64-mingw32-clang"
|
||||
else:
|
||||
env["CXX"] = prefix + "-w64-mingw32-g++"
|
||||
env["CC"] = prefix + "-w64-mingw32-gcc"
|
||||
env["AR"] = prefix + "-w64-mingw32-gcc-ar"
|
||||
env["RANLIB"] = prefix + "-w64-mingw32-ranlib"
|
||||
env["LINK"] = prefix + "-w64-mingw32-g++"
|
||||
|
||||
# Want dll suffix
|
||||
env["SHLIBSUFFIX"] = ".dll"
|
||||
|
||||
@@ -156,7 +195,20 @@ def generate(env):
|
||||
"-static-libstdc++",
|
||||
]
|
||||
)
|
||||
if env["use_llvm"]:
|
||||
env.Append(LINKFLAGS=["-lstdc++"])
|
||||
|
||||
if sys.platform == "win32" or sys.platform == "msys":
|
||||
my_spawn.configure(env)
|
||||
|
||||
env.Append(CPPDEFINES=["WINDOWS_ENABLED"])
|
||||
|
||||
# Refer to https://github.com/godotengine/godot/blob/master/platform/windows/detect.py
|
||||
if env["lto"] == "auto":
|
||||
if env.get("is_msvc", False):
|
||||
# No LTO by default for MSVC, doesn't help.
|
||||
env["lto"] = "none"
|
||||
else: # Release
|
||||
env["lto"] = "full"
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
Reference in New Issue
Block a user