From fd983459de154505a35b05bcd85f24b92a24b1e4 Mon Sep 17 00:00:00 2001 From: DmitriySalnikov Date: Sun, 7 Jan 2024 15:24:55 +0300 Subject: [PATCH] Fixed macOS support. ScopeConfig data is now stored separately to avoid creating new copies of Ref<>. Extended description of DebugDraw3DScopeConfig. Added a CI action to test API integration into the engine. Added `.framework` folder generation for macOS. Changed the way to get Godot executables. Now cache and downloading directly from the Godot repository is used. Updated version to 1.3.1. --- .../actions/compile_gdextension/action.yml | 12 +- .github/actions/delete_artifact/action.yml | 31 --- .github/actions/setup_godot/action.yml | 135 +++++++++++ .github/workflows/gdextension_build.yml | 91 +++++++- .github/workflows/util_update_libs.yml | 2 +- .github/workflows/web_deploy.yml | 91 ++++---- .gitignore | 3 + addons/debug_draw_3d/README.md | 9 +- .../debug_draw_3d/debug_draw_3d.gdextension | 27 ++- dd3d_web_build/headless_test.tscn | 68 ++++++ lib_utils.py | 210 ++++++++++++------ src/3d/config_scope_3d.cpp | 26 ++- src/3d/config_scope_3d.h | 52 ++++- src/3d/debug_draw_3d.cpp | 70 +++--- src/3d/debug_draw_3d.h | 13 +- src/common/i_scope_storage.h | 5 +- src/debug_draw_manager.cpp | 10 +- src/version.h | 2 +- 18 files changed, 631 insertions(+), 226 deletions(-) delete mode 100644 .github/actions/delete_artifact/action.yml create mode 100644 .github/actions/setup_godot/action.yml create mode 100644 dd3d_web_build/headless_test.tscn diff --git a/.github/actions/compile_gdextension/action.yml b/.github/actions/compile_gdextension/action.yml index 116e9d49..e591c8e7 100644 --- a/.github/actions/compile_gdextension/action.yml +++ b/.github/actions/compile_gdextension/action.yml @@ -33,7 +33,7 @@ inputs: description: Secrets token telemetry_version: description: Telemetry version - default: 2ed8ace3201d466c0bac4f0d40f05d2ec85a6bd3 + default: 999c64d0e0fc4c51f64130728eec33805721f4aa runs: using: composite steps: @@ -116,9 +116,13 @@ runs: shell: bash run: | if [ "$RUNNER_OS" == "macOS" ]; then - strip -u $(find -L ${{inputs.output_libs_path}} -type f) + found_files=$(find -L ${{inputs.output_libs_path}} -type f -exec file {} + | grep "Mach-O universal" | cut -d: -f1) + echo "Found files: $found_files" + strip -u $found_files else - strip $(find -L ${{inputs.output_libs_path}} -type f) + found_files=$(find -L ${{inputs.output_libs_path}} -type f -exec file {} + | grep "ELF" | cut -d: -f1) + echo "Found files: $found_files" + strip $found_files fi - name: Prepare artifact Windows @@ -135,7 +139,7 @@ runs: path: ${{inputs.output_libs_path}}/* - name: Save .scons_cache directory - if: ${{!steps.restore_scons_cache.outputs.cache-hit && inputs.use_cache != 'false'}} + if: inputs.use_cache != 'false' uses: actions/cache/save@v3 with: path: ${{env.SCONS_CACHE}} diff --git a/.github/actions/delete_artifact/action.yml b/.github/actions/delete_artifact/action.yml deleted file mode 100644 index 6c5cabee..00000000 --- a/.github/actions/delete_artifact/action.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Delete the artifact if it exists -description: Delete an artifact by its name if it exists. 'actions/upload-artifact@v4' usually removes artifacts itself when restarting jobs. -inputs: - artifact: - description: Any name of artifact - required: true -runs: - using: composite - steps: - - name: Delete `${{inputs.artifact}}` - shell: bash - continue-on-error: true - run: | - res=$(gh api \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/${{github.repository}}/actions/runs/${{github.run_id}}/artifacts?name="${{inputs.artifact}}") - - artifact_id=$(echo "$res" | jq -r 'if .total_count > 0 then .artifacts[0].id else 0 end') - - if [ "$artifact_id" == "0" ]; then - echo "No artifact to remove was found." - else - echo "Found the artifact ID $artifact_id for the ${{inputs.artifact}}." - gh api \ - --method DELETE \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/${{github.repository}}/actions/artifacts/$artifact_id - echo "The artifact with the ID $artifact_id has been removed." - fi diff --git a/.github/actions/setup_godot/action.yml b/.github/actions/setup_godot/action.yml new file mode 100644 index 00000000..5c6944ce --- /dev/null +++ b/.github/actions/setup_godot/action.yml @@ -0,0 +1,135 @@ +name: Download Godot Engine +description: Download Godot Engine executable and +inputs: + tag: + description: Release tag in the official repository (4.2.1-stable, 4.1.3-stable, 4.1-stable) + required: true + file_suffix: + description: The name of the file to download. + required: true + download_export_templates: + description: Whether export templates need to be downloaded (true|false). + default: "false" + required: false + is_mono: + description: Whether Godot and export templates support dotnet (true|false). + default: "false" + required: false +outputs: + godot_folder: + description: Path to the Godot executable file + value: ${{steps.store_folder.outputs.path}} + godot: + description: Path to the Godot executable file + value: ${{steps.store_folder.outputs.exe}} +runs: + using: composite + steps: + - name: Store Godot folder + id: store_folder + env: + temp: ${{runner.temp}} + shell: bash + run: | + tmp_path="${{env.temp}}" + tmp_path_unix="${{env.temp}}" + if [ "${{runner.os}}" == "Windows" ]; then + tmp_path_unix=$(cygpath -u "${{env.temp}}") + echo "Fixed path: $tmp_path_unix" + fi + + echo "path=$tmp_path/godot_installation" >> $GITHUB_OUTPUT + echo "path_unix=$tmp_path_unix/godot_installation" >> $GITHUB_OUTPUT + + if [[ "${{inputs.file_suffix}}" == *"macos"* ]]; then + echo "exe=$tmp_path_unix/godot_installation/Godot.app/Contents/MacOS/Godot" >> $GITHUB_OUTPUT + else + echo "exe=$tmp_path_unix/godot_installation/godot" >> $GITHUB_OUTPUT + fi + + - name: Restore cache directory + id: restore_scons_cache + uses: actions/cache/restore@v3 + with: + path: ${{steps.store_folder.outputs.path}} + key: godot-${{inputs.tag}}-${{inputs.file_suffix}}${{inputs.download_export_templates == 'true' && '-with_exports' || ''}} + + - name: Download Godot Engine + uses: robinraju/release-downloader@v1.8 + if: ${{!steps.restore_scons_cache.outputs.cache-hit}} + with: + repository: "godotengine/godot" + tag: "${{inputs.tag}}" + fileName: "*${{inputs.file_suffix}}" + out-file-path: "temp_download" + extract: true + + - name: Download templates + uses: robinraju/release-downloader@v1.8 + if: ${{!steps.restore_scons_cache.outputs.cache-hit && inputs.download_export_templates == 'true'}} + with: + repository: "godotengine/godot" + tag: "${{inputs.tag}}" + fileName: "*${{inputs.tag}}${{inputs.is_mono == 'true' && '_mono' || ''}}_export_templates.tpz" + out-file-path: "temp_download" + + - name: Finish preparation + if: ${{!steps.restore_scons_cache.outputs.cache-hit}} + shell: bash + run: | + if [ "${{inputs.is_mono}}" == "true" ]; then + echo "Move the Mono files to the root of the temporary folder" + mv -f Godot*/* temp_download/ || true + mv -f godot*/* temp_download/ || true + fi + + echo "Unzip templates" + if [ "${{inputs.download_export_templates}}" == "true" ]; then + templates_dir="temp_download/editor_data/export_templates" + mkdir -p $templates_dir + unzip temp_download/*_export_templates.tpz -d $templates_dir + version=$(cat $templates_dir/templates/version.txt) + mv $templates_dir/templates $templates_dir/$version + fi + + echo "Remove archives" + rm -rf temp_download/*.zip + rm -rf temp_download/*.tpz + + # Get files + files=$(find temp_download/ -mindepth 1 -maxdepth 1 -type f) + echo "Found files:" + echo ${files[@]} + + # Rename everything to godot.. + for file in $files; do + folder_basename=$(basename "$file") + if [[ "$folder_basename" == *"_console.exe" ]]; then + mv -f $file temp_download/godot_console.exe + elif [[ "$folder_basename" == *".exe" ]]; then + mv -f $file temp_download/godot.exe + elif [[ "$folder_basename" == "Godot"* || "$folder_basename" == "godot"* ]]; then + mv -f $file temp_download/godot + # Fix permissions on Unix + chmod +x temp_download/godot + fi + done + + echo "Move files to installation folder" + mv -f temp_download/ ${{steps.store_folder.outputs.path_unix}}/ + touch ${{steps.store_folder.outputs.path_unix}}/._sc_ + + echo "Final folder structure:" + find ${{steps.store_folder.outputs.path_unix}} -mindepth 1 + + if [[ "${{steps.store_folder.outputs.exe}}" == *"Godot.app"* ]]; then + echo "Fix permissions on macOS" + chmod 755 "${{steps.store_folder.outputs.exe}}" + fi + + - name: Save cache directory + if: ${{!steps.restore_scons_cache.outputs.cache-hit}} + uses: actions/cache/save@v3 + with: + path: ${{steps.store_folder.outputs.path}} + key: godot-${{inputs.tag}}-${{inputs.file_suffix}}${{inputs.download_export_templates == 'true' && '-with_exports' || ''}} diff --git a/.github/workflows/gdextension_build.yml b/.github/workflows/gdextension_build.yml index 784d8efb..3a1d7e42 100644 --- a/.github/workflows/gdextension_build.yml +++ b/.github/workflows/gdextension_build.yml @@ -229,6 +229,8 @@ jobs: ] name: ๐Ÿ“ฆ Collect GDExtension binaries runs-on: ubuntu-latest + outputs: + artifact_name: ${{steps.output_info.outputs.artifact_name}} steps: - name: Checkout @@ -242,19 +244,102 @@ jobs: - name: Store all libraries in one directory run: | - ls -R extracted_files/ + arch_dirs=$(find extracted_files/ -mindepth 1 -maxdepth 1 -type d) + echo "Original structure:" + find extracted_files -mindepth 1 mv -f extracted_files/**/* extracted_files - rm -rf extracted_files/**/ + rm -rf $arch_dirs + echo "Final structure:" + find extracted_files -mindepth 1 touch extracted_files/.gdignore - name: Output file information + id: output_info run: | cd extracted_files echo "Total size: $(du -ch -b | grep total | cut -f1 | awk '{printf "%.2f", $1/1048576}') MB, Total number of files: $(find . -type f | wc -l)" >> $GITHUB_STEP_SUMMARY + echo "artifact_name=${{env.PRODUCTION_BUILD == 'true' && '.gdextension_libs_production' || '.gdextension_libs'}}" >> $GITHUB_OUTPUT + - name: Upload GDExtension uses: actions/upload-artifact@v4 with: - name: ${{env.PRODUCTION_BUILD == 'true' && '.gdextension_libs_production' || '.gdextension_libs'}} + name: ${{steps.output_info.outputs.artifact_name}} retention-days: 7 path: extracted_files/* + + # ============================================ + + test_api_integration: + name: "๐Ÿงช Testing API: ${{matrix.runner-os}}, Godot-${{matrix.file_suffix}}" + runs-on: ${{matrix.runner-os}} + needs: collect-gdextension + + strategy: + fail-fast: false + matrix: + # sync with other jobs + runner-os: [ubuntu-20.04, macos-latest, windows-latest] + include: + - runner-os: ubuntu-20.04 + file_suffix: "stable_linux.x86_64.zip" + - runner-os: macos-latest + file_suffix: "stable_macos.universal.zip" + - runner-os: windows-latest + file_suffix: "stable_win64.exe.zip" + + env: + # Sync with container: image: + GODOT_VERSION: 4.2.1-stable + PROJECT_PATH: dd3d_web_build + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + lfs: true + + - name: Delete old libs folder + shell: bash + run: | + rm -rf addons/debug_draw_3d/libs + + - name: Download Binaries + uses: actions/download-artifact@v4 + with: + path: addons/debug_draw_3d/libs + name: ${{needs.collect-gdextension.outputs.artifact_name}} + + - name: Prepare Test Project + shell: bash + run: | + cp -r addons ${{env.PROJECT_PATH}}/addons + cp -r examples_dd3d ${{env.PROJECT_PATH}}/examples_dd3d + find ${{env.PROJECT_PATH}} -mindepth 1 + + - name: Setup Godot + uses: ./.github/actions/setup_godot + id: setup_godot + with: + tag: ${{env.GODOT_VERSION}} + file_suffix: ${{matrix.file_suffix}} + download_export_templates: false + is_mono: false + + - name: Import Assets + shell: bash + run: ${{steps.setup_godot.outputs.godot}} -v -e --headless --path ${{env.PROJECT_PATH}} --quit || true + + - name: Test Run + shell: bash + timeout-minutes: 2 + run: | + ${{steps.setup_godot.outputs.godot}} -v --headless --path ${{env.PROJECT_PATH}} res://headless_test.tscn || true + + - name: Check Results + shell: bash + run: | + if [ ! -f "${{env.PROJECT_PATH}}/SUCCESS" ]; then + echo "The file reporting success has not been created! Failed." + exit 1 + fi diff --git a/.github/workflows/util_update_libs.yml b/.github/workflows/util_update_libs.yml index 6c0f5eab..f184b014 100644 --- a/.github/workflows/util_update_libs.yml +++ b/.github/workflows/util_update_libs.yml @@ -31,7 +31,7 @@ jobs: - name: Replace with new files shell: bash run: | - ls -R extracted_files + find extracted_files -mindepth 1 rm -rf ${{env.ADDON_LIBS_PATH}}/ mv -f extracted_files ${{env.ADDON_LIBS_PATH}} diff --git a/.github/workflows/web_deploy.yml b/.github/workflows/web_deploy.yml index f2dd4d49..535a3aed 100644 --- a/.github/workflows/web_deploy.yml +++ b/.github/workflows/web_deploy.yml @@ -9,8 +9,8 @@ on: workflow_call: workflow_dispatch: inputs: - dev_deploy: - description: Dev deploy + production_build: + description: Production build default: true type: boolean @@ -33,7 +33,7 @@ concurrency: env: PAGES_BRANCH: gh-pages - DEV_DEPLOY: ${{!format('{0}', inputs.dev_deploy) && 'true' || format('{0}', inputs.dev_deploy)}} # Default true + DEV_DEPLOY: ${{!format('{0}', inputs.production_build) && 'true' || format('{0}', !inputs.production_build)}} # Default true GH_TOKEN: ${{github.token}} jobs: @@ -43,6 +43,7 @@ jobs: outputs: head_sha: ${{steps.get_sha.outputs.head_sha}} lib_version: ${{steps.get_lib_version.outputs.version}} + deploy_version: ${{steps.get_lib_version.outputs.deploy_version}} domain: ${{steps.get_domain.outputs.domain}} steps: @@ -77,6 +78,8 @@ jobs: - name: Get library version id: get_lib_version shell: bash + env: + REF: ${{github.ref_name}} run: | # Get DD3D version source_file="current/src/version.h" @@ -88,7 +91,18 @@ jobs: version_string="$major.$minor.$patch" echo "version=$version_string" >> $GITHUB_OUTPUT - echo "Version found in file \`version.h\`: \`$version_string\`" >> $GITHUB_STEP_SUMMARY + echo "Library Version found in file \`version.h\`: \`$version_string\`" >> $GITHUB_STEP_SUMMARY + + fixed_ref_name=$(echo "$REF" | tr -c [:alnum:]+[:cntrl:] [_*]) + deploy_version="" + if [ "${{env.DEV_DEPLOY}}" == "true" ]; then + deploy_version=$fixed_ref_name + echo "deploy_version=$deploy_version" >> $GITHUB_OUTPUT + else + deploy_version=$version_string + echo "deploy_version=$deploy_version" >> $GITHUB_OUTPUT + fi + echo "Deploy version: \`$deploy_version\`" >> $GITHUB_STEP_SUMMARY - name: Checkout CNAME uses: actions/checkout@v4 @@ -204,17 +218,15 @@ jobs: id: get_ref shell: bash env: - REF: ${{github.ref_name}} content_dir: docs # dev folder name must be synced with :fix_ref_names run: | - fixed_ref_name=$(echo "$REF" | tr -c [:alnum:]+[:cntrl:] [_*]) new_ref_name="" if [ "${{env.DEV_DEPLOY}}" == "true" ]; then - new_ref_name="dev/$fixed_ref_name/$content_dir" + new_ref_name="dev/${{needs.data_preparation.outputs.deploy_version}}/$content_dir" echo "new_ref_name=$new_ref_name" >> $GITHUB_OUTPUT else - new_ref_name="$content_dir/${{needs.data_preparation.outputs.lib_version}}" + new_ref_name="$content_dir/${{needs.data_preparation.outputs.deploy_version}}" echo "new_ref_name=$new_ref_name" >> $GITHUB_OUTPUT fi echo "Target URL: https://${{needs.data_preparation.outputs.domain}}/$new_ref_name" >> $GITHUB_STEP_SUMMARY @@ -237,24 +249,26 @@ jobs: name: ๐ŸŒ๐Ÿ“ฆ Export Demo Project runs-on: ubuntu-20.04 needs: [data_preparation, generate_docs, web-gdextension] - container: - image: barichello/godot-ci:4.2.1 env: - # Sync with container: image: - GODOT_VERSION: 4.2.1 + GODOT_VERSION: 4.2.1-stable PROJECT_PATH: dd3d_web_build + BUILD_FOLDER: demo_build steps: - - name: Check out code + - name: Checkout code uses: actions/checkout@v4 with: lfs: true - - name: Setup - run: | - mkdir -v -p ~/.local/share/godot/export_templates - mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable + - name: Setup Godot + uses: ./.github/actions/setup_godot + id: setup_godot + with: + tag: ${{env.GODOT_VERSION}} + file_suffix: "stable_linux.x86_64.zip" + download_export_templates: true + is_mono: false - name: Download Binaries uses: actions/download-artifact@v4 @@ -264,23 +278,22 @@ jobs: - name: Prepare Web Build run: | - ls addons/debug_draw_3d/libs - ls ${GITHUB_WORKSPACE}/addons/debug_draw_3d/libs - cp -r addons ${PROJECT_PATH}/addons - cp -r examples_dd3d ${PROJECT_PATH}/examples_dd3d + find addons/debug_draw_3d/libs -mindepth 1 + cp -r addons ${{env.PROJECT_PATH}}/addons + cp -r examples_dd3d ${{env.PROJECT_PATH}}/examples_dd3d - name: Import Assets - run: godot -v -e --headless --path ${PROJECT_PATH} --quit || true + run: ${{steps.setup_godot.outputs.godot}} -v -e --headless --path ${{env.PROJECT_PATH}} --quit || true - name: Web Build run: | - mkdir ${GITHUB_WORKSPACE}/demo - cp ${PROJECT_PATH}/coi-serviceworker.min.js ${GITHUB_WORKSPACE}/demo/coi-serviceworker.min.js - godot -v --headless --path ${PROJECT_PATH} --export-release web ${GITHUB_WORKSPACE}/demo/index.html + mkdir ${{env.BUILD_FOLDER}} + cp ${{env.PROJECT_PATH}}/coi-serviceworker.min.js ${{env.BUILD_FOLDER}}/coi-serviceworker.min.js + ${{steps.setup_godot.outputs.godot}} -v --headless --path ${{env.PROJECT_PATH}} --export-release web $(pwd)/${{env.BUILD_FOLDER}}/index.html - name: Fix Permissions run: | - chmod -c -R +rX "demo/" | while read line; do + chmod -c -R +rX "${{env.BUILD_FOLDER}}" | while read line; do echo "::warning title=Invalid file permissions automatically fixed::$line" done @@ -288,17 +301,15 @@ jobs: id: get_ref shell: bash env: - REF: ${{github.ref_name}} content_dir: demo # dev folder name must be synced with :fix_ref_names run: | - fixed_ref_name=$(echo "$REF" | tr -c [:alnum:]+[:cntrl:] [_*]) new_ref_name="" if [ "${{env.DEV_DEPLOY}}" == "true" ]; then - new_ref_name="dev/$fixed_ref_name/$content_dir" + new_ref_name="dev/${{needs.data_preparation.outputs.deploy_version}}/$content_dir" echo "new_ref_name=$new_ref_name" >> $GITHUB_OUTPUT else - new_ref_name="$content_dir/${{needs.data_preparation.outputs.lib_version}}" + new_ref_name="$content_dir/${{needs.data_preparation.outputs.deploy_version}}" echo "new_ref_name=$new_ref_name" >> $GITHUB_OUTPUT fi echo "Target URL: https://${{needs.data_preparation.outputs.domain}}/$new_ref_name" >> $GITHUB_STEP_SUMMARY @@ -307,7 +318,7 @@ jobs: uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} - publish_dir: demo + publish_dir: ${{env.BUILD_FOLDER}} destination_dir: ${{steps.get_ref.outputs.new_ref_name}} publish_branch: ${{env.PAGES_BRANCH}} allow_empty_commit: true @@ -561,8 +572,8 @@ jobs: shell: bash run: | git reset --soft ${{needs.data_preparation.outputs.head_sha}} - msg=$'Pages have been updated: ${{github.sha}}\n' - git commit -am "${msg}$(git log --format=%B --reverse HEAD..HEAD@{1})" + msg=$'Pages have been updated (${{env.DEV_DEPLOY == 'true' && 'Dev' || 'Release'}}, deploy version: ${{needs.data_preparation.outputs.deploy_version}}): ${{github.sha}}\n' + git commit --allow-empty -am "${msg}$(git log --format=%B --reverse HEAD..HEAD@{1})" git push -f echo "## Changed files:" >> $GITHUB_STEP_SUMMARY @@ -580,19 +591,11 @@ jobs: url: ${{steps.deployment.outputs.page_url}} steps: - - name: Checkout Action - uses: actions/checkout@v4 - with: - path: temp_repo - sparse-checkout: .github/actions/delete_artifact - - name: Remove `github-pages` if the action was restarted - uses: ./temp_repo/.github/actions/delete_artifact + uses: geekyeggo/delete-artifact@v4 with: - artifact: github-pages - - - name: Remove Action - run: rm -rf temp_repo/ + token: ${{secrets.GITHUB_TOKEN}} + name: github-pages - name: Checkout uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 1d7e0ab4..4628dae6 100644 --- a/.gitignore +++ b/.gitignore @@ -36,12 +36,15 @@ used_classes.json *.scor *.scor.* +.scons-cache/ .import/ .mono/ obj/ bin/ src/gen/* +src/editor/my_telemetry_modules addons/debug_draw_3d/libs/~* addons/debug_draw_3d/gen/* clang_rt.asan_* docs/images/classes/temp/ +SUCCESS diff --git a/addons/debug_draw_3d/README.md b/addons/debug_draw_3d/README.md index 6d1b0f99..78c74964 100644 --- a/addons/debug_draw_3d/README.md +++ b/addons/debug_draw_3d/README.md @@ -34,6 +34,7 @@ Your support adds motivation to develop my public projects. * Line * Line Path * Line with Arrow +* Plane * Points * Position 3D (3 crossing axes) * Sphere @@ -51,10 +52,10 @@ Overlay: Precompiled for: * Windows -* Linux -* macOS -* Android -* Web (WebAssembly) +* Linux (built on Ubuntu 20.04) +* macOS (10.14+) +* Android (5.0+) +* Web (Firefox not supported) ## [Interactive Web Demo](https://dd3d.dmitriysalnikov.ru/demo/) diff --git a/addons/debug_draw_3d/debug_draw_3d.gdextension b/addons/debug_draw_3d/debug_draw_3d.gdextension index d0f406fc..fbc1b9c6 100644 --- a/addons/debug_draw_3d/debug_draw_3d.gdextension +++ b/addons/debug_draw_3d/debug_draw_3d.gdextension @@ -6,9 +6,9 @@ reloadable = false [dependencies] -# example.x86_64 = { "relative or absolute path to the dependency" : "the path relative to the exported project", } - -# debug +; example.x86_64 = { "relative or absolute path to the dependency" : "the path relative to the exported project", } +; ------------------------------------- +; debug macos = { } windows.x86_64 = { } @@ -21,7 +21,8 @@ android.arm64 = { } android.x86_32 = { } android.x86_64 = { } -# release no debug draw +; ------------------------------------- +; release no debug draw macos.template_release = { } windows.template_release.x86_64 = { } @@ -34,7 +35,8 @@ android.template_release.arm64 = { } android.template_release.x86_32 = { } android.template_release.x86_64 = { } -# release forced debug draw +; ------------------------------------- +; release forced debug draw macos.template_release.forced_dd3d = { } windows.template_release.x86_64.forced_dd3d = { } @@ -44,9 +46,10 @@ web.template_release.wasm32.forced_dd3d = { } [libraries] -# debug +; ------------------------------------- +; debug -macos = "libs/libdd3d.macos.editor.universal.dylib" +macos = "libs/libdd3d.macos.editor.universal.framework" windows.x86_64 = "libs/libdd3d.windows.editor.x86_64.dll" linux.x86_64 = "libs/libdd3d.linux.editor.x86_64.so" @@ -57,9 +60,10 @@ android.arm64 = "libs/libdd3d.android.template_debug.arm64.so" android.x86_32 = "libs/libdd3d.android.template_debug.x86_32.so" android.x86_64 = "libs/libdd3d.android.template_debug.x86_64.so" -# release no debug draw +; ------------------------------------- +; release no debug draw -macos.template_release = "libs/libdd3d.macos.template_release.universal.dylib" +macos.template_release = "libs/libdd3d.macos.template_release.universal.framework" windows.template_release.x86_64 = "libs/libdd3d.windows.template_release.x86_64.dll" linux.template_release.x86_64 = "libs/libdd3d.linux.template_release.x86_64.so" @@ -70,9 +74,10 @@ android.template_release.arm64 = "libs/libdd3d.android.template_release.arm64.so android.template_release.x86_32 = "libs/libdd3d.android.template_release.x86_32.so" android.template_release.x86_64 = "libs/libdd3d.android.template_release.x86_64.so" -# release forced debug draw +; ------------------------------------- +; release forced debug draw -macos.template_release.forced_dd3d = "libs/libdd3d.macos.template_release.universal.enabled.dylib" +macos.template_release.forced_dd3d = "libs/libdd3d.macos.template_release.universal.enabled.framework" windows.template_release.x86_64.forced_dd3d = "libs/libdd3d.windows.template_release.x86_64.enabled.dll" linux.template_release.x86_64.forced_dd3d = "libs/libdd3d.linux.template_release.x86_64.enabled.so" diff --git a/dd3d_web_build/headless_test.tscn b/dd3d_web_build/headless_test.tscn new file mode 100644 index 00000000..104ea0cd --- /dev/null +++ b/dd3d_web_build/headless_test.tscn @@ -0,0 +1,68 @@ +[gd_scene load_steps=3 format=3 uid="uid://cnv87ogp7t43e"] + +[sub_resource type="GDScript" id="GDScript_wbn2v"] +script/source = "extends Node3D + + +func _ready(): + if FileAccess.file_exists(\"SUCCESS\"): + DirAccess.remove_absolute(\"SUCCESS\") + + print(\"DD3D Version: \", ProjectSettings.get_setting(\"debug_draw_3d/settings/updates/addon_version\")) + print(\"Engine Version: \", Engine.get_version_info()) + print(\"Distribution: \", OS.get_distribution_name()) + print(\"OS Name: \", OS.get_name()) + print(\"OS Version: \", OS.get_version()) + print(\"CPU: \", OS.get_processor_name()) + print(\"CPU Count: \", OS.get_processor_count()) + print(\"CPU Architecture: \", Engine.get_architecture_name()) + + var res = await $Runner.call(&\"start\") if $Runner.has_method(&\"start\") else false + print(\"Headless runner returns: \", res) + + if res: + var f = FileAccess.open(\"SUCCESS\", FileAccess.WRITE) + f.store_8(1) + + print() + get_tree().quit(0 if res == true else 1) +" + +[sub_resource type="GDScript" id="GDScript_7yy7l"] +script/source = "extends Node3D + + +# Some API calls to test library integration +func start() -> bool: + print() + print(\"Start of testing.\") + + if true: + var _s = DebugDraw3D.new_scoped_config().set_thickness(0.3) + DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE) + DebugDraw3D.draw_sphere(Vector3.ZERO) + DebugDraw2D.set_text(\"FPS\", \"0\") + DebugDraw2D.begin_text_group(\"Info\") + + await get_tree().process_frame + + DebugDraw3D.draw_sphere(Vector3.ZERO) + DebugDraw3D.config.culling_distance = 50 + print(\"culling_distance: \", DebugDraw3D.config.culling_distance) + + await get_tree().process_frame + + DebugDrawManager.clear_all() + + await get_tree().process_frame + + print(\"End of testing.\") + + return true +" + +[node name="HeadlessTest" type="Node3D"] +script = SubResource("GDScript_wbn2v") + +[node name="Runner" type="Node3D" parent="."] +script = SubResource("GDScript_7yy7l") diff --git a/lib_utils.py b/lib_utils.py index ede79084..637ec40a 100644 --- a/lib_utils.py +++ b/lib_utils.py @@ -2,8 +2,10 @@ import os import json +import re from patches import unity_tools +lib_readable_name = "Debug Draw 3D" lib_name = "dd3d" output_dir = os.path.join("addons", "debug_draw_3d", "libs") src_folder = "src" @@ -54,66 +56,12 @@ def setup_defines_and_flags(env, src_out): print() -# A utility function for getting the name of an unblocked file -def _get_unblocked_file_name(original_file_path, new_file_ext, max_files=256, keep_newest_one=True): - lib_dir = os.path.normpath(os.path.dirname(original_file_path)) - lib_name = os.path.splitext(os.path.basename(original_file_path))[0] - - # Collect all matching files - found_files = [ - f - for f in os.listdir(lib_dir) - if os.path.isfile(os.path.join(lib_dir, f)) and f.startswith(lib_name) and f.endswith("." + new_file_ext) - ] - found_files = sorted(found_files, key=lambda x: os.path.getmtime(os.path.join(lib_dir, x))) - - # Clean up the old files if possible, except for the newest one - if found_files: - if keep_newest_one: - found_files.pop() - for f in found_files: - try: - os.remove(os.path.join(lib_dir, f)) - except: - pass - - # Search for a unblocked file name - file_name = "" - for s in range(max_files): - file_name = "{}_{}.{}".format(os.path.join(lib_dir, lib_name), s, new_file_ext) - if not os.path.exists(file_name): - break - try: - with open(file_name, "a") as f: - pass - except IOError: - continue - break - - return file_name - - -# This is necessary to support debugging and Hot-Reload at the same time when building using MSVC -def msvc_pdb_rename(env, full_lib_path): - pdb_name = _get_unblocked_file_name(full_lib_path, "pdb") - print("New path to the PDB: " + pdb_name) - # explicit assignment of the PDB name - env.Append(LINKFLAGS=["/PDB:" + pdb_name]) - - def get_sources(src): res = [src_folder + "/" + file for file in src] res = unity_tools.generate_unity_build(res, "dd3d_") - return res -def replace_flag(arr, flag, new_flag): - if flag in arr: - arr.remove(flag) - arr.append(new_flag) - - def get_library_object(env, arguments=None, gen_help=None): if arguments != None and gen_help: setup_options(env, arguments, gen_help) @@ -125,8 +73,10 @@ def get_library_object(env, arguments=None, gen_help=None): with open(src_folder + "/default_sources.json") as f: src = json.load(f) - # store all obj's in a dedicated folder - env["SHOBJPREFIX"] = "#obj/" + scons_cache_path = os.environ.get("SCONS_CACHE") + if scons_cache_path is None: + # store all obj's in a dedicated folder + env["SHOBJPREFIX"] = "#obj/" generate_sources_for_resources(env, src) @@ -136,20 +86,30 @@ def get_library_object(env, arguments=None, gen_help=None): additional_tags += ".enabled" library_name = "lib{}.{}.{}.{}{}".format(lib_name, env["platform"], env["target"], env["arch"], additional_tags) - library_full_path = os.path.join(env["addon_output_dir"], (library_name + env["SHLIBSUFFIX"])) + library_full_path = os.path.join(env["addon_output_dir"], library_name + env["SHLIBSUFFIX"]) # using the library with `reloadable = true` and with the debugger block the PDB file, # so it needs to be renamed to something not blocked if env.get("is_msvc", False) and env["target"] != "template_release": msvc_pdb_rename(env, library_full_path) - env.Default( - env.SharedLibrary( - target=env.File(library_full_path), - source=additional_src + get_sources(src), - SHLIBSUFFIX=env["SHLIBSUFFIX"], + if env["platform"] != "macos": + env.Default( + env.SharedLibrary( + target=env.File(library_full_path), + source=additional_src + get_sources(src), + SHLIBSUFFIX=env["SHLIBSUFFIX"], + ) + ) + else: + generate_framework_folder(env, library_name) + env.Default( + env.SharedLibrary( + target=env.File(os.path.join(env["addon_output_dir"], library_name + ".framework", library_name)), + source=additional_src + get_sources(src), + SHLIBSUFFIX="", + ) ) - ) # Needed for easy reuse of this library in other build scripts # TODO: not tested at the moment. Probably need some changes in the C++ code @@ -163,6 +123,32 @@ def get_library_object(env, arguments=None, gen_help=None): return env +def get_library_version(): + with open("src/version.h", "r") as f: + header_content = f.read() + + major_match = re.search(r"#define .*_MAJOR (\d+)", header_content) + minor_match = re.search(r"#define .*_MINOR (\d+)", header_content) + patch_match = re.search(r"#define .*_PATCH (\d+)", header_content) + + if major_match: + major_value = int(major_match.group(1)) + else: + major_value = 0 + + if minor_match: + minor_value = int(minor_match.group(1)) + else: + minor_value = 0 + + if patch_match: + patch_value = int(patch_match.group(1)) + else: + patch_value = 0 + + return f"{major_value}.{minor_value}.{patch_value}" + + def generate_sources_for_resources(env, src_out): # Array of (path, is_text) editor_files = [ @@ -255,3 +241,101 @@ def generate_resources_cpp_h_files(input_files, namespace, output_no_ext, src_ou h_file.write("}\n") cpp_file.write("}\n") + + +def generate_framework_folder(env, library_name): + min_version = env.get("macos_deployment_target", "10.14") + lib_version = get_library_version() + + info_plist = f""" + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + {library_name} + CFBundleName + {lib_readable_name} + CFBundleDisplayName + {lib_readable_name} + CFBundleIdentifier + ru.dmitriysalnikov.{lib_name} + NSHumanReadableCopyright + Copyright (c) Dmitriy Salnikov. + CFBundleVersion + {lib_version} + CFBundleShortVersionString + {lib_version} + CFBundlePackageType + FMWK + CSResourcesFileMapped + + DTPlatformName + macosx + LSMinimumSystemVersion + {min_version} + + + """ + + res_folder = os.path.join(env["addon_output_dir"], library_name + ".framework", "Resources") + os.makedirs(res_folder, exist_ok=True) + + with open(os.path.join(res_folder, "Info.plist"), "w") as info_plist_file: + info_plist_file.write(info_plist) + + +def replace_flag(arr, flag, new_flag): + if flag in arr: + arr.remove(flag) + arr.append(new_flag) + + +# A utility function for getting the name of an unblocked file +def get_unblocked_file_name(original_file_path, new_file_ext, max_files=256, keep_newest_one=True): + lib_dir = os.path.normpath(os.path.dirname(original_file_path)) + lib_name = os.path.splitext(os.path.basename(original_file_path))[0] + + # Collect all matching files + found_files = [ + f + for f in os.listdir(lib_dir) + if os.path.isfile(os.path.join(lib_dir, f)) and f.startswith(lib_name) and f.endswith("." + new_file_ext) + ] + found_files = sorted(found_files, key=lambda x: os.path.getmtime(os.path.join(lib_dir, x))) + + # Clean up the old files if possible, except for the newest one + if found_files: + if keep_newest_one: + found_files.pop() + for f in found_files: + try: + os.remove(os.path.join(lib_dir, f)) + except: + pass + + # Search for a unblocked file name + file_name = "" + for s in range(max_files): + file_name = "{}_{}.{}".format(os.path.join(lib_dir, lib_name), s, new_file_ext) + if not os.path.exists(file_name): + break + try: + with open(file_name, "a") as f: + pass + except IOError: + continue + break + + return file_name + + +# This is necessary to support debugging and Hot-Reload at the same time when building using MSVC +def msvc_pdb_rename(env, full_lib_path): + pdb_name = get_unblocked_file_name(full_lib_path, "pdb") + print("New path to the PDB: " + pdb_name) + # explicit assignment of the PDB name + env.Append(LINKFLAGS=["/PDB:" + pdb_name]) diff --git a/src/3d/config_scope_3d.cpp b/src/3d/config_scope_3d.cpp index 94b78ea3..a68df8c0 100644 --- a/src/3d/config_scope_3d.cpp +++ b/src/3d/config_scope_3d.cpp @@ -28,39 +28,39 @@ void DebugDraw3DScopeConfig::_manual_unregister() { } Ref DebugDraw3DScopeConfig::set_thickness(real_t value) { - thickness = Math::clamp(value, (real_t)0, (real_t)100); + data->thickness = Math::clamp(value, (real_t)0, (real_t)100); return Ref(this); } real_t DebugDraw3DScopeConfig::get_thickness() { - return thickness; + return data->thickness; } Ref DebugDraw3DScopeConfig::set_center_brightness(real_t value) { - center_brightness = Math::clamp(value, (real_t)0, (real_t)1); + data->center_brightness = Math::clamp(value, (real_t)0, (real_t)1); return Ref(this); } real_t DebugDraw3DScopeConfig::get_center_brightness() { - return center_brightness; + return data->center_brightness; } Ref DebugDraw3DScopeConfig::set_hd_sphere(bool value) { - hd_sphere = value; + data->hd_sphere = value; return this; } bool DebugDraw3DScopeConfig::is_hd_sphere() { - return hd_sphere; + return data->hd_sphere; } Ref DebugDraw3DScopeConfig::set_plane_size(real_t value) { - plane_size = value; + data->plane_size = value; return this; } real_t DebugDraw3DScopeConfig::get_plane_size() { - return plane_size; + return data->plane_size; } DebugDraw3DScopeConfig::DebugDraw3DScopeConfig() { @@ -68,18 +68,26 @@ DebugDraw3DScopeConfig::DebugDraw3DScopeConfig() { thread_id = 0; guard_id = 0; + data = std::make_shared(); +} + +DebugDraw3DScopeConfig::Data::Data() { thickness = 0; center_brightness = 0; hd_sphere = false; plane_size = INFINITY; } -DebugDraw3DScopeConfig::DebugDraw3DScopeConfig(const uint64_t &p_thread_id, const uint64_t &p_guard_id, const DebugDraw3DScopeConfig *parent, const unregister_func p_unreg) { +DebugDraw3DScopeConfig::DebugDraw3DScopeConfig(const uint64_t &p_thread_id, const uint64_t &p_guard_id, const std::shared_ptr &parent, const unregister_func p_unreg) { unregister_action = p_unreg; thread_id = p_thread_id; guard_id = p_guard_id; + data = std::make_shared(parent); +} + +DebugDraw3DScopeConfig::Data::Data(const std::shared_ptr &parent) { thickness = parent->thickness; center_brightness = parent->center_brightness; hd_sphere = parent->hd_sphere; diff --git a/src/3d/config_scope_3d.h b/src/3d/config_scope_3d.h index 938a1c94..03bb0386 100644 --- a/src/3d/config_scope_3d.h +++ b/src/3d/config_scope_3d.h @@ -3,6 +3,7 @@ #include "utils/compiler.h" #include +#include GODOT_WARNING_DISABLE() #include @@ -15,10 +16,33 @@ using namespace godot; * * `Scope` means that these overridden parameters will affect the drawn geometry until it exits the current scope. * - * To create it, use DebugDraw3D.new_scoped_config. Immediately after creation, you can change the values and save the reference to a variable. + * To create it, use DebugDraw3D.new_scoped_config. + * Immediately after creation, you can change the values and save the reference in a variable. * - * But the main thing is not to save it outside the method or in other objects. After leaving the scope, this object should be deleted. + * @warning + * But the main thing is not to save it outside the method or in other objects. + * After leaving the scope, this object should be deleted. * + * --- + * @warning + * Also, you can't use scope config between `await`s unless this object is freed before `await`. + * So, narrow the scope if you want to use `await` and DebugDraw3DScopeConfig in the same method. + * ```python + * # Bad example + * var _s = DebugDraw3D.new_scoped_config().set_thickness(0.3) + * DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE) + * await get_tree().process_frame + * # your code... + * + * # Good example + * if true: + * var _s = DebugDraw3D.new_scoped_config().set_thickness(0.3) + * DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE) + * await get_tree().process_frame + * # your code... + * ``` + * + * ### Examples: * ```python * var _s = DebugDraw3D.new_scoped_config().set_thickness(0.025).set_center_brightness(0.7) * DebugDraw3D.draw_grid_xf(%Grid.global_transform, Vector2i(10,10), Color.LIGHT_GRAY) @@ -40,16 +64,24 @@ class DebugDraw3DScopeConfig : public RefCounted { uint64_t thread_id; uint64_t guard_id; - typedef std::function unregister_func; + typedef std::function unregister_func; unregister_func unregister_action; - // Update constructor! - real_t thickness; - real_t center_brightness; - bool hd_sphere; - real_t plane_size; - public: + /// @private + struct Data { + // Update constructor! + real_t thickness; + real_t center_brightness; + bool hd_sphere; + real_t plane_size; + + Data(); + Data(const std::shared_ptr &parent); + }; + /// @private + std::shared_ptr data = nullptr; + /// @private // It can be used for example in C# void _manual_unregister(); @@ -91,6 +123,6 @@ class DebugDraw3DScopeConfig : public RefCounted { // `DDScopedConfig3D` is passed as Ref to avoid a random unreference /// @private - DebugDraw3DScopeConfig(const uint64_t &p_thread_id, const uint64_t &p_guard_id, const DebugDraw3DScopeConfig *parent, const unregister_func p_unreg); + DebugDraw3DScopeConfig(const uint64_t &p_thread_id, const uint64_t &p_guard_id, const std::shared_ptr &parent, const unregister_func p_unreg); ~DebugDraw3DScopeConfig(); }; diff --git a/src/3d/debug_draw_3d.cpp b/src/3d/debug_draw_3d.cpp index f1d9dde4..1ec35728 100644 --- a/src/3d/debug_draw_3d.cpp +++ b/src/3d/debug_draw_3d.cpp @@ -166,48 +166,48 @@ void DebugDraw3D::physics_process_end(double delta) { } #ifndef DISABLE_DEBUG_RENDERING -DebugDraw3DScopeConfig *DebugDraw3D::scoped_config_for_current_thread() { +const DebugDraw3D::DebugDraw3DScopeConfig_Data DebugDraw3D::scoped_config_for_current_thread() { ZoneScoped; LOCK_GUARD(datalock); uint64_t thread = OS::get_singleton()->get_thread_caller_id(); - auto it = cached_scoped_configs.find(thread); - if (it != cached_scoped_configs.end()) { + const auto &it = cached_scoped_configs.find(thread); + if (it != cached_scoped_configs.cend()) { return it->second; } - auto it_v = scoped_configs.find(thread); - if (it_v != scoped_configs.end()) { + const auto &it_v = scoped_configs.find(thread); + if (it_v != scoped_configs.cend()) { const auto &cfgs = it_v->second; if (!cfgs.empty()) { DebugDraw3DScopeConfig *tmp = cfgs.back().second; - cached_scoped_configs[thread] = tmp; - return tmp; + cached_scoped_configs[thread] = tmp->data; + return tmp->data; } } - cached_scoped_configs[thread] = default_scoped_config.ptr(); - return default_scoped_config.ptr(); + cached_scoped_configs[thread] = default_scoped_config.ptr()->data; + return default_scoped_config.ptr()->data; } -DebugDraw3D::GeometryType DebugDraw3D::_scoped_config_get_geometry_type(DebugDraw3DScopeConfig *cfg) { +DebugDraw3D::GeometryType DebugDraw3D::_scoped_config_get_geometry_type(const DebugDraw3DScopeConfig_Data &cfg) { ZoneScoped; - if (cfg->get_thickness() != 0) { + if (cfg->thickness != 0) { return GeometryType::Volumetric; } // TODO solid return GeometryType::Wireframe; } -Color DebugDraw3D::_scoped_config_to_custom(DebugDraw3DScopeConfig *cfg) { +Color DebugDraw3D::_scoped_config_to_custom(const DebugDraw3DScopeConfig_Data &cfg) { ZoneScoped; if (_scoped_config_get_geometry_type(cfg) == GeometryType::Volumetric) - return Color(cfg->get_thickness(), cfg->get_center_brightness(), 0, 0); + return Color(cfg->thickness, cfg->center_brightness, 0, 0); return Color(); } -InstanceType DebugDraw3D::_scoped_config_type_convert(ConvertableInstanceType type, DebugDraw3DScopeConfig *cfg) { +InstanceType DebugDraw3D::_scoped_config_type_convert(ConvertableInstanceType type, const DebugDraw3DScopeConfig_Data &cfg) { ZoneScoped; switch (_scoped_config_get_geometry_type(cfg)) { case GeometryType::Wireframe: { @@ -272,7 +272,7 @@ void DebugDraw3D::_register_scoped_config(uint64_t thread_id, uint64_t guard_id, scoped_configs[thread_id].push_back(ScopedPairIdConfig(guard_id, cfg)); // Update cached value - cached_scoped_configs[thread] = cfg; + cached_scoped_configs[thread] = cfg->data; } void DebugDraw3D::_unregister_scoped_config(uint64_t thread_id, uint64_t guard_id) { @@ -287,9 +287,9 @@ void DebugDraw3D::_unregister_scoped_config(uint64_t thread_id, uint64_t guard_i // Update cached value if (!cfgs.empty()) { - cached_scoped_configs[thread_id] = cfgs.back().second; + cached_scoped_configs[thread_id] = (DebugDraw3DScopeConfig_Data)(cfgs.back().second->data); } else { - cached_scoped_configs[thread_id] = default_scoped_config.ptr(); + cached_scoped_configs[thread_id] = default_scoped_config.ptr()->data; } } } @@ -327,12 +327,14 @@ Ref DebugDraw3D::new_scoped_config() { create_counter++; uint64_t thread = OS::get_singleton()->get_thread_caller_id(); - Ref res = memnew( + Ref res(memnew( DebugDraw3DScopeConfig( thread, create_counter, scoped_config_for_current_thread(), - std::bind(&DebugDraw3D::_unregister_scoped_config, this, std::placeholders::_1, std::placeholders::_2))); + [this](const uint64_t &p_thread_id, const uint64_t &p_guard_id) { + _unregister_scoped_config(p_thread_id, p_guard_id); + }))); _register_scoped_config(thread, create_counter, res.ptr()); create_scoped_configs++; @@ -527,9 +529,9 @@ void DebugDraw3D::add_or_update_line_with_thickness(real_t _exp_time, std::uniqu ZoneScoped; LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); - if (!scfg->get_thickness()) { + if (!scfg->thickness) { dgc->geometry_pool.add_or_update_line(_exp_time, GET_PROC_TYPE(), std::move(_lines), _line_count, _col); } else { for (int i = 0; i < _line_count; i += 2) { @@ -557,10 +559,10 @@ void DebugDraw3D::draw_sphere_base(const Transform3D &transform, const Color &co CHECK_BEFORE_CALL(); LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); dgc->geometry_pool.add_or_update_instance( - _scoped_config_type_convert(scfg->is_hd_sphere() ? ConvertableInstanceType::SPHERE_HD : ConvertableInstanceType::SPHERE, scfg), + _scoped_config_type_convert(scfg->hd_sphere ? ConvertableInstanceType::SPHERE_HD : ConvertableInstanceType::SPHERE, scfg), duration, GET_PROC_TYPE(), transform, @@ -589,7 +591,7 @@ void DebugDraw3D::draw_cylinder(const Transform3D &transform, const Color &color CHECK_BEFORE_CALL(); LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); dgc->geometry_pool.add_or_update_instance( _scoped_config_type_convert(ConvertableInstanceType::CYLINDER, scfg), @@ -614,7 +616,7 @@ void DebugDraw3D::draw_cylinder_ab(const Vector3 &a, const Vector3 &b, const rea Transform3D t = Transform3D(Basis().looking_at(half_center, up).scaled_local(Vector3(diameter, diameter, len)), a + half_center); LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); dgc->geometry_pool.add_or_update_instance( _scoped_config_type_convert(ConvertableInstanceType::CYLINDER_AB, scfg), @@ -656,7 +658,7 @@ void DebugDraw3D::draw_box_ab(const Vector3 &a, const Vector3 &b, const Vector3 SphereBounds sb(t.origin + half_center_orig, MathUtils::get_max_basis_length(t.basis) * MathUtils::CubeRadiusForSphere); LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); dgc->geometry_pool.add_or_update_instance( _scoped_config_type_convert(ConvertableInstanceType::CUBE, scfg), @@ -688,7 +690,7 @@ void DebugDraw3D::draw_box_xf(const Transform3D &transform, const Color &color, } LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); dgc->geometry_pool.add_or_update_instance( _scoped_config_type_convert(is_box_centered ? ConvertableInstanceType::CUBE_CENTERED : ConvertableInstanceType::CUBE, scfg), @@ -833,7 +835,7 @@ void DebugDraw3D::create_arrow(const Vector3 &a, const Vector3 &b, const Color & Vector3 up = get_up_vector(dir); Transform3D t = Transform3D(Basis().looking_at(dir, up).scaled(Vector3(size, size, size)), b); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); LOCK_GUARD(datalock); dgc->geometry_pool.add_or_update_instance( @@ -851,7 +853,7 @@ void DebugDraw3D::draw_arrowhead(const Transform3D &transform, const Color &colo CHECK_BEFORE_CALL(); LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); dgc->geometry_pool.add_or_update_instance( _scoped_config_type_convert(ConvertableInstanceType::ARROWHEAD, scfg), @@ -918,7 +920,7 @@ void DebugDraw3D::draw_square(const Vector3 &position, const real_t &size, const Transform3D t(Basis().scaled(Vector3_ONE * size), position); LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); dgc->geometry_pool.add_or_update_instance( InstanceType::BILLBOARD_SQUARE, @@ -938,9 +940,9 @@ void DebugDraw3D::draw_plane(const Plane &plane, const Color &color, const Vecto Color front_color = IS_DEFAULT_COLOR(color) ? Colors::plane_light_sky_blue : color; LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); - float plane_size = scfg->get_plane_size() != INFINITY ? scfg->get_plane_size() : (float)previous_camera_far_plane; + float plane_size = scfg->plane_size != INFINITY ? scfg->plane_size : (float)previous_camera_far_plane; Transform3D t(Basis(), center_pos); t = t.looking_at(center_pos + plane.normal, get_up_vector(plane.normal)).scaled_local(Vector3_ONE * plane_size); @@ -976,7 +978,7 @@ void DebugDraw3D::draw_position(const Transform3D &transform, const Color &color CHECK_BEFORE_CALL(); LOCK_GUARD(datalock); - DebugDraw3DScopeConfig *scfg = scoped_config_for_current_thread(); + auto scfg = scoped_config_for_current_thread(); dgc->geometry_pool.add_or_update_instance( _scoped_config_type_convert(ConvertableInstanceType::POSITION, scfg), @@ -1024,7 +1026,7 @@ void DebugDraw3D::draw_grid_xf(const Transform3D &transform, const Vector2i &p_s ZoneScoped; CHECK_BEFORE_CALL(); -#define MAX_SUBDIVISIONS 1024 * 1024 + const int MAX_SUBDIVISIONS = 1024 * 1024; ERR_FAIL_COND(p_subdivision.x > MAX_SUBDIVISIONS); ERR_FAIL_COND(p_subdivision.y > MAX_SUBDIVISIONS); diff --git a/src/3d/debug_draw_3d.h b/src/3d/debug_draw_3d.h index 5eb9da34..a2052262 100644 --- a/src/3d/debug_draw_3d.h +++ b/src/3d/debug_draw_3d.h @@ -71,7 +71,7 @@ enum class ConvertableInstanceType : char; * # some DD3D logic * ``` */ -class DebugDraw3D : public Object, public IScopeStorage { +class DebugDraw3D : public Object, public IScopeStorage { GDCLASS(DebugDraw3D, Object) friend DebugDrawManager; @@ -117,14 +117,15 @@ class DebugDraw3D : public Object, public IScopeStorage ProfiledMutex(std::recursive_mutex, datalock, "3D Geometry lock"); typedef std::pair ScopedPairIdConfig; + typedef std::shared_ptr DebugDraw3DScopeConfig_Data; // stores thread id and array of id's with ptrs std::unordered_map > scoped_configs; // stores thread id and most recent config - std::unordered_map cached_scoped_configs; + std::unordered_map cached_scoped_configs; uint64_t create_scoped_configs = 0; // Inherited via IScopeStorage - DebugDraw3DScopeConfig *scoped_config_for_current_thread() override; + const DebugDraw3DScopeConfig_Data scoped_config_for_current_thread() override; // Meshes std::unique_ptr dgc; @@ -151,9 +152,9 @@ class DebugDraw3D : public Object, public IScopeStorage void _clear_scoped_configs() override; // Internal use of raw pointer to avoid ref/unref - Color _scoped_config_to_custom(DebugDraw3DScopeConfig *cfg); - InstanceType _scoped_config_type_convert(ConvertableInstanceType type, DebugDraw3DScopeConfig *cfg); - GeometryType _scoped_config_get_geometry_type(DebugDraw3DScopeConfig *cfg); + Color _scoped_config_to_custom(const DebugDraw3DScopeConfig_Data &cfg); + InstanceType _scoped_config_type_convert(ConvertableInstanceType type, const DebugDraw3DScopeConfig_Data &cfg); + GeometryType _scoped_config_get_geometry_type(const DebugDraw3DScopeConfig_Data &cfg); _FORCE_INLINE_ Vector3 get_up_vector(const Vector3 &dir); void add_or_update_line_with_thickness(real_t _exp_time, std::unique_ptr _lines, const size_t _line_count, const Color &_col, const std::function _custom_upd = nullptr); diff --git a/src/common/i_scope_storage.h b/src/common/i_scope_storage.h index dad71057..a59f88c0 100644 --- a/src/common/i_scope_storage.h +++ b/src/common/i_scope_storage.h @@ -3,13 +3,14 @@ #include "utils/compiler.h" #include +#include GODOT_WARNING_DISABLE() #include GODOT_WARNING_RESTORE() using namespace godot; -template +template class IScopeStorage { private: #ifndef DISABLE_DEBUG_RENDERING @@ -17,7 +18,7 @@ class IScopeStorage { virtual void _unregister_scoped_config(uint64_t thread_id, uint64_t guard_id) = 0; virtual void _clear_scoped_configs() = 0; - virtual TCfgStorage *scoped_config_for_current_thread() = 0; + virtual const std::shared_ptr scoped_config_for_current_thread() = 0; #endif public: diff --git a/src/debug_draw_manager.cpp b/src/debug_draw_manager.cpp index 928193c4..46c54bd8 100644 --- a/src/debug_draw_manager.cpp +++ b/src/debug_draw_manager.cpp @@ -4,6 +4,7 @@ #include "2d/grouped_text.h" #include "3d/debug_draw_3d.h" #include "utils/utils.h" +#include "version.h" #ifdef TOOLS_ENABLED #include "editor/generate_csharp_bindings.h" @@ -250,7 +251,6 @@ void DebugDrawManager::_integrate_into_engine() { if (is_headless) { set_debug_enabled(false); - return; } // Draw everything after calls from scripts to avoid lagging @@ -352,7 +352,9 @@ void DebugDrawManager::_integrate_into_engine() { _try_to_update_cs_bindings(); #ifdef TELEMETRY_ENABLED - time_usage_reporter = std::make_unique([&]() { call_deferred(NAMEOF(_on_telemetry_sending_completed)); }); + if (!is_headless) { + time_usage_reporter = std::make_unique(DD3D_VERSION_STR, [&]() { call_deferred(NAMEOF(_on_telemetry_sending_completed)); }); + } #endif } #endif @@ -423,7 +425,9 @@ void DebugDrawManager::_try_to_update_cs_bindings() { #ifdef TELEMETRY_ENABLED void DebugDrawManager::_on_telemetry_sending_completed() { - time_usage_reporter->stop_thread(); + if (time_usage_reporter) { + time_usage_reporter->stop_thread(); + } } #endif #endif diff --git a/src/version.h b/src/version.h index fe7b641c..9fffaef9 100644 --- a/src/version.h +++ b/src/version.h @@ -2,7 +2,7 @@ #define DD3D_MAJOR 1 #define DD3D_MINOR 3 -#define DD3D_PATCH 0 +#define DD3D_PATCH 1 #define DD3D_VERSION ((DD3D_MAJOR << (8 * 3)) + (DD3D_MINOR << (8 * 2)) + (DD3D_PATCH << (8 * 1))) #define _DD3D_VERSION_STR_TEXT(text) #text