From e643327f489d9239cb2dff3bba14aba15f569e49 Mon Sep 17 00:00:00 2001 From: Niamh Nikali Date: Fri, 11 Jul 2025 21:43:03 -0600 Subject: [PATCH 1/4] Add DebugDraw3D extension --- addons/debug_draw_3d/LICENSE | 21 + addons/debug_draw_3d/README.md | 157 +++ .../debug_draw_3d/debug_draw_3d.gdextension | 153 +++ .../debug_draw_3d.gdextension.uid | 1 + addons/debug_draw_3d/libs/.gdignore | 0 .../libdd3d.android.template_debug.arm32.so | 3 + .../libdd3d.android.template_debug.arm64.so | 3 + .../libdd3d.android.template_debug.x86_32.so | 3 + .../libdd3d.android.template_debug.x86_64.so | 3 + .../libdd3d.android.template_release.arm32.so | 3 + .../libdd3d.android.template_release.arm64.so | 3 + ...libdd3d.android.template_release.x86_32.so | 3 + ...libdd3d.android.template_release.x86_64.so | 3 + ...libdd3d.ios.template_debug.universal.dylib | 3 + ...bdd3d.ios.template_release.universal.dylib | 3 + ...s.template_release.universal.enabled.dylib | 3 + .../libs/libdd3d.linux.editor.x86_64.so | 3 + ...d.linux.template_release.x86_64.enabled.so | 3 + .../libdd3d.linux.template_release.x86_64.so | 3 + .../Resources/Info.plist | 37 + .../libdd3d.macos.editor.universal.dylib | 3 + .../Resources/Info.plist | 37 + ...s.template_release.universal.enabled.dylib | 3 + .../Resources/Info.plist | 37 + ...d3d.macos.template_release.universal.dylib | 3 + ...d3d.web.template_debug.wasm32.threads.wasm | 3 + .../libdd3d.web.template_debug.wasm32.wasm | 3 + ...d.web.template_release.wasm32.enabled.wasm | 3 + ...mplate_release.wasm32.threads.enabled.wasm | 3 + ...d.web.template_release.wasm32.threads.wasm | 3 + .../libdd3d.web.template_release.wasm32.wasm | 3 + .../libs/libdd3d.windows.editor.x86_64.dll | 3 + ...ibdd3d.windows.template_release.x86_64.dll | 3 + ...indows.template_release.x86_64.enabled.dll | 3 + examples_dd3d/DebugDrawDemoScene.gd | 621 ++++++++++ examples_dd3d/DebugDrawDemoScene.gd.uid | 1 + examples_dd3d/DebugDrawDemoScene.tscn | 1042 +++++++++++++++++ examples_dd3d/DebugDrawDemoSceneCS.cs | 854 ++++++++++++++ examples_dd3d/DebugDrawDemoSceneCS.cs.uid | 1 + examples_dd3d/DebugDrawDemoSceneCS.tscn | 16 + examples_dd3d/PixelatedElegance.ttf | 3 + examples_dd3d/PixelatedElegance.ttf.import | 35 + examples_dd3d/Roboto-Bold.ttf | 3 + examples_dd3d/Roboto-Bold.ttf.import | 39 + examples_dd3d/VisualizerAudioBus.tres | 17 + examples_dd3d/addon_icon.gd | 11 + examples_dd3d/addon_icon.gd.uid | 1 + examples_dd3d/addon_icon.tscn | 37 + examples_dd3d/demo_camera_movement.gd | 60 + examples_dd3d/demo_camera_movement.gd.uid | 1 + examples_dd3d/demo_music_visualizer.gd | 175 +++ examples_dd3d/demo_music_visualizer.gd.uid | 1 + examples_dd3d/demo_settings_panel.gd | 103 ++ examples_dd3d/demo_settings_panel.gd.uid | 1 + examples_dd3d/demo_web_docs_version_select.gd | 42 + .../demo_web_docs_version_select.gd.uid | 1 + 56 files changed, 3586 insertions(+) create mode 100644 addons/debug_draw_3d/LICENSE create mode 100644 addons/debug_draw_3d/README.md create mode 100644 addons/debug_draw_3d/debug_draw_3d.gdextension create mode 100644 addons/debug_draw_3d/debug_draw_3d.gdextension.uid create mode 100644 addons/debug_draw_3d/libs/.gdignore create mode 100644 addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm32.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm64.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_32.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_64.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.android.template_release.arm32.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.android.template_release.arm64.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_32.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_64.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.ios.template_debug.universal.dylib create mode 100644 addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.dylib create mode 100644 addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.enabled.dylib create mode 100644 addons/debug_draw_3d/libs/libdd3d.linux.editor.x86_64.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.enabled.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.so create mode 100644 addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/Resources/Info.plist create mode 100644 addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/libdd3d.macos.editor.universal.dylib create mode 100644 addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/Resources/Info.plist create mode 100644 addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/libdd3d.macos.template_release.universal.enabled.dylib create mode 100644 addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/Resources/Info.plist create mode 100644 addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/libdd3d.macos.template_release.universal.dylib create mode 100644 addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.threads.wasm create mode 100644 addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.wasm create mode 100644 addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.enabled.wasm create mode 100644 addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm create mode 100644 addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.wasm create mode 100644 addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.wasm create mode 100644 addons/debug_draw_3d/libs/libdd3d.windows.editor.x86_64.dll create mode 100644 addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.dll create mode 100644 addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.enabled.dll create mode 100644 examples_dd3d/DebugDrawDemoScene.gd create mode 100644 examples_dd3d/DebugDrawDemoScene.gd.uid create mode 100644 examples_dd3d/DebugDrawDemoScene.tscn create mode 100644 examples_dd3d/DebugDrawDemoSceneCS.cs create mode 100644 examples_dd3d/DebugDrawDemoSceneCS.cs.uid create mode 100644 examples_dd3d/DebugDrawDemoSceneCS.tscn create mode 100644 examples_dd3d/PixelatedElegance.ttf create mode 100644 examples_dd3d/PixelatedElegance.ttf.import create mode 100644 examples_dd3d/Roboto-Bold.ttf create mode 100644 examples_dd3d/Roboto-Bold.ttf.import create mode 100644 examples_dd3d/VisualizerAudioBus.tres create mode 100644 examples_dd3d/addon_icon.gd create mode 100644 examples_dd3d/addon_icon.gd.uid create mode 100644 examples_dd3d/addon_icon.tscn create mode 100644 examples_dd3d/demo_camera_movement.gd create mode 100644 examples_dd3d/demo_camera_movement.gd.uid create mode 100644 examples_dd3d/demo_music_visualizer.gd create mode 100644 examples_dd3d/demo_music_visualizer.gd.uid create mode 100644 examples_dd3d/demo_settings_panel.gd create mode 100644 examples_dd3d/demo_settings_panel.gd.uid create mode 100644 examples_dd3d/demo_web_docs_version_select.gd create mode 100644 examples_dd3d/demo_web_docs_version_select.gd.uid diff --git a/addons/debug_draw_3d/LICENSE b/addons/debug_draw_3d/LICENSE new file mode 100644 index 0000000..617a15b --- /dev/null +++ b/addons/debug_draw_3d/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 DmitriySalnikov + +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, andor 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. \ No newline at end of file diff --git a/addons/debug_draw_3d/README.md b/addons/debug_draw_3d/README.md new file mode 100644 index 0000000..3cd3961 --- /dev/null +++ b/addons/debug_draw_3d/README.md @@ -0,0 +1,157 @@ +![icon](/images/icon_3d_128.png) + +# Debug drawing utility for Godot + +This is an add-on for debug drawing in 3D and for some 2D overlays, which is written in `C++` and can be used with `GDScript` or `C#`. + +Based on my previous addon, which was developed [only for C#](https://github.com/DmitriySalnikov/godot_debug_draw_cs), and which was inspired by [Zylann's GDScript addon](https://github.com/Zylann/godot_debug_draw) + +## [Documentation](https://dd3d.dmitriysalnikov.ru/docs/) + +## [Godot 3 version](https://github.com/DmitriySalnikov/godot_debug_draw_3d/tree/godot_3) + +## Support me + +Your support adds motivation to develop my public projects. + +Boosty + +USDT-TRC20 + +USDT-TRC20 TEw934PrsffHsAn5M63SoHYRuZo984EF6v + +## Features + +3D: + +* Arrow +* Billboard opaque square +* Box +* Camera Frustum +* Cylinder +* Gizmo +* Grid +* Line +* Line Path +* Line with Arrow +* Plane +* Points +* Position 3D (3 crossing axes) +* Sphere +* 3D Text + +2D: + +* **[Work in progress]** + +Overlay: + +* Text (with grouping and coloring) + +Precompiled for: + +* Windows +* Linux (built on Ubuntu 22.04) +* macOS (10.15+) +* Android (5.0+) +* iOS +* Web (Firefox is supported by Godot 4.3+) + +This addon supports working with several World3D and different Viewports. +There is also a no depth test mode and other settings that can be changed for each instance. + +This library supports double-precision builds, for more information, [see the documentation](https://dd3d.dmitriysalnikov.ru/docs/?page=md_docs_2DoublePrecision.html). + +## [Interactive Web Demo](https://dd3d.dmitriysalnikov.ru/demo/) + +[![screenshot_web](/images/screenshot_web.png)](https://dd3d.dmitriysalnikov.ru/demo/) + +## Download + +To download, use the [Godot Asset Library](https://godotengine.org/asset-library/asset/1766) or use one of the stable versions from the [GitHub Releases](https://github.com/DmitriySalnikov/godot_debug_draw_3d/releases) page. + +For versions prior to `1.4.5`, just download one of the `source codes` in the assets. For newer versions, download `debug-draw-3d_[version].zip`. + +### Installation + +* Close editor +* Copy `addons/debug_draw_3d` to your `addons` folder, create it if the folder doesn't exist +* Launch editor + +## Examples + +More examples can be found in the `examples_dd3d/` folder. + +Simple test: + +```gdscript +func _process(delta: float) -> void: + var _time = Time.get_ticks_msec() / 1000.0 + var box_pos = Vector3(0, sin(_time * 4), 0) + var line_begin = Vector3(-1, sin(_time * 4), 0) + var line_end = Vector3(1, cos(_time * 4), 0) + + DebugDraw3D.draw_box(box_pos, Quaternion.IDENTITY, Vector3(1, 2, 1), Color(0, 1, 0)) + DebugDraw3D.draw_line(line_begin, line_end, Color(1, 1, 0)) + DebugDraw2D.set_text("Time", _time) + DebugDraw2D.set_text("Frames drawn", Engine.get_frames_drawn()) + DebugDraw2D.set_text("FPS", Engine.get_frames_per_second()) + DebugDraw2D.set_text("delta", delta) +``` + +![screenshot_1](/images/screenshot_1.png) + +An example of using scoped configs: + +```gdscript +@tool +extends Node3D + +func _ready(): + # Set the base scoped_config. + # Each frame will be reset to these scoped values. + DebugDraw3D.scoped_config().set_thickness(0.1).set_center_brightness(0.6) + +func _process(delta): + # Draw using the base scoped config. + DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE * 2, Color.CORNFLOWER_BLUE) + if true: + # Create a scoped config that will exist until exiting this if. + var _s = DebugDraw3D.new_scoped_config().set_thickness(0).set_center_brightness(0.1) + # Draw with a thickness of 0 + DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE, Color.RED) + # If necessary, the values inside this scope can be changed + # even before each call to draw_*. + _s.set_thickness(0.05) + DebugDraw3D.draw_box(Vector3(1,0,1), Quaternion.IDENTITY, Vector3.ONE * 1, Color.BLUE_VIOLET) +``` + +![screenshot_5](/images/screenshot_5.png) + +> [!TIP] +> +> If you want to use a non-standard Viewport for rendering a 3d scene, then do not forget to specify it in the scoped config! + +## API + +This project has a separate [documentation](https://dd3d.dmitriysalnikov.ru/docs/) page. + +Also, a list of all functions is available in the documentation inside the editor (see `DebugDraw3D` and `DebugDraw2D`). + +![screenshot_4](/images/screenshot_4.png) + +## Known issues and limitations + +The text in the keys and values of a text group cannot contain multi-line strings. + +The entire text overlay can only be placed in one corner. + +[Frustum of Camera3D does not take into account the window size from ProjectSettings](https://github.com/godotengine/godot/issues/70362). + +## More screenshots + +`DebugDrawDemoScene.tscn` in editor +![screenshot_2](/images/screenshot_2.png) + +`DebugDrawDemoScene.tscn` in play mode +![screenshot_3](/images/screenshot_3.png) diff --git a/addons/debug_draw_3d/debug_draw_3d.gdextension b/addons/debug_draw_3d/debug_draw_3d.gdextension new file mode 100644 index 0000000..cead527 --- /dev/null +++ b/addons/debug_draw_3d/debug_draw_3d.gdextension @@ -0,0 +1,153 @@ +[configuration] + +entry_symbol = "debug_draw_3d_library_init" +compatibility_minimum = "4.2.2" +reloadable = false + +[dependencies] + +; example.x86_64 = { "relative or absolute path to the dependency" : "the path relative to the exported project", } +; ------------------------------------- +; debug + +macos = { } +windows.x86_64 = { } +linux.x86_64 = { } + +; by default godot is using threads +web.wasm32.nothreads = {} +web.wasm32 = {} + +android.arm32 = { } +android.arm64 = { } +android.x86_32 = { } +android.x86_64 = { } + +ios = {} + +; ------------------------------------- +; release no debug draw + +macos.template_release = { } +windows.template_release.x86_64 = { } +linux.template_release.x86_64 = { } + +web.template_release.wasm32.nothreads = { } +web.template_release.wasm32 = { } + +android.template_release.arm32 = { } +android.template_release.arm64 = { } +android.template_release.x86_32 = { } +android.template_release.x86_64 = { } + +ios.template_release = {} + +; ------------------------------------- +; release forced debug draw + +macos.template_release.forced_dd3d = { } +windows.template_release.x86_64.forced_dd3d = { } +linux.template_release.x86_64.forced_dd3d = { } + +web.template_release.wasm32.nothreads.forced_dd3d = { } +web.template_release.wasm32.forced_dd3d = { } + +ios.template_release.forced_dd3d = {} + +[libraries] + +; ------------------------------------- +; debug + +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" + +web.wasm32.nothreads = "libs/libdd3d.web.template_debug.wasm32.wasm" +web.wasm32 = "libs/libdd3d.web.template_debug.wasm32.threads.wasm" + +android.arm32 = "libs/libdd3d.android.template_debug.arm32.so" +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" + +ios = "libs/libdd3d.ios.template_debug.universal.dylib" + +; ------------------------------------- +; release no debug draw + +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" + +web.template_release.wasm32.nothreads = "libs/libdd3d.web.template_release.wasm32.wasm" +web.template_release.wasm32 = "libs/libdd3d.web.template_release.wasm32.threads.wasm" + +android.template_release.arm32 = "libs/libdd3d.android.template_release.arm32.so" +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" + +ios.template_release = "libs/libdd3d.ios.template_release.universal.dylib" + +; ------------------------------------- +; release forced debug draw + +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" + +web.template_release.wasm32.nothreads.forced_dd3d = "libs/libdd3d.web.template_release.wasm32.enabled.wasm" +web.template_release.wasm32.forced_dd3d = "libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm" + +ios.template_release.forced_dd3d = "libs/libdd3d.ios.template_release.universal.enabled.dylib" + +; ------------------------------------- +; DOUBLE PRECISION +; ------------------------------------- + +; ------------------------------------- +; debug + +macos.double = "libs/libdd3d.macos.editor.universal.double.framework" +windows.x86_64.double = "libs/libdd3d.windows.editor.x86_64.double.dll" +linux.x86_64.double = "libs/libdd3d.linux.editor.x86_64.double.so" + +web.wasm32.nothreads.double = "libs/libdd3d.web.template_debug.wasm32.double.wasm" +web.wasm32.double = "libs/libdd3d.web.template_debug.wasm32.threads.double.wasm" + +android.arm32.double = "libs/libdd3d.android.template_debug.arm32.double.so" +android.arm64.double = "libs/libdd3d.android.template_debug.arm64.double.so" +android.x86_32.double = "libs/libdd3d.android.template_debug.x86_32.double.so" +android.x86_64.double = "libs/libdd3d.android.template_debug.x86_64.double.so" + +ios.double = "libs/libdd3d.ios.template_debug.universal.dylib" + +; ------------------------------------- +; release no debug draw + +macos.template_release.double = "libs/libdd3d.macos.template_release.universal.double.framework" +windows.template_release.x86_64.double = "libs/libdd3d.windows.template_release.x86_64.double.dll" +linux.template_release.x86_64.double = "libs/libdd3d.linux.template_release.x86_64.double.so" + +web.template_release.wasm32.nothreads.double = "libs/libdd3d.web.template_release.wasm32.double.wasm" +web.template_release.wasm32.double = "libs/libdd3d.web.template_release.wasm32.threads.double.wasm" + +android.template_release.arm32.double = "libs/libdd3d.android.template_release.arm32.double.so" +android.template_release.arm64.double = "libs/libdd3d.android.template_release.arm64.double.so" +android.template_release.x86_32.double = "libs/libdd3d.android.template_release.x86_32.double.so" +android.template_release.x86_64.double = "libs/libdd3d.android.template_release.x86_64.double.so" + +ios.template_release.double = "libs/libdd3d.ios.template_release.universal.double.dylib" + +; ------------------------------------- +; release forced debug draw + +macos.template_release.forced_dd3d.double = "libs/libdd3d.macos.template_release.universal.enabled.double.framework" +windows.template_release.x86_64.forced_dd3d.double = "libs/libdd3d.windows.template_release.x86_64.enabled.double.dll" +linux.template_release.x86_64.forced_dd3d.double = "libs/libdd3d.linux.template_release.x86_64.enabled.double.so" + +web.template_release.wasm32.nothreads.forced_dd3d.double = "libs/libdd3d.web.template_release.wasm32.enabled.double.wasm" +web.template_release.wasm32.forced_dd3d.double = "libs/libdd3d.web.template_release.wasm32.threads.enabled.double.wasm" + +ios.template_release.forced_dd3d.double = "libs/libdd3d.ios.template_release.universal.enabled.double.dylib" diff --git a/addons/debug_draw_3d/debug_draw_3d.gdextension.uid b/addons/debug_draw_3d/debug_draw_3d.gdextension.uid new file mode 100644 index 0000000..15da0d3 --- /dev/null +++ b/addons/debug_draw_3d/debug_draw_3d.gdextension.uid @@ -0,0 +1 @@ +uid://svqaxfp5kyrl diff --git a/addons/debug_draw_3d/libs/.gdignore b/addons/debug_draw_3d/libs/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm32.so b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm32.so new file mode 100644 index 0000000..5a6169f --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm32.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a13a936094bdb1fd8d8696c4776df9eba163631157a78a8a194fd67c8f1619e8 +size 1070740 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm64.so b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm64.so new file mode 100644 index 0000000..c4a5373 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18ed71ec4650615b91bc9366b6fab152519bf3fb2572f4593c9d107f5af14b71 +size 942832 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_32.so b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_32.so new file mode 100644 index 0000000..e9ee02d --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_32.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e276acc613beb3c1441e1575add0064414fd0b0176901d0425e6860b577a68e0 +size 979384 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_64.so b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_64.so new file mode 100644 index 0000000..75d6c8c --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff8f3e63878a9dfea04d0caa39885aff2da20fbf6048eddde59352fcd0e9d4fe +size 1025552 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm32.so b/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm32.so new file mode 100644 index 0000000..7fff4dd --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm32.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a6366cfe23826d0603aca5e682ca08ac237a68d8482da0dd56af6f1d2be797b +size 744532 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm64.so b/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm64.so new file mode 100644 index 0000000..c629b96 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c50971c8a07204ebeb0ae8ed4f5994d0cb42ba1953e3f5a8ea6d9fc18d0bc8f +size 653280 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_32.so b/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_32.so new file mode 100644 index 0000000..d430abd --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_32.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca28332705b88569b2ef5b09ca1503f7014a327ea5d45391bb048df37c7198bf +size 667848 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_64.so b/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_64.so new file mode 100644 index 0000000..c1cf211 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d7c5f77a7c9f0fc065ae00b78a72d7f73bdcb5637501449c4cf7ac4730ac668 +size 705568 diff --git a/addons/debug_draw_3d/libs/libdd3d.ios.template_debug.universal.dylib b/addons/debug_draw_3d/libs/libdd3d.ios.template_debug.universal.dylib new file mode 100644 index 0000000..b460976 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.ios.template_debug.universal.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a71ff0d07bf2ac8fd2f3e0e8537b0d45d0bba3327c8b85a2f462cfef16802d3c +size 923288 diff --git a/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.dylib b/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.dylib new file mode 100644 index 0000000..79466c9 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd0096e5bdff49f33ab110000730dde56f7eff316879face9f2535ea90f53b93 +size 675816 diff --git a/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.enabled.dylib b/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.enabled.dylib new file mode 100644 index 0000000..c52a56c --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.enabled.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:544521ef419a8050dec95803aa58f6a719df2c4a4d8fbd1a907fb1f96e5bf155 +size 955824 diff --git a/addons/debug_draw_3d/libs/libdd3d.linux.editor.x86_64.so b/addons/debug_draw_3d/libs/libdd3d.linux.editor.x86_64.so new file mode 100644 index 0000000..abbaf4d --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.linux.editor.x86_64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6f5cec2a65a2581335444dcdceb6f044e72719f82da597ce08a110abd9f889b7 +size 2586424 diff --git a/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.enabled.so b/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.enabled.so new file mode 100644 index 0000000..fe161f6 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.enabled.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6df92bce5ee17015019b36090268970c30c1aee84beaa88fab02cc903ab4cde0 +size 2258464 diff --git a/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.so b/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.so new file mode 100644 index 0000000..cf6cc0f --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:407a8451cc1abebc5075c549dc78a9e647fd4582e0f21940d6e9834a14c21fd4 +size 1967552 diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/Resources/Info.plist b/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/Resources/Info.plist new file mode 100644 index 0000000..933a7f8 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/Resources/Info.plist @@ -0,0 +1,37 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + libdd3d.macos.editor.universal.dylib + CFBundleName + Debug Draw 3D + CFBundleDisplayName + Debug Draw 3D + CFBundleIdentifier + ru.dmitriysalnikov.dd3d + NSHumanReadableCopyright + Copyright (c) Dmitriy Salnikov. + CFBundleVersion + 1.5.1 + CFBundleShortVersionString + 1.5.1 + CFBundlePackageType + FMWK + CSResourcesFileMapped + + DTPlatformName + macosx + LSMinimumSystemVersion + 10.14 + CFBundleSupportedPlatforms + + MacOSX + + + + \ No newline at end of file diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/libdd3d.macos.editor.universal.dylib b/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/libdd3d.macos.editor.universal.dylib new file mode 100644 index 0000000..41bcab6 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/libdd3d.macos.editor.universal.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f377cdcf3da122e00f7292d33511079cc0bd6a379444755381bb0e32c55137c4 +size 2525848 diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/Resources/Info.plist b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/Resources/Info.plist new file mode 100644 index 0000000..33bf631 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/Resources/Info.plist @@ -0,0 +1,37 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + libdd3d.macos.template_release.universal.enabled.dylib + CFBundleName + Debug Draw 3D + CFBundleDisplayName + Debug Draw 3D + CFBundleIdentifier + ru.dmitriysalnikov.dd3d + NSHumanReadableCopyright + Copyright (c) Dmitriy Salnikov. + CFBundleVersion + 1.5.1 + CFBundleShortVersionString + 1.5.1 + CFBundlePackageType + FMWK + CSResourcesFileMapped + + DTPlatformName + macosx + LSMinimumSystemVersion + 10.14 + CFBundleSupportedPlatforms + + MacOSX + + + + \ No newline at end of file diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/libdd3d.macos.template_release.universal.enabled.dylib b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/libdd3d.macos.template_release.universal.enabled.dylib new file mode 100644 index 0000000..af5e917 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/libdd3d.macos.template_release.universal.enabled.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef07b4c9bdb93f305ff4fbd558283c40da74f41b99204ce502d462441591dc55 +size 1931080 diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/Resources/Info.plist b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/Resources/Info.plist new file mode 100644 index 0000000..0b36e0b --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/Resources/Info.plist @@ -0,0 +1,37 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + libdd3d.macos.template_release.universal.dylib + CFBundleName + Debug Draw 3D + CFBundleDisplayName + Debug Draw 3D + CFBundleIdentifier + ru.dmitriysalnikov.dd3d + NSHumanReadableCopyright + Copyright (c) Dmitriy Salnikov. + CFBundleVersion + 1.5.1 + CFBundleShortVersionString + 1.5.1 + CFBundlePackageType + FMWK + CSResourcesFileMapped + + DTPlatformName + macosx + LSMinimumSystemVersion + 10.14 + CFBundleSupportedPlatforms + + MacOSX + + + + \ No newline at end of file diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/libdd3d.macos.template_release.universal.dylib b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/libdd3d.macos.template_release.universal.dylib new file mode 100644 index 0000000..a02c470 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/libdd3d.macos.template_release.universal.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11427fad2d43c89248cfc1e8dccdd76f21ee9f1f9466f4ed264927668a3d3d46 +size 1337264 diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.threads.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.threads.wasm new file mode 100644 index 0000000..1a62ebc --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.threads.wasm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa4991502d6ebd6bca87c0dbf87bfb69e1933787dc7a596d548c4b0345a377d6 +size 1377955 diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.wasm new file mode 100644 index 0000000..d4dbadd --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.wasm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0a00a28793a77ff73e4512381c4424b5c66c5d829f9f57a26bcf3b28d97b05a +size 1613410 diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.enabled.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.enabled.wasm new file mode 100644 index 0000000..3b4d840 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.enabled.wasm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d66a8e47e862caf25a1b0dc5c079fb78c8c694cb52a18224b0aaf925ee74648 +size 1585140 diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm new file mode 100644 index 0000000..52dcb2c --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f08cbc0b9424c863e3b46274fe07b41e8182a33e12e1a4ad57c7505cd46f7ebc +size 1419533 diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.wasm new file mode 100644 index 0000000..381309a --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.wasm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db9de4eda6ea1ec619de51eb8035abab1b07efa1603283babc1bea9bbf3db943 +size 1110445 diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.wasm new file mode 100644 index 0000000..5af2e45 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.wasm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38dda420ef63cb79820bb7f74b35d923e777f6ea79347cab5db9bafbdf36e2fd +size 1141046 diff --git a/addons/debug_draw_3d/libs/libdd3d.windows.editor.x86_64.dll b/addons/debug_draw_3d/libs/libdd3d.windows.editor.x86_64.dll new file mode 100644 index 0000000..d032e2b --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.windows.editor.x86_64.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f59a3349bc838fb34ddb45f50828b232733bdc8e35f38cecf1e9a133c90dabf +size 1323008 diff --git a/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.dll b/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.dll new file mode 100644 index 0000000..e1c83ae --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c2daa6ba64696f1b5aebd84e19331fbdfa31ce8745f48203b6f2e628507d7043 +size 612352 diff --git a/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.enabled.dll b/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.enabled.dll new file mode 100644 index 0000000..eb0053b --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.enabled.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5094da797fde8008625a02477f519ab3ca0c2d6aa91990928ebfb066cdd31f72 +size 885760 diff --git a/examples_dd3d/DebugDrawDemoScene.gd b/examples_dd3d/DebugDrawDemoScene.gd new file mode 100644 index 0000000..8c4ef15 --- /dev/null +++ b/examples_dd3d/DebugDrawDemoScene.gd @@ -0,0 +1,621 @@ +@tool +extends Node3D + +@export var custom_font : Font +@export var custom_3d_font : Font +@export var zylann_example := false +@export var update_in_physics := false +@export var test_text := true +@export var more_test_cases := true +@export var draw_3d_text := true +@export var draw_array_of_boxes := false +@export var draw_text_with_boxes := false +@export var draw_1m_boxes := false +@export_range(0, 5, 0.001) var debug_thickness := 0.1 +@export_range(0, 1, 0.001) var debug_center_brightness := 0.8 +@export_range(0, 1) var camera_frustum_scale := 0.9 + +@export_group("Text groups", "text_groups") +@export var text_groups_show_examples := true +@export var text_groups_show_hints := true +@export var text_groups_show_stats := false +@export var text_groups_show_stats_2d := false +@export var text_groups_position := DebugDraw2DConfig.POSITION_LEFT_TOP +@export var text_groups_offset := Vector2i(8, 8) +@export var text_groups_padding := Vector2i(3, 1) +@export_range(1, 100) var text_groups_default_font_size := 15 +@export_range(1, 100) var text_groups_title_font_size := 20 +@export_range(1, 100) var text_groups_text_font_size := 17 + +@export_group("Tests", "tests") +@export var tests_use_threads := false +var test_thread : Thread = null +var test_thread_closing := false + +var button_presses := {} +var frame_rendered := false +var physics_tick_processed := false + +var timer_1 := 0.0 +var timer_cubes := 0.0 +var timer_3 := 0.0 +var timer_text := 0.0 + + +func _process(delta) -> void: + #print("Label3Ds count: %d" % get_child(0).get_child_count() if Engine.is_editor_hint() else get_tree().root.get_child(0).get_child_count()) + + $OtherWorld.mesh.material.set_shader_parameter("albedo_texture", $OtherWorld/SubViewport.get_texture()) + + physics_tick_processed = false + if not update_in_physics: + main_update(delta) + _update_timers(delta) + + _call_from_thread() + + +## Since physics frames may not be called every frame or may be called multiple times in one frame, +## there is an additional check to ensure that a new frame has been drawn before updating the data. +func _physics_process(delta: float) -> void: + if not physics_tick_processed: + physics_tick_processed = true + if update_in_physics: + main_update(delta) + _update_timers(delta) + + # Physics specific: + if not zylann_example: + DebugDraw3D.draw_line($"Lines/8".global_position, $Lines/Target.global_position, Color.YELLOW) + + if more_test_cases: + _draw_rays_casts() + + ## Additional drawing in the Viewport + if true: + var _w1 = DebugDraw3D.new_scoped_config().set_viewport(%OtherWorldBox.get_viewport()).set_thickness(0.01).set_center_brightness(1).set_no_depth_test(true) + DebugDraw3D.draw_box_xf(Transform3D(Basis() + .scaled(Vector3.ONE*0.3) + .rotated(Vector3(0,0,1), PI/4) + .rotated(Vector3(0,1,0), wrapf(Time.get_ticks_msec() / -1500.0, 0, TAU) - PI/4), %OtherWorldBox.global_transform.origin), + Color.BROWN, true, 0.4) + + +func main_update(delta: float) -> void: + DebugDraw3D.scoped_config().set_thickness(debug_thickness).set_center_brightness(debug_center_brightness) + + _update_keys_just_press() + + if _is_key_just_pressed(KEY_F1): + zylann_example = !zylann_example + + # Zylann's example :D + if zylann_example: + var _time = Time.get_ticks_msec() / 1000.0 + var box_pos = Vector3(0, sin(_time * 4), 0) + var line_begin = Vector3(-1, sin(_time * 4), 0) + var line_end = Vector3(1, cos(_time * 4), 0) + + DebugDraw3D.draw_box(box_pos, Quaternion.IDENTITY, Vector3(1, 2, 1), Color(0, 1, 0)) + DebugDraw3D.draw_line(line_begin, line_end, Color(1, 1, 0)) + DebugDraw2D.set_text("Time", _time) + DebugDraw2D.set_text("Frames drawn", Engine.get_frames_drawn()) + DebugDraw2D.set_text("FPS", Engine.get_frames_per_second()) + DebugDraw2D.set_text("delta", delta) + + $HitTest.visible = false + $LagTest.visible = false + $PlaneOrigin.visible = false + $OtherWorld.visible = false + %ZDepthTestCube.visible = false + return + + $HitTest.visible = true + $LagTest.visible = true + $PlaneOrigin.visible = true + $OtherWorld.visible = true + %ZDepthTestCube.visible = true + + # Testing the rendering layers by showing the image from the second camera inside the 2D panel + DebugDraw3D.config.geometry_render_layers = 1 if not Input.is_key_pressed(KEY_ALT) else 0b10010 + $Panel.visible = Input.is_key_pressed(KEY_ALT) + DebugDraw2D.custom_canvas = %CustomCanvas if Input.is_key_pressed(KEY_ALT) else null + + # More property toggles + DebugDraw3D.config.freeze_3d_render = Input.is_key_pressed(KEY_DOWN) + DebugDraw3D.config.visible_instance_bounds = Input.is_key_pressed(KEY_RIGHT) + + # Regenerate meshes + if Input.is_action_just_pressed("ui_end"): + DebugDraw3D.regenerate_geometry_meshes() + + # Some property toggles + if _is_key_just_pressed(KEY_LEFT): + DebugDraw3D.config.use_frustum_culling = !DebugDraw3D.config.use_frustum_culling + if _is_key_just_pressed(KEY_UP): + DebugDraw3D.config.force_use_camera_from_scene = !DebugDraw3D.config.force_use_camera_from_scene + if _is_key_just_pressed(KEY_CTRL): + if not Engine.is_editor_hint(): + get_viewport().msaa_3d = Viewport.MSAA_DISABLED if get_viewport().msaa_3d == Viewport.MSAA_4X else Viewport.MSAA_4X + + if not Engine.is_editor_hint(): + if _is_key_just_pressed(KEY_1): + DebugDraw3D.debug_enabled = !DebugDraw3D.debug_enabled + if _is_key_just_pressed(KEY_2): + DebugDraw2D.debug_enabled = !DebugDraw2D.debug_enabled + if _is_key_just_pressed(KEY_3): + DebugDrawManager.debug_enabled = !DebugDrawManager.debug_enabled + + + DebugDraw3D.config.frustum_length_scale = camera_frustum_scale + + # Zones with black borders + for z in $Zones.get_children(): + DebugDraw3D.draw_box_xf(z.global_transform, Color.BLACK) + + # Spheres + _draw_zone_title(%SpheresBox, "Spheres") + + DebugDraw3D.draw_sphere_xf($Spheres/SphereTransform.global_transform, Color.CRIMSON) + if true: + var _shd = DebugDraw3D.new_scoped_config().set_hd_sphere(true) + DebugDraw3D.draw_sphere_xf($Spheres/SphereHDTransform.global_transform, Color.ORANGE_RED) + + ## Delayed spheres + if timer_1 < 0: + DebugDraw3D.draw_sphere($Spheres/SpherePosition.global_position, 2.0, Color.BLUE_VIOLET, 2.0) + var _shd = DebugDraw3D.new_scoped_config().set_hd_sphere(true) + DebugDraw3D.draw_sphere($Spheres/SpherePosition.global_position + Vector3.FORWARD * 4, 2.0, Color.CORNFLOWER_BLUE, 2.0) + timer_1 = 2 + + # Cylinders + _draw_zone_title(%CylindersBox, "Cylinders") + + DebugDraw3D.draw_cylinder($Cylinders/Cylinder1.global_transform, Color.CRIMSON) + DebugDraw3D.draw_cylinder(Transform3D(Basis.IDENTITY.scaled(Vector3(1,2,1)), $Cylinders/Cylinder2.global_position), Color.RED) + DebugDraw3D.draw_cylinder_ab($"Cylinders/Cylinder3/1".global_position, $"Cylinders/Cylinder3/2".global_position, 0.7) + + # Boxes + _draw_zone_title(%BoxesBox, "Boxes") + + DebugDraw3D.draw_box_xf($Boxes/Box1.global_transform, Color.MEDIUM_PURPLE) + DebugDraw3D.draw_box($Boxes/Box2.global_position, Quaternion.from_euler(Vector3(0, deg_to_rad(45), deg_to_rad(45))), Vector3.ONE, Color.REBECCA_PURPLE) + DebugDraw3D.draw_box_xf(Transform3D(Basis(Vector3.UP, PI * 0.25).scaled(Vector3.ONE * 2), $Boxes/Box3.global_position), Color.ROSY_BROWN) + + DebugDraw3D.draw_aabb(AABB($Boxes/AABB_fixed.global_position, Vector3(2, 1, 2)), Color.AQUA) + DebugDraw3D.draw_aabb_ab($Boxes/AABB/a.global_position, $Boxes/AABB/b.global_position, Color.DEEP_PINK) + + # Boxes AB + DebugDraw3D.draw_arrow($Boxes/BoxAB.global_position, $Boxes/BoxAB/o/up.global_position, Color.GOLD, 0.1, true) + DebugDraw3D.draw_box_ab($Boxes/BoxAB/a.global_position, $Boxes/BoxAB/b.global_position, $Boxes/BoxAB/o/up.global_position - $Boxes/BoxAB.global_position, Color.PERU) + + DebugDraw3D.draw_arrow($Boxes/BoxABEdge.global_position, $Boxes/BoxABEdge/o/up.global_position, Color.DARK_RED, 0.1, true) + DebugDraw3D.draw_box_ab($Boxes/BoxABEdge/a.global_position, $Boxes/BoxABEdge/b.global_position, $Boxes/BoxABEdge/o/up.global_position - $Boxes/BoxABEdge.global_position, Color.DARK_OLIVE_GREEN, false) + + # Lines + _draw_zone_title(%LinesBox, "Lines") + + var target = $Lines/Target + DebugDraw3D.draw_square(target.global_position, 0.5, Color.RED) + + DebugDraw3D.draw_line($"Lines/1".global_position, target.global_position, Color.FUCHSIA) + DebugDraw3D.draw_ray($"Lines/3".global_position, (target.global_position - $"Lines/3".global_position).normalized(), 3.0, Color.CRIMSON) + + if timer_3 < 0: + DebugDraw3D.draw_line($"Lines/6".global_position, target.global_position, Color.FUCHSIA, 2.0) + timer_3 = 2 + + # Test UP vector + DebugDraw3D.draw_line($"Lines/7".global_position, target.global_position, Color.RED) + + # Lines with Arrow + DebugDraw3D.draw_arrow($"Lines/2".global_position, target.global_position, Color.BLUE, 0.5, true) + DebugDraw3D.draw_arrow_ray($"Lines/4".global_position, (target.global_position - $"Lines/4".global_position).normalized(), 8.0, Color.LAVENDER, 0.5, true) + + DebugDraw3D.draw_line_hit_offset($"Lines/5".global_position, target.global_position, true, abs(sin(Time.get_ticks_msec() / 1000.0)), 0.25, Color.AQUA) + + # Paths + _draw_zone_title(%PathsBox, "Paths") + + ## preparing data + var points: PackedVector3Array = [] + var points_below: PackedVector3Array = [] + var points_below2: PackedVector3Array = [] + var points_below3: PackedVector3Array = [] + var points_below4: PackedVector3Array = [] + var lines_above: PackedVector3Array = [] + + for c in $LinePath.get_children(): + if not c is Node3D: + break + points.append(c.global_position) + points_below.append(c.global_position + Vector3.DOWN) + points_below2.append(c.global_position + Vector3.DOWN * 2) + points_below3.append(c.global_position + Vector3.DOWN * 3) + points_below4.append(c.global_position + Vector3.DOWN * 4) + + for x in points.size()-1: + lines_above.append(points[x] + Vector3.UP) + lines_above.append(points[x+1] + Vector3.UP) + + ## drawing lines + DebugDraw3D.draw_lines(lines_above) + DebugDraw3D.draw_line_path(points, Color.BEIGE) + DebugDraw3D.draw_points(points_below, DebugDraw3D.POINT_TYPE_SQUARE, 0.2, Color.DARK_GREEN) + DebugDraw3D.draw_point_path(points_below2, DebugDraw3D.POINT_TYPE_SQUARE, 0.25, Color.BLUE, Color.TOMATO) + DebugDraw3D.draw_arrow_path(points_below3, Color.GOLD, 0.5) + if true: + var _sl = DebugDraw3D.new_scoped_config().set_thickness(0.05) + DebugDraw3D.draw_point_path(points_below4, DebugDraw3D.POINT_TYPE_SPHERE, 0.25, Color.MEDIUM_SEA_GREEN, Color.MEDIUM_VIOLET_RED) + + # Misc + _draw_zone_title(%MiscBox, "Misc") + + if Engine.is_editor_hint(): + #for i in 1000: + var _a11 = DebugDraw3D.new_scoped_config().set_thickness(0) + DebugDraw3D.draw_camera_frustum($Camera, Color.DARK_ORANGE) + + if true: + var _s123 = DebugDraw3D.new_scoped_config().set_center_brightness(0.1) + DebugDraw3D.draw_arrowhead($Misc/Arrow.global_transform, Color.YELLOW_GREEN) + + DebugDraw3D.draw_square($Misc/Billboard.global_position, 0.5, Color.GREEN) + + DebugDraw3D.draw_position($Misc/Position.global_transform, Color.BROWN) + + DebugDraw3D.draw_gizmo($Misc/GizmoTransform.global_transform, DebugDraw3D.empty_color, true) + DebugDraw3D.draw_gizmo($Misc/GizmoOneColor.global_transform, Color.BROWN, true) + if true: + var _s123 = DebugDraw3D.new_scoped_config().set_center_brightness(0.5).set_no_depth_test(true) + DebugDraw3D.draw_gizmo($Misc/GizmoNormal.global_transform.orthonormalized(), DebugDraw3D.empty_color, false) + + # Grids + _draw_zone_title_pos($Grids/GridCentered.global_position + Vector3(0, 1.5, 0), "Grids", 96, 36) + + var tg : Transform3D = $Grids/Grid.global_transform + var tn : Vector3 = $Grids/Grid/Subdivision.transform.origin + DebugDraw3D.draw_grid(tg.origin, tg.basis.x, tg.basis.z, Vector2i(int(tn.x*10), int(tn.z*10)), Color.LIGHT_CORAL, false) + + var tn1 = $Grids/GridCentered/Subdivision.transform.origin + DebugDraw3D.draw_grid_xf($Grids/GridCentered.global_transform, Vector2i(tn1.x*10, tn1.z*10)) + + if true: + var _s32 = DebugDraw3D.new_scoped_config().set_thickness(0.05) + DebugDraw3D.draw_box_xf($PostProcess.global_transform, Color.SEA_GREEN) + + # Local transform + _draw_local_xf_box(%LocalTransformRecursiveOrigin.global_transform, 0.05, 10) + + # 2D + DebugDraw2D.config.text_default_size = text_groups_default_font_size + DebugDraw2D.config.text_block_offset = text_groups_offset + DebugDraw2D.config.text_block_position = text_groups_position + DebugDraw2D.config.text_padding = text_groups_padding + + DebugDraw2D.config.text_custom_font = custom_font + + if test_text: + _text_tests() + + # Lag Test + var lag_test_pos = $LagTest/RESET.get_animation("RESET").track_get_key_value(0,0) + _draw_zone_title_pos(lag_test_pos, "Lag test") + + $LagTest.position = lag_test_pos + Vector3(sin(Time.get_ticks_msec() / 100.0) * 2.5, 0, 0) + DebugDraw3D.draw_box($LagTest.global_position, Quaternion.IDENTITY, Vector3.ONE * 2.01, Color.CHOCOLATE, true) + + if more_test_cases: + for ray in $HitTest/RayEmitter.get_children(): + ray.set_physics_process_internal(true) + + _more_tests() + else: + for ray in $HitTest/RayEmitter.get_children(): + ray.set_physics_process_internal(false) + + _draw_other_world() + + if draw_array_of_boxes: + _draw_array_of_boxes() + + +func _text_tests(): + DebugDraw2D.set_text("FPS", "%.2f" % Engine.get_frames_per_second(), 0, Color.GOLD) + + if text_groups_show_examples: + if timer_text < 0: + DebugDraw2D.set_text("Some delayed text", "for 2.5s", -1, Color.BLACK, 2.5) # it's supposed to show text for 2.5 seconds + timer_text = 5 + + DebugDraw2D.begin_text_group("-- First Group --", 2, Color.LIME_GREEN, true, text_groups_title_font_size, text_groups_text_font_size) + DebugDraw2D.set_text("Simple text") + DebugDraw2D.set_text("Text", "Value", 0, Color.AQUAMARINE) + DebugDraw2D.set_text("Text out of order", null, -1, Color.SILVER) + DebugDraw2D.begin_text_group("-- Second Group --", 1, Color.BEIGE) + DebugDraw2D.set_text("Rendered frames", Engine.get_frames_drawn()) + DebugDraw2D.end_text_group() + + if text_groups_show_stats or text_groups_show_stats_2d: + DebugDraw2D.begin_text_group("-- Stats --", 3, Color.WHEAT) + + var render_stats := DebugDraw3D.get_render_stats() + if render_stats && text_groups_show_stats: + DebugDraw2D.set_text("Total", render_stats.total_geometry) + DebugDraw2D.set_text("Instances", render_stats.instances + render_stats.instances_physics, 1) + DebugDraw2D.set_text("Lines", render_stats.lines + render_stats.lines_physics, 2) + DebugDraw2D.set_text("Total Visible", render_stats.total_visible, 3) + DebugDraw2D.set_text("Visible Instances", render_stats.visible_instances, 4) + DebugDraw2D.set_text("Visible Lines", render_stats.visible_lines, 5) + + DebugDraw2D.set_text("---", null, 12) + + DebugDraw2D.set_text("Culling time", "%.2f ms" % (render_stats.total_time_culling_usec / 1000.0), 13) + DebugDraw2D.set_text("Filling instances buffer", "%.2f ms" % (render_stats.time_filling_buffers_instances_usec / 1000.0), 14) + DebugDraw2D.set_text("Filling lines buffer", "%.2f ms" % (render_stats.time_filling_buffers_lines_usec / 1000.0), 15) + DebugDraw2D.set_text("Filling time", "%.2f ms" % (render_stats.total_time_filling_buffers_usec / 1000.0), 16) + DebugDraw2D.set_text("Total time", "%.2f ms" % (render_stats.total_time_spent_usec / 1000.0), 17) + + DebugDraw2D.set_text("----", null, 32) + + DebugDraw2D.set_text("Total Label3D", render_stats.nodes_label3d_exists_total, 33) + DebugDraw2D.set_text("Visible Label3D", render_stats.nodes_label3d_visible + render_stats.nodes_label3d_visible_physics, 34) + + DebugDraw2D.set_text("-----", null, 48) + + DebugDraw2D.set_text("Created scoped configs", "%d" % render_stats.created_scoped_configs, 49) + + if text_groups_show_stats && text_groups_show_stats_2d: + DebugDraw2D.set_text("------", null, 64) + + var render_stats_2d := DebugDraw2D.get_render_stats() + if render_stats_2d && text_groups_show_stats_2d: + DebugDraw2D.set_text("Text groups", render_stats_2d.overlay_text_groups, 96) + DebugDraw2D.set_text("Text lines", render_stats_2d.overlay_text_lines, 97) + + DebugDraw2D.end_text_group() + + if text_groups_show_hints: + DebugDraw2D.begin_text_group("controls", 1024, Color.WHITE, false) + if not Engine.is_editor_hint(): + DebugDraw2D.set_text("WASD QE, LMB", "To move", 0) + DebugDraw2D.set_text("Alt: change render layers", DebugDraw3D.config.geometry_render_layers, 1) + if not OS.has_feature("web"): + DebugDraw2D.set_text("Ctrl: toggle anti-aliasing", "MSAA 4x" if get_viewport().msaa_3d == Viewport.MSAA_4X else "Disabled", 2) + DebugDraw2D.set_text("Down: freeze render", DebugDraw3D.config.freeze_3d_render, 3) + if Engine.is_editor_hint(): + DebugDraw2D.set_text("Up: use scene camera", DebugDraw3D.config.force_use_camera_from_scene, 4) + DebugDraw2D.set_text("1,2,3: toggle debug", "%s, %s 😐, %s 😏" % [DebugDraw3D.debug_enabled, DebugDraw2D.debug_enabled, DebugDrawManager.debug_enabled], 5) + DebugDraw2D.set_text("Left: toggle frustum culling", DebugDraw3D.config.use_frustum_culling, 6) + DebugDraw2D.set_text("Right: draw bounds for culling", DebugDraw3D.config.visible_instance_bounds, 7) + DebugDraw2D.end_text_group() + + +func _draw_zone_title(node: Node3D, title: String): + if draw_3d_text: + var _s1 = DebugDraw3D.new_scoped_config().set_text_outline_size(72) + DebugDraw3D.draw_text(node.global_position + node.global_basis.y * 0.85, title, 128) + + +func _draw_zone_title_pos(pos: Vector3, title: String, font_size: int = 128, outline: int = 72): + if draw_3d_text: + var _s1 = DebugDraw3D.new_scoped_config().set_text_outline_size(outline) + DebugDraw3D.draw_text(pos, title, font_size) + + +const _local_mul := 0.45 +const _local_mul_vec := Vector3(_local_mul, _local_mul, _local_mul) +var __local_lines_cross_recursive = PackedVector3Array([Vector3(-0.5, -0.5, -0.5), Vector3(0.5, -0.5, 0.5), Vector3(-0.5, -0.5, 0.5), Vector3(0.5, -0.5, -0.5)]) +var __local_box_recursive = Transform3D.IDENTITY.rotated_local(Vector3.UP, deg_to_rad(30)).translated(Vector3(-0.25, -0.55, 0.25)).scaled(_local_mul_vec) +var __local_sphere_recursive = Transform3D.IDENTITY.translated(Vector3(0.5, 0.55, -0.5)).scaled(_local_mul_vec) + +func _draw_local_xf_box(xf: Transform3D, thickness: float, max_depth: int, depth: int = 0): + if depth >= max_depth: + return + + var _s1 = DebugDraw3D.new_scoped_config().set_thickness(thickness).set_transform(xf) + + # a box with a small offset + DebugDraw3D.draw_box_xf(Transform3D(Basis(), Vector3(0, 0.001, 0)), Color.BROWN) + # a box and a stand for the next depth + DebugDraw3D.draw_box_xf(__local_box_recursive, Color.CHARTREUSE) + # just a sphere and lines + DebugDraw3D.draw_sphere_xf(__local_sphere_recursive, Color.DARK_ORANGE) + _s1.set_thickness(0) + DebugDraw3D.draw_lines(__local_lines_cross_recursive, Color.CRIMSON) + + # A simple animation generator with descent into the depth of the scene + if false: + var anim: Animation = %RecursiveTransformTest.get_animation("recursive") + # clear keys + if depth == 0: for i in anim.track_get_key_count(0): anim.track_remove_key(0, 0); anim.track_remove_key(1, 0) + + var time = depth * 2 + var s_xf = xf * __local_sphere_recursive + var next_s_xf = (xf * __local_box_recursive.translated(__local_box_recursive.basis.y)) * __local_sphere_recursive + var get_sphere_pos = func(l_xf): return l_xf.origin + (l_xf).basis.y + anim.position_track_insert_key(0, time, get_sphere_pos.call(s_xf)) + anim.rotation_track_insert_key(1, time, Transform3D(Basis(), get_sphere_pos.call(s_xf)).looking_at(get_sphere_pos.call(next_s_xf), xf.basis.y).basis.get_rotation_quaternion()) + + _draw_local_xf_box(xf * __local_box_recursive.translated(__local_box_recursive.basis.y), thickness * _local_mul, max_depth, depth + 1) + + +func _draw_other_world(): + var _w1 = DebugDraw3D.new_scoped_config().set_viewport(%OtherWorldBox.get_viewport()) + DebugDraw3D.draw_box_xf(%OtherWorldBox.global_transform.rotated_local(Vector3(1,1,-1).normalized(), wrapf(Time.get_ticks_msec() / 1000.0, 0, TAU)), Color.SANDY_BROWN) + DebugDraw3D.draw_box_xf(%OtherWorldBox.global_transform.rotated_local(Vector3(-1,1,-1).normalized(), wrapf(Time.get_ticks_msec() / -1000.0, 0, TAU) - PI/4), Color.SANDY_BROWN) + + if draw_3d_text: + var angle = wrapf(Time.get_ticks_msec() / 1000.0, 0, TAU) + if true: + var _w2 = DebugDraw3D.new_scoped_config().set_text_font(custom_3d_font) + DebugDraw3D.draw_text(%OtherWorldBox.global_position + Vector3(cos(angle), -0.25, sin(angle)), "Hello world!", 32, Color.CRIMSON, 0) + + if true: + var _w3 = DebugDraw3D.new_scoped_config().set_no_depth_test(true).set_text_outline_color(Color.INDIAN_RED).set_text_outline_size(6) + DebugDraw3D.draw_text(%OtherWorldBox.global_position + Vector3(cos(angle), +0.25, sin(-angle)), "World without depth", 20, Color.PINK, 0) + + +func _draw_rays_casts(): + # Line hits render + _draw_zone_title_pos(%HitTestSphere.global_position, "Line hits", 96, 36) + + for ray in $HitTest/RayEmitter.get_children(): + if ray is RayCast3D: + ray.force_raycast_update() + DebugDraw3D.draw_line_hit(ray.global_position, ray.to_global(ray.target_position), ray.get_collision_point(), ray.is_colliding(), 0.3) + + +func _more_tests(): + # Delayed line render + if true: + var _a12 = DebugDraw3D.new_scoped_config().set_thickness(0.035) + DebugDraw3D.draw_line($LagTest.global_position + Vector3.UP, $LagTest.global_position + Vector3(0,3,sin(Time.get_ticks_msec() / 50.0)), DebugDraw3D.empty_color, 0.35) + + if draw_3d_text: + DebugDraw3D.draw_text($LagTest.global_position + Vector3(0,3,sin(Time.get_ticks_msec() / 50.0)), "%.1f" % sin(Time.get_ticks_msec() / 50.0), 16, DebugDraw3D.empty_color, 0.35) + + # Draw plane + if true: + var _s11 = DebugDraw3D.new_scoped_config().set_thickness(0.02).set_plane_size(10) + + var pl_node: Node3D = $PlaneOrigin + var xf: Transform3D = pl_node.global_transform + var normal: = xf.basis.y.normalized() + var plane = Plane(normal, xf.origin.dot(normal)) + + var vp: Viewport = get_viewport() + if Engine.is_editor_hint() and Engine.get_singleton(&"EditorInterface").get_editor_viewport_3d(0): + vp = Engine.get_singleton(&"EditorInterface").get_editor_viewport_3d(0) + + var cam = vp.get_camera_3d() + if cam: + var dir = vp.get_camera_3d().project_ray_normal(vp.get_mouse_position()) + var intersect = plane.intersects_ray(cam.global_position, dir) + + DebugDraw3D.draw_plane(plane, Color.CORAL * Color(1,1,1, 0.4), pl_node.global_position) + if intersect and intersect.distance_to(pl_node.global_position) < _s11.get_plane_size() * 0.5: + # Need to test different colors on both sides of the plane + var col = Color.FIREBRICK if plane.is_point_over(cam.global_position) else Color.AQUAMARINE + DebugDraw3D.draw_sphere(intersect, 0.3, col) + + +func _draw_array_of_boxes(): + # Lots of boxes to check performance.. + var x_size := 50 + var y_size := 50 + var z_size := 3 + var mul := 1 + var cubes_max_time := 1.25 + var show_text := draw_text_with_boxes + var cfg = DebugDraw3D.new_scoped_config() + + if draw_1m_boxes: + x_size = 100 + y_size = 100 + z_size = 100 + mul = 4 + cubes_max_time = 60 + show_text = false + + var size := Vector3.ONE + var half_size := size * 0.5 + + if timer_cubes < 0: + var _start_time = Time.get_ticks_usec() + for x in x_size: + for y in y_size: + for z in z_size: + cfg.set_thickness(randf_range(0, 0.1)) + var pos := Vector3(x * mul, (-4-z) * mul, y * mul) + global_position + DebugDraw3D.draw_box(pos, Quaternion.IDENTITY, size, DebugDraw3D.empty_color, false, cubes_max_time) + + if show_text and z == 0: + DebugDraw3D.draw_text(pos + half_size, str(pos), 32, DebugDraw3D.empty_color, cubes_max_time) + #print("Draw Cubes: %.3fms" % ((Time.get_ticks_usec() - _start_time) / 1000.0)) + timer_cubes = cubes_max_time + + +func _ready() -> void: + _update_keys_just_press() + + await get_tree().process_frame + + # this check is required for inherited scenes, because an instance of this + # script is created first, and then overridden by another + if not is_inside_tree(): + return + + DebugDraw2D.config.text_background_color = Color(0.3, 0.3, 0.3, 0.8) + + +func _is_key_just_pressed(key): + if (button_presses[key] == 1): + button_presses[key] = 2 + return true + return false + + +func _update_keys_just_press(): + var set_key = func (k: Key): + if Input.is_key_pressed(k) and button_presses.has(k): + if button_presses[k] == 0: + return 1 + else: + return button_presses[k] + else: + return 0 + button_presses[KEY_LEFT] = set_key.call(KEY_LEFT) + button_presses[KEY_UP] = set_key.call(KEY_UP) + button_presses[KEY_CTRL] = set_key.call(KEY_CTRL) + button_presses[KEY_F1] = set_key.call(KEY_F1) + button_presses[KEY_1] = set_key.call(KEY_1) + button_presses[KEY_2] = set_key.call(KEY_2) + button_presses[KEY_3] = set_key.call(KEY_3) + + +func _update_timers(delta : float): + timer_1 -= delta + timer_cubes -= delta + timer_3 -= delta + timer_text -= delta + + +func _notification(what: int) -> void: + if what == NOTIFICATION_EDITOR_PRE_SAVE or what == NOTIFICATION_EXIT_TREE: + _thread_stop() + + +func _call_from_thread(): + if tests_use_threads and (not test_thread or not test_thread.is_alive()): + test_thread_closing = false + test_thread = Thread.new() + test_thread.start(_thread_body) + elif not tests_use_threads and (test_thread and test_thread.is_alive()): + _thread_stop() + + +func _thread_stop(): + if test_thread and test_thread.is_alive(): + tests_use_threads = false + test_thread_closing = true + test_thread.wait_to_finish() + + +func _thread_body(): + print("Thread started!") + while not test_thread_closing: + DebugDraw3D.draw_box(Vector3(0,-1,0), Quaternion.IDENTITY, Vector3.ONE, Color.BROWN, true, 0.016) + + var boxes = 10 + for y in boxes: + var offset := sin(TAU/boxes * y + wrapf(Time.get_ticks_msec() / 100.0, 0, TAU)) + var pos := Vector3(offset, y, 0) + DebugDraw3D.draw_box(pos, Quaternion.IDENTITY, Vector3.ONE, Color.GREEN_YELLOW, true, 0.016) + DebugDraw3D.draw_text(pos, str(y), 64, Color.WHITE , 0.016) + + if y == 0: + DebugDraw2D.set_text("thread. sin", offset) + + OS.delay_msec(16) + print("Thread finished!") diff --git a/examples_dd3d/DebugDrawDemoScene.gd.uid b/examples_dd3d/DebugDrawDemoScene.gd.uid new file mode 100644 index 0000000..39b5273 --- /dev/null +++ b/examples_dd3d/DebugDrawDemoScene.gd.uid @@ -0,0 +1 @@ +uid://ba2ie81p2x3x7 diff --git a/examples_dd3d/DebugDrawDemoScene.tscn b/examples_dd3d/DebugDrawDemoScene.tscn new file mode 100644 index 0000000..2193d51 --- /dev/null +++ b/examples_dd3d/DebugDrawDemoScene.tscn @@ -0,0 +1,1042 @@ +[gd_scene load_steps=43 format=3 uid="uid://c3sccy6x0ht5j"] + +[ext_resource type="Script" path="res://examples_dd3d/DebugDrawDemoScene.gd" id="1"] +[ext_resource type="FontFile" uid="uid://erdgllynwqkw" path="res://examples_dd3d/Roboto-Bold.ttf" id="2_aedbq"] +[ext_resource type="Script" path="res://examples_dd3d/demo_camera_movement.gd" id="3_3m1mp"] +[ext_resource type="FontFile" uid="uid://7am1h57ldd6" path="res://examples_dd3d/PixelatedElegance.ttf" id="3_tkhi8"] +[ext_resource type="Script" path="res://examples_dd3d/demo_music_visualizer.gd" id="4_eq2lt"] +[ext_resource type="Script" path="res://examples_dd3d/demo_settings_panel.gd" id="5_31v5h"] +[ext_resource type="Script" path="res://examples_dd3d/demo_web_docs_version_select.gd" id="6_07f7q"] + +[sub_resource type="Animation" id="Animation_ucqh5"] +resource_name = "RESET" +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("..:tests_use_threads") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:mesh:material:shader_parameter/albedo_texture") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [null] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_cq37i"] +_data = { +"RESET": SubResource("Animation_ucqh5") +} + +[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_87638"] +sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1) +ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1) + +[sub_resource type="Sky" id="Sky_4jfme"] +sky_material = SubResource("ProceduralSkyMaterial_87638") + +[sub_resource type="Environment" id="Environment_38m85"] +sky = SubResource("Sky_4jfme") +tonemap_mode = 2 +fog_light_energy = 0.41 +fog_density = 0.0757 +fog_height = 0.5 +fog_height_density = 4.6102 + +[sub_resource type="Animation" id="9"] +resource_name = "New Anim" +length = 1.5 +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Spatial2:transform") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.7), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 1, 1), Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0.31558, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Spatial5:transform") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, -1, 1), Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, -1.5801, 1)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Spatial4:transform") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.443643, 0, 1.53767), Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.443643, -0.791383, 1.53767)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Spatial7:position") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0.4, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector3(1.33, -0.119, -0.025), Vector3(1.32989, -0.583818, -0.025198)] +} + +[sub_resource type="Animation" id="10"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Spatial2:transform") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 1, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Spatial5:transform") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, -1, 1)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Spatial4:transform") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.443643, 0, 1.53767)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Spatial7:position") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector3(1.32989, -0.583818, -0.025198)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_nj4nv"] +_data = { +"New Anim": SubResource("9"), +"RESET": SubResource("10") +} + +[sub_resource type="Shader" id="Shader_621vv"] +code = "shader_type spatial; +render_mode unshaded; + +uniform sampler2D albedo_texture : source_color; + +void fragment() { + ALBEDO = texture(albedo_texture,UV).rgb; +} +" + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_ho0aq"] +render_priority = 0 +shader = SubResource("Shader_621vv") + +[sub_resource type="PlaneMesh" id="PlaneMesh_c6mie"] +material = SubResource("ShaderMaterial_ho0aq") +size = Vector2(4, 4) + +[sub_resource type="CapsuleMesh" id="CapsuleMesh_tigpa"] +radius = 0.395 +height = 1.825 + +[sub_resource type="BoxMesh" id="BoxMesh_b14rm"] + +[sub_resource type="Animation" id="Animation_w1m7s"] +length = 0.001 +tracks/0/type = "position_3d" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Camera") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = PackedFloat32Array(0, 1, -6.988, 10.986, 29.206) +tracks/1/type = "rotation_3d" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Camera") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = PackedFloat32Array(0, 1, -0.16935, 0, 0, 0.985556) + +[sub_resource type="Animation" id="Animation_h4e34"] +resource_name = "recursive" +length = 18.0 +tracks/0/type = "position_3d" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Camera") +tracks/0/interp = 2 +tracks/0/loop_wrap = true +tracks/0/keys = PackedFloat32Array(0, 1, -4.43594, -0.0101277, 8.56634, 2, 1, -4.63897, -0.279309, 8.78785, 4, 1, -4.65315, -0.433226, 8.88306, 6, 1, -4.6267, -0.506496, 8.90766, 8, 1, -4.60482, -0.535954, 8.90541, 10, 1, -4.59385, -0.545658, 8.89771, 12, 1, -4.59006, -0.547969, 8.89174, 14, 1, -4.58948, -0.548125, 8.88844, 16, 1, -4.58985, -0.547923, 8.887, 18, 1, -4.5903, -0.547799, 8.8865) +tracks/1/type = "rotation_3d" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Camera") +tracks/1/interp = 2 +tracks/1/loop_wrap = true +tracks/1/keys = PackedFloat32Array(0, 1, 0.190215, 0.859282, 0.43192, 0.197228, 2, 1, 0.183697, 0.853511, 0.484111, -0.0584063, 4, 1, 0.164659, 0.789579, 0.503307, -0.310057, 6, 1, -0.134401, -0.671836, -0.48821, 0.540577, 8, 1, -0.0949895, -0.508291, -0.439844, 0.734271, 10, 1, -0.0490975, -0.310157, -0.361506, 0.877898, 12, 1, 0.000153813, -0.090853, -0.258524, 0.961723, 14, 1, 0.0493618, 0.134434, -0.138051, 0.980017, 16, 1, 0.0953059, 0.351263, -0.00774742, 0.931381, 18, 1, 0.13493, 0.543814, 0.122741, 0.819143) + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_rcwnp"] +_data = { +"RESET": SubResource("Animation_w1m7s"), +"recursive": SubResource("Animation_h4e34") +} + +[sub_resource type="SphereShape3D" id="4"] +radius = 1.0 + +[sub_resource type="StandardMaterial3D" id="5"] +transparency = 1 +albedo_color = Color(0.54902, 0.54902, 0.729412, 0.403922) +emission_enabled = true +emission = Color(0.752941, 0.741176, 0.862745, 1) + +[sub_resource type="Animation" id="6"] +resource_name = "New Anim" +length = 3.0 +loop_mode = 1 +tracks/0/type = "rotation_3d" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("RayEmitter") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = PackedFloat32Array(0, 1, 0, 0, 0, 1, 1.3, 1, 1.31237e-06, -9.55543e-07, -2.2333e-06, 1, 2.3, 1, -0.158418, 0.0315871, 0.980558, -0.111409) +tracks/1/type = "position_3d" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("RayEmitter") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = PackedFloat32Array(0, 1, -1.03574, 2.47907, -0.819963, 0.5, 1, 0.914907, 1.78507, -0.103575, 1.3, 1, 0.00863326, 2.47907, -0.595551, 2.3, 1, 1.00051, 1.4046, 1.02585) + +[sub_resource type="Animation" id="7"] +length = 0.001 +tracks/0/type = "position_3d" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("RayEmitter") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = PackedFloat32Array(0, 1, -1.03574, 2.47907, -0.819963) +tracks/1/type = "rotation_3d" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("RayEmitter") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = PackedFloat32Array(0, 1, 0, 0, 0, 1) + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_vh8ml"] +_data = { +"New Anim": SubResource("6"), +"RESET": SubResource("7") +} + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_rbfyn"] +transparency = 1 +cull_mode = 2 +shading_mode = 0 +albedo_color = Color(0.215686, 0.215686, 0.215686, 0.764706) + +[sub_resource type="QuadMesh" id="QuadMesh_1t0id"] +material = SubResource("StandardMaterial3D_rbfyn") +orientation = 1 + +[sub_resource type="StandardMaterial3D" id="1"] +shading_mode = 0 +albedo_color = Color(0.533333, 0.105882, 0.105882, 1) + +[sub_resource type="Animation" id="8"] +resource_name = "RESET" +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector3(7, -2, 0)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_a7f1a"] +_data = { +"RESET": SubResource("8") +} + +[sub_resource type="Shader" id="Shader_3cmiq"] +code = "shader_type spatial; +render_mode unshaded; + +uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; + +void fragment() { + vec4 col = texture(screen_texture, SCREEN_UV); + ALBEDO = col.brg; + ALPHA = col.a; +} +" + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_t3isk"] +render_priority = 0 +shader = SubResource("Shader_3cmiq") + +[sub_resource type="BoxMesh" id="BoxMesh_0xv07"] +material = SubResource("ShaderMaterial_t3isk") + +[sub_resource type="Gradient" id="Gradient_tup4c"] +offsets = PackedFloat32Array(0.00471698, 0.316038, 0.646226, 1) +colors = PackedColorArray(0, 0.0156863, 1, 1, 0.0988327, 1, 0.122977, 1, 1, 0.111986, 0.118936, 1, 0, 0.0156863, 1, 1) + +[sub_resource type="Animation" id="Animation_n750a"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("../MusicPlayer:stream") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [null] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_0ity1"] +_data = { +"RESET": SubResource("Animation_n750a") +} + +[sub_resource type="Theme" id="3"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_oj5gf"] +content_margin_top = 5.0 +content_margin_bottom = 7.0 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_boyhr"] +content_margin_left = 5.0 +content_margin_top = 5.0 +content_margin_right = 5.0 +content_margin_bottom = 5.0 +bg_color = Color(0.0705882, 0.0705882, 0.0705882, 0.784314) +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 + +[node name="DebugDrawDemoScene" type="Node3D"] +process_priority = 1 +script = ExtResource("1") +custom_font = ExtResource("2_aedbq") +custom_3d_font = ExtResource("3_tkhi8") +text_groups_position = 2 + +[node name="RESET" type="AnimationPlayer" parent="."] +root_node = NodePath("../OtherWorld") +libraries = { +"": SubResource("AnimationLibrary_cq37i") +} + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 0, 0) +visible = false +directional_shadow_max_distance = 200.0 + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_38m85") + +[node name="Camera" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.942642, 0.333808, 0, -0.333808, 0.942642, -6.988, 10.986, 29.206) +cull_mask = 1 +current = true +fov = 53.0 +near = 0.001 +far = 100.0 +script = ExtResource("3_3m1mp") + +[node name="Panel" type="PanelContainer" parent="."] +visible = false +custom_minimum_size = Vector2(300, 300) +anchors_preset = 2 +anchor_top = 1.0 +anchor_bottom = 1.0 +offset_top = -300.0 +offset_right = 300.0 +grow_vertical = 0 + +[node name="ViewportContainer" type="SubViewportContainer" parent="Panel"] +layout_mode = 2 + +[node name="Viewport" type="SubViewport" parent="Panel/ViewportContainer"] +handle_input_locally = false +size = Vector2i(300, 300) +render_target_update_mode = 0 + +[node name="CameraLayer2_5" type="Camera3D" parent="Panel/ViewportContainer/Viewport"] +transform = Transform3D(1, 0, 0, 0, 0.34202, 0.939693, 0, -0.939693, 0.34202, -3.988, 39.474, 14.053) +cull_mask = 2 +current = true +fov = 38.8 +near = 2.63 +far = 52.5 + +[node name="Zones" type="Node3D" parent="."] + +[node name="SpheresBox" type="Node3D" parent="Zones"] +unique_name_in_owner = true +transform = Transform3D(8.3761, 0, 0, 0, 4.89771, 0, 0, 0, 9.36556, -11.1864, 0.645876, -7.86506) + +[node name="CylindersBox" type="Node3D" parent="Zones"] +unique_name_in_owner = true +transform = Transform3D(9.78549, 0, 0, 0, 4.20302, 0, 0, 0, 5.62455, -23.6827, -0.015712, -6.19233) + +[node name="BoxesBox" type="Node3D" parent="Zones"] +unique_name_in_owner = true +transform = Transform3D(10.0513, 0, 0, 0, 5.99877, 0, 0, 0, 12.1174, -16.0257, -0.206735, 6.27643) + +[node name="LinesBox" type="Node3D" parent="Zones"] +unique_name_in_owner = true +transform = Transform3D(10.7186, 0, 0, 0, 3.9777, 0, 0, 0, 7.05487, 10.6302, 1.91174, -7.11416) + +[node name="PathsBox" type="Node3D" parent="Zones"] +unique_name_in_owner = true +transform = Transform3D(5.95153, 0, 0, 0, 7.71864, 0, 0, 0, 6.31617, 0.184938, 1.12881, -7.18731) + +[node name="MiscBox" type="Node3D" parent="Zones"] +unique_name_in_owner = true +transform = Transform3D(4.38886, 0, 0, 0, 2.72083, 0, 0, 0, 8.81683, -5.69728, -0.206735, 5.58232) + +[node name="LinesAnim" type="AnimationPlayer" parent="."] +root_node = NodePath("../LinePath") +libraries = { +"": SubResource("AnimationLibrary_nj4nv") +} +autoplay = "New Anim" + +[node name="LinePath" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3.0543, -8) + +[node name="Spatial" type="Node3D" parent="LinePath"] + +[node name="Spatial2" type="Node3D" parent="LinePath"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 1, 1) + +[node name="Spatial3" type="Node3D" parent="LinePath"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.462435, 0, 3) + +[node name="Spatial4" type="Node3D" parent="LinePath"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.443643, 0, 1.53767) + +[node name="Spatial5" type="Node3D" parent="LinePath"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, -1, 1) + +[node name="Spatial6" type="Node3D" parent="LinePath"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, -1) + +[node name="Spatial7" type="Node3D" parent="LinePath"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.32989, -0.583818, -0.025198) + +[node name="Cylinders" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -23.5266, 4.76837e-07, -5.82213) + +[node name="Cylinder1" type="Node3D" parent="Cylinders"] +transform = Transform3D(1.20775, 0.591481, -3.4521e-07, 0.554162, -1.12986, 0.858242, 0.208031, -0.424147, -2.28622, -3.03832, 0, -0.377882) + +[node name="Cylinder2" type="Node3D" parent="Cylinders"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.234978, -0.4237, 0.332998) + +[node name="Cylinder3" type="Node3D" parent="Cylinders"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.35527, -0.655492, -0.352802) + +[node name="1" type="Node3D" parent="Cylinders/Cylinder3"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.419773, -2.38419e-07, -1.40591) + +[node name="2" type="Node3D" parent="Cylinders/Cylinder3"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.01018, 0.486778, 1.32635) + +[node name="Spheres" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -11.1201, 0.166728, -7.893) + +[node name="SphereTransform" type="Node3D" parent="Spheres"] +transform = Transform3D(3.018, 0, 0, 0, 0.945452, -3.30182, 0, 1.04515, 2.98686, -2.14465, 4.76837e-07, 2.11952) + +[node name="SphereHDTransform" type="Node3D" parent="Spheres"] +transform = Transform3D(1.26984, 1.16629, -2.42095, 0.098772, 0.80937, 4.21576, -2.65493, 0.587941, -1.00109, -2.13175, 4.76837e-07, -2.62531) + +[node name="SpherePosition" type="Node3D" parent="Spheres"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.76745, 0.458486, 1.95921) + +[node name="Boxes" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15.2493, 0, 6.42043) + +[node name="Box1" type="Node3D" parent="Boxes"] +transform = Transform3D(2.90583, -0.000527017, -5.34615, 0.00469241, 3.92788, 0.0141019, 0.556318, -0.0303774, 1.91619, -0.961557, 0, -3.78672) +rotation_edit_mode = 2 + +[node name="Box2" type="Node3D" parent="Boxes"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.531922, -1.34723, 1.44924) + +[node name="Box3" type="Node3D" parent="Boxes"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.34837, -1.08298, 4.36414) + +[node name="AABB_fixed" type="Node3D" parent="Boxes"] +transform = Transform3D(0.834492, 0, -0.551019, 0, 1, 0, 0.55102, 0, 0.834493, -3.71325, -1.03995, 0.470324) + +[node name="AABB" type="Node3D" parent="Boxes"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.99963, -0.869998, 0.205034) + +[node name="a" type="Node3D" parent="Boxes/AABB"] +transform = Transform3D(0.864099, 0.258702, 0.431747, -1.49012e-08, 0.857796, -0.51399, -0.503322, 0.444139, 0.741221, 1.48526, -1.45318, 1.96619) + +[node name="b" type="Node3D" parent="Boxes/AABB"] +transform = Transform3D(0.864099, 0.258702, 0.431747, -1.49012e-08, 0.857796, -0.51399, -0.503322, 0.444139, 0.741221, -1.24128, 1.47773, -2.13102) + +[node name="BoxAB" type="Node3D" parent="Boxes"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.66169, -2.2624, 4.04042) + +[node name="a" type="Node3D" parent="Boxes/BoxAB"] +transform = Transform3D(0.864099, 0.258702, 0.431747, -1.49012e-08, 0.857796, -0.51399, -0.503322, 0.444139, 0.741221, 0.556136, -0.666145, 0.951601) + +[node name="b" type="Node3D" parent="Boxes/BoxAB"] +transform = Transform3D(0.864099, 0.258702, 0.431747, -1.49012e-08, 0.857796, -0.51399, -0.503322, 0.444139, 0.741221, -0.548804, 0.715255, -0.942184) + +[node name="o" type="Node3D" parent="Boxes/BoxAB"] +transform = Transform3D(0.826805, 0.360538, 0.431748, -0.102949, 0.851596, -0.51399, -0.552988, 0.380522, 0.741221, 0, 0, 0) +metadata/_edit_group_ = true + +[node name="up" type="Node3D" parent="Boxes/BoxAB/o"] +transform = Transform3D(1, -1.49012e-08, 0, -1.04308e-07, 1, 0, 0, 0, 1, 0, 0.553809, -0.331842) + +[node name="BoxABEdge" type="Node3D" parent="Boxes"] +transform = Transform3D(0.965926, -0.0669873, -0.25, 0, 0.965926, -0.258819, 0.258819, 0.25, 0.933013, 0.348115, -1.30239, 4.88007) + +[node name="a" type="Node3D" parent="Boxes/BoxABEdge"] +transform = Transform3D(0.241143, 0.650584, 0.720132, -0.123077, 0.756539, -0.642262, -0.962654, 0.066246, 0.262507, 0.384618, -0.635015, 0.0956135) + +[node name="b" type="Node3D" parent="Boxes/BoxABEdge"] +transform = Transform3D(0.241143, 0.650584, 0.720133, -0.123077, 0.756539, -0.642261, -0.962654, 0.0662459, 0.262507, -0.287622, 0.997905, -0.144578) + +[node name="o" type="Node3D" parent="Boxes/BoxABEdge"] +transform = Transform3D(1, 1.49012e-08, 2.98023e-08, 7.45058e-09, 1, -1.49012e-08, -1.49012e-08, -1.49012e-08, 1, 0, 0, 0) +metadata/_edit_group_ = true + +[node name="up" type="Node3D" parent="Boxes/BoxABEdge/o"] +transform = Transform3D(1, -7.45058e-09, 0, -7.45058e-09, 1, 0, 2.98023e-08, -1.49012e-08, 1, -9.53674e-07, 0.6, 0) + +[node name="OtherWorld" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.53219, -2.5, 5.30229) +mesh = SubResource("PlaneMesh_c6mie") +skeleton = NodePath("") + +[node name="RESET" type="AnimationPlayer" parent="OtherWorld"] +libraries = { +"": SubResource("AnimationLibrary_cq37i") +} + +[node name="SubViewport" type="SubViewport" parent="OtherWorld"] +own_world_3d = true +handle_input_locally = false +render_target_update_mode = 4 + +[node name="SubViewportContainer" type="SubViewportContainer" parent="OtherWorld/SubViewport"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +stretch = true + +[node name="SubViewport" type="SubViewport" parent="OtherWorld/SubViewport/SubViewportContainer"] +handle_input_locally = false +render_target_update_mode = 4 + +[node name="Camera3D" type="Camera3D" parent="OtherWorld/SubViewport/SubViewportContainer/SubViewport"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.57063, 0.6, 7.25557) +current = true +far = 5.0 + +[node name="MeshInstance3D" type="MeshInstance3D" parent="OtherWorld/SubViewport/SubViewportContainer/SubViewport"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.57063, 0.6, 5.72253) +mesh = SubResource("CapsuleMesh_tigpa") +skeleton = NodePath("../../..") + +[node name="OtherWorldBox" type="Node3D" parent="OtherWorld/SubViewport/SubViewportContainer/SubViewport"] +unique_name_in_owner = true +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.57063, 0.6, 5.72253) + +[node name="Misc" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.68259, 0, 4.46741) + +[node name="Billboard" type="Node3D" parent="Misc"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.403353, -0.331599, 2.22542) + +[node name="Arrow" type="Node3D" parent="Misc"] +transform = Transform3D(0.802141, -0.286294, -0.524028, -0.539546, 0.0285125, -0.841473, 0.25585, 0.957718, -0.131597, -0.475607, -0.670307, 2.30581) + +[node name="Position" type="Node3D" parent="Misc"] +transform = Transform3D(1.51514, 0.589536, 1.00858, -1.34875, 0.662262, 1.133, 0, -0.462445, 2.90833, 0.853743, 0.0843356, -1.73676) + +[node name="GizmoNormal" type="Node3D" parent="Misc"] +transform = Transform3D(0.965926, 0, -0.258819, 0, 1, 0, 0.258819, 0, 0.965926, 0.890203, -0.306246, 0.356159) + +[node name="ZDepthTestCube" type="MeshInstance3D" parent="Misc/GizmoNormal"] +unique_name_in_owner = true +transform = Transform3D(0.591801, 0, 4.47035e-08, 0, 0.591801, 0, -4.47035e-08, 0, 0.591801, 0, 0, 0) +mesh = SubResource("BoxMesh_b14rm") + +[node name="GizmoTransform" type="Node3D" parent="Misc"] +transform = Transform3D(0.879881, 0.248446, -0.405072, -0.346604, 0.918688, -0.189411, 0.325077, 0.307059, 0.894449, -0.838587, -0.458, -0.176491) + +[node name="GizmoOneColor" type="Node3D" parent="Misc"] +transform = Transform3D(0.385568, 0.0415614, 0.921743, 0.082879, 0.993386, -0.0794599, -0.91895, 0.107031, 0.379573, -0.838587, -0.139425, -1.93055) + +[node name="LocalTransformRecursiveOrigin" type="Node3D" parent="Misc"] +unique_name_in_owner = true +transform = Transform3D(0.785829, 0.365814, 0.498651, 0.0146361, 0.795073, -0.606337, -0.618271, 0.483775, 0.619438, 0.92688, -0.70441, 4.03998) + +[node name="RecursiveTransformTest" type="AnimationPlayer" parent="Misc/LocalTransformRecursiveOrigin"] +unique_name_in_owner = true +root_node = NodePath("../../..") +libraries = { +"": SubResource("AnimationLibrary_rcwnp") +} + +[node name="HitTest" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.724359, -1.03227, 7.85404) + +[node name="StaticBody" type="StaticBody3D" parent="HitTest"] + +[node name="CollisionShape" type="CollisionShape3D" parent="HitTest/StaticBody"] +shape = SubResource("4") + +[node name="HitTestSphere" type="CSGSphere3D" parent="HitTest/StaticBody"] +unique_name_in_owner = true +radius = 1.0 +radial_segments = 16 +rings = 10 +material = SubResource("5") + +[node name="RayEmitter" type="Node3D" parent="HitTest"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.03574, 2.47907, -0.819963) + +[node name="RayCast" type="RayCast3D" parent="HitTest/RayEmitter"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.732104, 0, -0.814761) +enabled = false +target_position = Vector3(0, -3.464, 0) + +[node name="RayCast2" type="RayCast3D" parent="HitTest/RayEmitter"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.684873, 0, -0.791145) +enabled = false +target_position = Vector3(0, -3.464, 0) + +[node name="RayCast3" type="RayCast3D" parent="HitTest/RayEmitter"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.708488, 0, 0.543175) +enabled = false +target_position = Vector3(0, -3.464, 0) + +[node name="RayCast4" type="RayCast3D" parent="HitTest/RayEmitter"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.708489, 0, 0.566791) +enabled = false +target_position = Vector3(0, -3.464, 0) + +[node name="RayCast5" type="RayCast3D" parent="HitTest/RayEmitter"] +transform = Transform3D(0.974217, -0.225614, 0, 0.225614, 0.974217, 0, 0, 0, 1, -0.447564, 0, -0.259778) +enabled = false +target_position = Vector3(0, -3.464, 0) + +[node name="RayCast6" type="RayCast3D" parent="HitTest/RayEmitter"] +transform = Transform3D(0.935992, 0.352021, 0, -0.352021, 0.935992, 0, 0, 0, 1, 0.35227, -0.245904, -0.25849) +enabled = false +target_position = Vector3(0, -3.464, 0) + +[node name="RayEmitterAnimationPlayer" type="AnimationPlayer" parent="HitTest"] +unique_name_in_owner = true +libraries = { +"": SubResource("AnimationLibrary_vh8ml") +} +autoplay = "New Anim" + +[node name="Grids" type="Node3D" parent="."] +transform = Transform3D(0.707106, 0, -0.707108, 0, 1, 0, 0.707108, 0, 0.707106, 0.730597, -2.5, 2.76274) + +[node name="GridCentered" type="Node3D" parent="Grids"] +transform = Transform3D(1.74492, 0.723785, -1.74493, -1.24976, -7.72562e-08, -1.24975, -1.74493, 0.723783, 1.74493, 1.74919, -0.0010004, 1.75466) +rotation_edit_mode = 2 + +[node name="Subdivision" type="Node3D" parent="Grids/GridCentered"] +transform = Transform3D(1, -6.03961e-14, -2.68221e-07, 3.55271e-13, 1, 1.42109e-14, -1.19209e-07, 1.1724e-13, 1, -0.2, 4.76837e-07, 0.4) + +[node name="Grid" type="Node3D" parent="Grids"] +transform = Transform3D(5, 0, 4.76837e-07, 0, 1, 0, -4.76837e-07, 0, 5, 0, 0, 0) + +[node name="Subdivision" type="Node3D" parent="Grids/Grid"] +transform = Transform3D(1, 0, -2.98023e-08, 0, 0.999999, 1.90735e-05, 0, 4.65661e-10, 0.999999, 1, 0, 1) + +[node name="PlaneOrigin" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 11.0482, 7.33669, -13.1715) +mesh = SubResource("QuadMesh_1t0id") + +[node name="Lines" type="Node3D" parent="."] +transform = Transform3D(1.51514, 0.589536, 1.00858, -1.34875, 0.662262, 1.133, 0, -0.462445, 2.90833, 10.2488, -0.331599, -10.3326) + +[node name="1" type="Node3D" parent="Lines"] +transform = Transform3D(1, 6.61592e-09, 2.23038e-08, 9.40939e-07, 1, 0, -2.76085e-08, -1.49012e-08, 1, -1.46213, -4.03317, 0.61692) + +[node name="2" type="Node3D" parent="Lines"] +transform = Transform3D(1, 6.61592e-09, 2.23038e-08, 9.40939e-07, 1, 0, -2.76085e-08, -1.49012e-08, 1, -1.01875, -1.79584, -0.163045) + +[node name="3" type="Node3D" parent="Lines"] +transform = Transform3D(1, 6.61592e-09, 2.23038e-08, 6.87561e-07, 1, 0, -2.87275e-08, -1.49012e-08, 1, -0.1559, -0.407045, 0.0523388) + +[node name="4" type="Node3D" parent="Lines"] +transform = Transform3D(1, 6.61592e-09, 2.23038e-08, 4.9239e-07, 1, 0, -3.40677e-08, -1.49012e-08, 1, 1.18591, 1.8987, 0.301906) + +[node name="5" type="Node3D" parent="Lines"] +transform = Transform3D(-0.998871, -0.0207882, -0.0355643, 0.0855375, -0.5714, -2.68836, 0.0136011, -0.249864, 0.572532, 1.43126, 0.26242, 1.92347) + +[node name="6" type="Node3D" parent="Lines"] +transform = Transform3D(-0.998872, -0.0207882, -0.0355643, 0.085537, -0.5714, -2.68836, 0.0136012, -0.249864, 0.572533, 1.43441, 1.50606, 1.20028) + +[node name="7" type="Node3D" parent="Lines"] +transform = Transform3D(-0.998873, -0.0207882, -0.0355641, 0.0855357, -0.5714, -2.68836, 0.0136014, -0.249864, 0.572533, 0.0511096, -1.3236, 1.06745) + +[node name="8" type="Node3D" parent="Lines"] +transform = Transform3D(-0.998873, -0.0207882, -0.0355641, 0.0855353, -0.5714, -2.68836, 0.0136016, -0.249864, 0.572533, -1.01372, -3.80486, 1.25019) + +[node name="Target" type="Node3D" parent="Lines"] +transform = Transform3D(1, -2.7352e-06, 2.60722e-07, 4.10378e-06, 1, 0, -4.28605e-07, -1.49012e-08, 1, -0.69134, 0.176475, 1.30597) + +[node name="LagTest" type="CSGBox3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7, -2, 0) +size = Vector3(2, 2, 2) +material = SubResource("1") + +[node name="RESET" type="AnimationPlayer" parent="LagTest"] +libraries = { +"": SubResource("AnimationLibrary_a7f1a") +} + +[node name="PostProcess" type="MeshInstance3D" parent="."] +transform = Transform3D(-2.18557e-07, 0, 1.5, 0, 5, 0, -5, 0, -6.55671e-08, 16, 0, 0) +mesh = SubResource("BoxMesh_0xv07") +skeleton = NodePath("../Lines") + +[node name="MusicVisualizer" type="VBoxContainer" parent="."] +offset_left = 10.0 +offset_top = 10.0 +offset_right = 50.0 +offset_bottom = 50.0 +script = ExtResource("4_eq2lt") +colors = SubResource("Gradient_tup4c") + +[node name="OpenFile" type="Button" parent="MusicVisualizer"] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Open music" + +[node name="RESET" type="AnimationPlayer" parent="MusicVisualizer"] +root_node = NodePath("../OpenFile") +libraries = { +"": SubResource("AnimationLibrary_0ity1") +} + +[node name="MusicPlayer" type="AudioStreamPlayer" parent="MusicVisualizer"] +unique_name_in_owner = true +autoplay = true +bus = &"MusicAnalyzer" + +[node name="VBox" type="VBoxContainer" parent="MusicVisualizer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="MusicVisualizer/VBox"] +layout_mode = 2 + +[node name="VolumeSlider" type="HSlider" parent="MusicVisualizer/VBox/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(100, 0) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 4 +max_value = 1.0 +step = 0.01 +value = 0.1 + +[node name="MuteMaster" type="CheckBox" parent="MusicVisualizer/VBox/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +button_pressed = true +text = "Mute" + +[node name="AudioVisualizer" type="Node3D" parent="."] +unique_name_in_owner = true +transform = Transform3D(0.2, 0, 0, 0, 5, 0, 0, 0, 0.2, -5.31036, -1.422, 14.14) + +[node name="CustomCanvas" type="Control" parent="."] +unique_name_in_owner = true +layout_mode = 3 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -545.0 +offset_top = 46.0 +offset_right = -37.0 +offset_bottom = 638.0 +grow_horizontal = 0 +mouse_filter = 2 +metadata/_edit_lock_ = true + +[node name="Settings" type="Control" parent="."] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme = SubResource("3") +script = ExtResource("5_31v5h") +switch_to_scene = "res://examples_dd3d/DebugDrawDemoSceneCS.tscn" +metadata/_edit_lock_ = true + +[node name="HBox" type="HBoxContainer" parent="Settings"] +layout_mode = 1 +anchors_preset = 3 +anchor_left = 1.0 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -497.0 +offset_top = -372.0 +offset_right = -10.0006 +offset_bottom = -10.0 +grow_horizontal = 0 +grow_vertical = 0 + +[node name="VBoxContainer" type="VBoxContainer" parent="Settings/HBox"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 8 + +[node name="VersionBlock" type="HBoxContainer" parent="Settings/HBox/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +script = ExtResource("6_07f7q") + +[node name="Label" type="Label" parent="Settings/HBox/VBoxContainer/VersionBlock"] +layout_mode = 2 +size_flags_horizontal = 10 +theme_override_font_sizes/font_size = 13 +text = "Demo version:" + +[node name="OptionButton" type="OptionButton" parent="Settings/HBox/VBoxContainer/VersionBlock"] +layout_mode = 2 +size_flags_horizontal = 8 +theme_override_font_sizes/font_size = 13 +item_count = 1 +popup/item_0/text = "1.0.0" +popup/item_0/id = 0 + +[node name="Label" type="Label" parent="Settings/HBox/VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 8 +theme_override_styles/normal = SubResource("StyleBoxEmpty_oj5gf") +text = "GDScript example" +horizontal_alignment = 2 +metadata/_edit_use_anchors_ = true + +[node name="VBox" type="VBoxContainer" parent="Settings/HBox"] +layout_mode = 2 +alignment = 2 + +[node name="HideShowPanelButton" type="Button" parent="Settings/HBox/VBox"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 4 +theme_override_font_sizes/font_size = 13 +text = "Hide panel" + +[node name="SettingsPanel" type="PanelContainer" parent="Settings/HBox/VBox"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 8 +theme_override_styles/panel = SubResource("StyleBoxFlat_boyhr") + +[node name="VBox" type="VBoxContainer" parent="Settings/HBox/VBox/SettingsPanel"] +layout_mode = 2 +size_flags_horizontal = 3 +alignment = 2 + +[node name="Label" type="Label" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +layout_mode = 2 +theme_override_colors/font_color = Color(0.792157, 0.792157, 0.792157, 1) +text = "Common:" + +[node name="HBox3" type="HBoxContainer" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +layout_mode = 2 + +[node name="Label" type="Label" parent="Settings/HBox/VBox/SettingsPanel/VBox/HBox3"] +layout_mode = 2 +text = "Thickness " + +[node name="ThicknessSlider" type="HSlider" parent="Settings/HBox/VBox/SettingsPanel/VBox/HBox3"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 4 +max_value = 0.5 +step = 0.001 +value = 0.05 + +[node name="HBox5" type="HBoxContainer" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +layout_mode = 2 + +[node name="Label" type="Label" parent="Settings/HBox/VBox/SettingsPanel/VBox/HBox5"] +layout_mode = 2 +text = "Frustum Scale" + +[node name="FrustumScaleSlider" type="HSlider" parent="Settings/HBox/VBox/SettingsPanel/VBox/HBox5"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 4 +max_value = 1.0 +step = 0.001 +value = 0.5 + +[node name="UpdateInPhysics" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +unique_name_in_owner = true +layout_mode = 2 +text = "Update in physics (15 Ticks) *" + +[node name="Label4" type="Label" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +layout_mode = 2 +theme_override_colors/font_color = Color(0.792157, 0.792157, 0.792157, 1) +text = "Text:" + +[node name="ShowText" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +unique_name_in_owner = true +layout_mode = 2 +text = "Show text" + +[node name="ShowExamples" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +unique_name_in_owner = true +layout_mode = 2 +text = "Examples" + +[node name="ShowStats" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +unique_name_in_owner = true +layout_mode = 2 +text = "Debug stats" + +[node name="ShowHints" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +unique_name_in_owner = true +layout_mode = 2 +text = "Hints" + +[node name="Draw3DText" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +unique_name_in_owner = true +layout_mode = 2 +text = "3D Text" + +[node name="Label3" type="Label" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +layout_mode = 2 +theme_override_colors/font_color = Color(0.792157, 0.792157, 0.792157, 1) +text = "Boxes:" + +[node name="HBox4" type="HBoxContainer" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +layout_mode = 2 + +[node name="DrawBoxes" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox/HBox4"] +unique_name_in_owner = true +layout_mode = 2 +text = "Draw an array of boxes" + +[node name="Draw1MBoxes" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox/HBox4"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Draw 1 Million boxes, otherwise 7500pcs." +text = "1M" + +[node name="DrawBoxesAddText" type="CheckBox" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +unique_name_in_owner = true +layout_mode = 2 +text = "Add text to boxes" + +[node name="SwitchLang" type="Button" parent="Settings/HBox/VBox/SettingsPanel/VBox"] +unique_name_in_owner = true +layout_mode = 2 +text = "Switch to C#" + +[connection signal="pressed" from="MusicVisualizer/OpenFile" to="MusicVisualizer" method="_pressed"] +[connection signal="value_changed" from="MusicVisualizer/VBox/HBoxContainer/VolumeSlider" to="MusicVisualizer" method="_on_volume_slider_value_changed"] +[connection signal="toggled" from="MusicVisualizer/VBox/HBoxContainer/MuteMaster" to="MusicVisualizer" method="_on_mute_master_toggled"] +[connection signal="pressed" from="Settings/HBox/VBox/HideShowPanelButton" to="Settings" method="_on_hide_show_panel_pressed"] +[connection signal="value_changed" from="Settings/HBox/VBox/SettingsPanel/VBox/HBox3/ThicknessSlider" to="Settings" method="_on_thickness_slider_value_changed"] +[connection signal="value_changed" from="Settings/HBox/VBox/SettingsPanel/VBox/HBox5/FrustumScaleSlider" to="Settings" method="_on_frustum_scale_slider_value_changed"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/UpdateInPhysics" to="Settings" method="_on_update_in_physics_toggled"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/ShowText" to="Settings" method="_on_show_text_toggled"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/ShowExamples" to="Settings" method="_on_show_examples_toggled"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/ShowStats" to="Settings" method="_on_show_stats_toggled"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/ShowHints" to="Settings" method="_on_show_hints_toggled"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/Draw3DText" to="Settings" method="_on_draw_3d_text_toggled"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/HBox4/DrawBoxes" to="Settings" method="_on_draw_boxes_toggled"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/HBox4/Draw1MBoxes" to="Settings" method="_on_draw_1m_boxes_toggled"] +[connection signal="toggled" from="Settings/HBox/VBox/SettingsPanel/VBox/DrawBoxesAddText" to="Settings" method="_on_add_text_to_boxes_toggled"] +[connection signal="pressed" from="Settings/HBox/VBox/SettingsPanel/VBox/SwitchLang" to="Settings" method="_on_Button_pressed"] diff --git a/examples_dd3d/DebugDrawDemoSceneCS.cs b/examples_dd3d/DebugDrawDemoSceneCS.cs new file mode 100644 index 0000000..f847d05 --- /dev/null +++ b/examples_dd3d/DebugDrawDemoSceneCS.cs @@ -0,0 +1,854 @@ + +using Godot; +using System; +using System.Collections.Generic; + +[Tool] +public partial class DebugDrawDemoSceneCS : Node3D +{ + Random random = new Random(); + + [Export] Font custom_font; + [Export] Font custom_3d_font; + [Export] bool zylann_example = false; + [Export] bool update_in_physics = false; + [Export] bool test_text = true; + [Export] bool more_test_cases = true; + [Export] bool draw_3d_text = true; + [Export] bool draw_array_of_boxes = false; + [Export] bool draw_text_with_boxes = false; + [Export] bool draw_1m_boxes = false; + [Export(PropertyHint.Range, "0, 5, 0.001")] float debug_thickness = 0.1f; + [Export(PropertyHint.Range, "0, 1")] float camera_frustum_scale = 0.9f; + + [ExportGroup("Text groups", "text_groups")] + [Export] bool text_groups_show_examples = true; + [Export] bool text_groups_show_hints = true; + [Export] bool text_groups_show_stats = true; + [Export] bool text_groups_show_stats_2d = true; + [Export] DebugDraw2DConfig.BlockPosition text_groups_position = DebugDraw2DConfig.BlockPosition.LeftTop; + [Export] Vector2I text_groups_offset = new Vector2I(8, 8); + [Export] Vector2I text_groups_padding = new Vector2I(3, 1); + [Export(PropertyHint.Range, "1, 100")] int text_groups_default_font_size = 15; + [Export(PropertyHint.Range, "1, 100")] int text_groups_title_font_size = 20; + [Export(PropertyHint.Range, "1, 100")] int text_groups_text_font_size = 17; + + Dictionary button_presses = new Dictionary() { + { Key.Left, 0 }, + { Key.Up, 0 }, + { Key.Ctrl, 0 }, + { Key.F1, 0 }, + { Key.Key1, 0 }, + { Key.Key2, 0 }, + { Key.Key3, 0 }, + }; + + double timer_1 = 0.0; + double timer_cubes = 0.0; + double timer_3 = 0.0; + double timer_text = 0.0; + + public override async void _Ready() + { + _get_nodes(); + _update_keys_just_press(); + + await new SignalAwaiter(GetTree(), "process_frame", this); + + // this check is required for inherited scenes, because an instance of this + // script is created first, and then overridden by another + if (!IsInsideTree()) + return; + + DebugDraw2D.Config.TextBackgroundColor = new Color(0.3f, 0.3f, 0.3f, 0.8f); + } + + bool _is_key_just_pressed(Key key) + { + if (button_presses[key] == 1) + { + button_presses[key] = 2; + return true; + } + return false; + } + + void _update_timers(double delta) + { + timer_1 -= delta; + timer_cubes -= delta; + timer_3 -= delta; + timer_text -= delta; + } + + void _update_keys_just_press() + { + var set = (Key k) => Input.IsKeyPressed(k) ? (button_presses[k] == 0 ? 1 : button_presses[k]) : 0; + button_presses[Key.Left] = set(Key.Left); + button_presses[Key.Up] = set(Key.Up); + button_presses[Key.Ctrl] = set(Key.Ctrl); + button_presses[Key.F1] = set(Key.F1); + button_presses[Key.Key1] = set(Key.Key1); + button_presses[Key.Key2] = set(Key.Key2); + button_presses[Key.Key3] = set(Key.Key3); + } + + bool phys_frame_called = false; + public override void _Process(double delta) + { + ((ShaderMaterial)((PrimitiveMesh)dOtherWorld.Mesh).Material).SetShaderParameter("albedo_texture", dOtherWorldViewport.GetTexture()); + + phys_frame_called = false; + if (!update_in_physics) + { + MainUpdate(delta); + _update_timers(delta); + } + } + + public override void _PhysicsProcess(double delta) + { + if (!phys_frame_called) + { + phys_frame_called = true; + if (update_in_physics) + { + MainUpdate(delta); + _update_timers(delta); + } + } + + // Physics specific: + if (!zylann_example) + { + DebugDraw3D.DrawLine(dLines_8.GlobalPosition, dLines_Target.GlobalPosition, Colors.Yellow); + if (more_test_cases) + { + _draw_rays_casts(); + } + + // Additional drawing in the Viewport + using (var _w1 = DebugDraw3D.NewScopedConfig().SetViewport(dOtherWorldBox.GetViewport()).SetThickness(0.01f).SetCenterBrightness(1).SetNoDepthTest(true)) + { + DebugDraw3D.DrawBoxXf(new Transform3D(Basis.Identity + .Scaled(Vector3.One * 0.3f) + .Rotated(new Vector3(0, 0, 1), Mathf.Pi / 4) + .Rotated(new Vector3(0, 1, 0), Mathf.Wrap(Time.GetTicksMsec() / -1500.0f, 0, Mathf.Tau) - Mathf.Pi / 4), dOtherWorldBox.GlobalPosition), + Colors.Brown, true, 0.4f); + } + } + } + + void MainUpdate(double delta) + { + DebugDraw3D.ScopedConfig().SetThickness(debug_thickness); + + _update_keys_just_press(); + + if (_is_key_just_pressed(Key.F1)) + zylann_example = !zylann_example; + + // Zylann's example :D + if (zylann_example) + { + var _time = Time.GetTicksMsec() / 1000.0f; + var box_pos = new Vector3(0, Mathf.Sin(_time * 4f), 0); + var line_begin = new Vector3(-1, Mathf.Sin(_time * 4f), 0); + var line_end = new Vector3(1, Mathf.Cos(_time * 4f), 0); + DebugDraw3D.DrawBox(box_pos, Quaternion.Identity, new Vector3(1, 2, 1), new Color(0, 1, 0)); + DebugDraw3D.DrawLine(line_begin, line_end, new Color(1, 1, 0)); + DebugDraw2D.SetText("Time", _time); + DebugDraw2D.SetText("Frames drawn", Engine.GetFramesDrawn()); + DebugDraw2D.SetText("FPS", Engine.GetFramesPerSecond()); + DebugDraw2D.SetText("delta", delta); + + dHitTest.Visible = false; + dLagTest.Visible = false; + dPlaneOrigin.Visible = false; + pZDepthTestCube.Visible = false; + dOtherWorld.Visible = false; + return; + } + + dHitTest.Visible = true; + dLagTest.Visible = true; + dPlaneOrigin.Visible = true; + pZDepthTestCube.Visible = true; + dOtherWorld.Visible = true; + + // Testing the rendering layers by showing the image from the second camera inside the 2D panel + DebugDraw3D.Config.GeometryRenderLayers = !Input.IsKeyPressed(Key.Alt) ? 1 : 0b10010; + dPanel.Visible = Input.IsKeyPressed(Key.Alt); + DebugDraw2D.CustomCanvas = Input.IsKeyPressed(Key.Alt) ? dCustomCanvas : null; + + // More property toggles + DebugDraw3D.Config.Freeze3dRender = Input.IsKeyPressed(Key.Down); + DebugDraw3D.Config.VisibleInstanceBounds = Input.IsKeyPressed(Key.Right); + + // Regenerate meshes + if (Input.IsActionJustPressed("ui_end")) + DebugDraw3D.RegenerateGeometryMeshes(); + + // Some property toggles + if (_is_key_just_pressed(Key.Left)) + DebugDraw3D.Config.UseFrustumCulling = !DebugDraw3D.Config.UseFrustumCulling; + + if (_is_key_just_pressed(Key.Up)) + DebugDraw3D.Config.ForceUseCameraFromScene = !DebugDraw3D.Config.ForceUseCameraFromScene; + + if (_is_key_just_pressed(Key.Ctrl)) + if (!Engine.IsEditorHint()) + GetViewport().Msaa3D = GetViewport().Msaa3D == Viewport.Msaa.Msaa4X ? Viewport.Msaa.Disabled : Viewport.Msaa.Msaa4X; + + if (!Engine.IsEditorHint()) + { + if (_is_key_just_pressed(Key.Key1)) + DebugDraw3D.DebugEnabled = !DebugDraw3D.DebugEnabled; + if (_is_key_just_pressed(Key.Key2)) + DebugDraw2D.DebugEnabled = !DebugDraw2D.DebugEnabled; + if (_is_key_just_pressed(Key.Key3)) + DebugDrawManager.DebugEnabled = !DebugDrawManager.DebugEnabled; + } + + + DebugDraw3D.Config.FrustumLengthScale = camera_frustum_scale; + + // Zones with black borders + foreach (var node in dZones.GetChildren()) + { + if (node is Node3D z) + { + DebugDraw3D.DrawBoxXf(z.GlobalTransform, Colors.Black); + } + } + + // Spheres + _draw_zone_title(pSpheresBox, "Spheres"); + + DebugDraw3D.DrawSphereXf(dSphereTransform.GlobalTransform, Colors.Crimson); + using (var _s1 = DebugDraw3D.NewScopedConfig().SetHdSphere(true)) + DebugDraw3D.DrawSphereXf(dSphereHDTransform.GlobalTransform, Colors.OrangeRed); + + /// Delayed spheres + if (timer_1 <= 0) + { + DebugDraw3D.DrawSphere(dSpherePosition.GlobalPosition, 2.0f, Colors.BlueViolet, 2.0f); + using (var _s1 = DebugDraw3D.NewScopedConfig().SetHdSphere(true)) + DebugDraw3D.DrawSphere(dSpherePosition.GlobalPosition + Vector3.Forward * 4, 2.0f, Colors.CornflowerBlue, 2.0f); + timer_1 = 2; + } + + timer_1 -= delta; + + // Cylinders + _draw_zone_title(pCylindersBox, "Cylinders"); + + DebugDraw3D.DrawCylinder(dCylinder1.GlobalTransform, Colors.Crimson); + DebugDraw3D.DrawCylinder(new Transform3D(Basis.Identity.Scaled(new Vector3(1, 2, 1)), dCylinder2.GlobalPosition), Colors.Red); + DebugDraw3D.DrawCylinderAb(dCylinder3a.GlobalPosition, dCylinder3b.GlobalPosition, 0.7f); + + // Boxes + _draw_zone_title(pBoxesBox, "Boxes"); + + DebugDraw3D.DrawBoxXf(dBox1.GlobalTransform, Colors.MediumPurple); + DebugDraw3D.DrawBox(dBox2.GlobalPosition, Quaternion.FromEuler(new Vector3(0, Mathf.DegToRad(45), Mathf.DegToRad(45))), Vector3.One, Colors.RebeccaPurple); + DebugDraw3D.DrawBoxXf(new Transform3D(new Basis(Vector3.Up, Mathf.Pi * 0.25f).Scaled(Vector3.One * 2), dBox3.GlobalPosition), Colors.RosyBrown); + + DebugDraw3D.DrawAabb(new Aabb(dAABB_fixed.GlobalPosition, new Vector3(2, 1, 2)), Colors.Aqua); + DebugDraw3D.DrawAabbAb(dAABB.GetChild(0).GlobalPosition, dAABB.GetChild(1).GlobalPosition, Colors.DeepPink); + + // Boxes AB + + DebugDraw3D.DrawArrow(dBoxAB.GlobalPosition, dBoxABup.GlobalPosition, Colors.Gold, 0.1f, true); + DebugDraw3D.DrawBoxAb(dBoxABa.GlobalPosition, dBoxABb.GlobalPosition, dBoxABup.GlobalPosition - dBoxAB.GlobalPosition, Colors.Peru); + + DebugDraw3D.DrawArrow(dBoxABEdge.GlobalPosition, dBoxABEdgeup.GlobalPosition, Colors.DarkRed, 0.1f, true); + DebugDraw3D.DrawBoxAb(dBoxABEdgea.GlobalPosition, dBoxABEdgeb.GlobalPosition, dBoxABEdgeup.GlobalPosition - dBoxABEdge.GlobalPosition, Colors.DarkOliveGreen, false); + + // Lines + _draw_zone_title(pLinesBox, "Lines"); + + DebugDraw3D.DrawSquare(dLines_Target.GlobalPosition, 0.5f, Colors.Red); + + DebugDraw3D.DrawLine(dLines_1.GlobalPosition, dLines_Target.GlobalPosition, Colors.Fuchsia); + DebugDraw3D.DrawRay(dLines_3.GlobalPosition, (dLines_Target.GlobalPosition - dLines_3.GlobalPosition).Normalized(), 3.0f, Colors.Crimson); + + + if (timer_3 <= 0) + { + DebugDraw3D.DrawLine(dLines_6.GlobalPosition, dLines_Target.GlobalPosition, Colors.Fuchsia, 2.0f); + timer_3 = 2; + } + + timer_3 -= delta; + + // Test UP vector + DebugDraw3D.DrawLine(dLines_7.GlobalPosition, dLines_Target.GlobalPosition, Colors.Red); + + // Lines with Arrow + DebugDraw3D.DrawArrow(dLines_2.GlobalPosition, dLines_Target.GlobalPosition, Colors.Blue, 0.5f, true); + DebugDraw3D.DrawArrowRay(dLines_4.GlobalPosition, (dLines_Target.GlobalPosition - dLines_4.GlobalPosition).Normalized(), 8.0f, Colors.Lavender, 0.5f, true); + + DebugDraw3D.DrawLineHitOffset(dLines_5.GlobalPosition, dLines_Target.GlobalPosition, true, Mathf.Abs(Mathf.Sin(Time.GetTicksMsec() / 1000.0f)), 0.25f, Colors.Aqua); + + // Paths + _draw_zone_title(pPathsBox, "Paths"); + + /// preparing data + List points = new List(); + List points_below = new List(); + List points_below2 = new List(); + List points_below3 = new List(); + List points_below4 = new List(); + List lines_above = new List(); + + foreach (var node in dLinePath.GetChildren()) + { + if (node is Node3D c) + { + points.Add(c.GlobalPosition); + points_below.Add(c.GlobalPosition + Vector3.Down); + points_below2.Add(c.GlobalPosition + Vector3.Down * 2); + points_below3.Add(c.GlobalPosition + Vector3.Down * 3); + points_below4.Add(c.GlobalPosition + Vector3.Down * 4); + } + } + + for (int x = 0; x < points.Count - 1; x++) + { + lines_above.Add(points[x] + Vector3.Up); + lines_above.Add(points[x + 1] + Vector3.Up); + } + + /// drawing lines + DebugDraw3D.DrawLines(lines_above.ToArray()); + DebugDraw3D.DrawLinePath(points.ToArray(), Colors.Beige); + DebugDraw3D.DrawPoints(points_below.ToArray(), DebugDraw3D.PointType.TypeSquare, 0.2f, Colors.DarkGreen); + DebugDraw3D.DrawPointPath(points_below2.ToArray(), DebugDraw3D.PointType.TypeSquare, 0.25f, Colors.Blue, Colors.Tomato); + DebugDraw3D.DrawArrowPath(points_below3.ToArray(), Colors.Gold, 0.5f); + using (var _sl = DebugDraw3D.NewScopedConfig().SetThickness(0.05f)) + DebugDraw3D.DrawPointPath(points_below4.ToArray(), DebugDraw3D.PointType.TypeSphere, 0.25f, Colors.MediumSeaGreen, Colors.MediumVioletRed); + + // Misc + _draw_zone_title(pMiscBox, "Misc"); + + if (Engine.IsEditorHint()) + { + using var s = DebugDraw3D.NewScopedConfig().SetThickness(0); + DebugDraw3D.DrawCameraFrustum(dCamera, Colors.DarkOrange); + } + + using (var s = DebugDraw3D.NewScopedConfig().SetCenterBrightness(0.1f)) + { + DebugDraw3D.DrawArrowhead(dMisc_Arrow.GlobalTransform, Colors.YellowGreen); + } + + DebugDraw3D.DrawSquare(dMisc_Billboard.GlobalPosition, 0.5f, Colors.Green); + + DebugDraw3D.DrawPosition(dMisc_Position.GlobalTransform, Colors.Brown); + + DebugDraw3D.DrawGizmo(dMisc_GizmoTransform.GlobalTransform, null, true); + DebugDraw3D.DrawGizmo(dMisc_GizmoOneColor.GlobalTransform, Colors.Brown, true); + using (var s = DebugDraw3D.NewScopedConfig().SetCenterBrightness(0.5f).SetNoDepthTest(true)) + { + DebugDraw3D.DrawGizmo(dMisc_GizmoNormal.GlobalTransform.Orthonormalized(), null, false); + } + + // Grids + _draw_zone_title_pos(dGrids_GridCentered.GlobalPosition + new Vector3(0, 1.5f, 0), "Grids", 96, 36); + + Transform3D tg = dGrids_Grid.GlobalTransform; + Vector3 tn = dGrids_Grid_Subdivision.Transform.Origin; + DebugDraw3D.DrawGrid(tg.Origin, tg.Basis.X, tg.Basis.Z, new Vector2I((int)tn.X * 10, (int)tn.Z * 10), Colors.LightCoral, false); + + var tn1 = dGrids_GridCentered_Subdivision.Transform.Origin; + DebugDraw3D.DrawGridXf(dGrids_GridCentered.GlobalTransform, new Vector2I((int)(tn1.X * 10), (int)(tn1.Z * 10))); + + using (var s = DebugDraw3D.NewScopedConfig().SetThickness(0.05f)) + { + DebugDraw3D.DrawBoxXf(dPostProcess.GlobalTransform, Colors.SeaGreen); + } + + // Local transform + _draw_local_xf_box(pLocalTransformRecursiveOrigin.GlobalTransform, 0.05f, 10); + + // 2D + DebugDraw2D.Config.TextDefaultSize = text_groups_default_font_size; + DebugDraw2D.Config.TextBlockOffset = text_groups_offset; + DebugDraw2D.Config.TextBlockPosition = text_groups_position; + DebugDraw2D.Config.TextPadding = text_groups_padding; + + DebugDraw2D.Config.TextCustomFont = custom_font; + + + if (test_text) + { + _text_tests(); + } + + // Lag Test + var lag_test_pos = (Vector3)dLagTest_RESET.GetAnimation("RESET").TrackGetKeyValue(0, 0); + _draw_zone_title_pos(lag_test_pos, "Lag test"); + + dLagTest.Position = lag_test_pos + new Vector3(Mathf.Sin(Time.GetTicksMsec() / 100.0f) * 2.5f, 0, 0); + DebugDraw3D.DrawBox(dLagTest.GlobalPosition, Quaternion.Identity, Vector3.One * 2.01f, Colors.Chocolate, true); + + if (more_test_cases) + { + foreach (var node in dHitTest_RayEmitter.GetChildren()) + { + if (node is RayCast3D ray) + ray.SetPhysicsProcessInternal(true); + } + + _more_tests(); + } + else + { + foreach (var node in dHitTest_RayEmitter.GetChildren()) + { + if (node is RayCast3D ray) + ray.SetPhysicsProcessInternal(false); + } + } + + _draw_other_world(); + + if (draw_array_of_boxes) + { + _draw_array_of_boxes(); + } + + } + + void _text_tests() + { + DebugDraw2D.SetText("FPS", $"{Engine.GetFramesPerSecond():F2}", 0, Colors.Gold); + + if (text_groups_show_examples) + { + if (timer_text < 0) + { + DebugDraw2D.SetText("Some delayed text", "for 2.5s", -1, Colors.Black, 2.5f); // it's supposed to show text for 2.5 seconds + timer_text += 5; + } + + DebugDraw2D.BeginTextGroup("-- First Group --", 2, Colors.LimeGreen, true, text_groups_title_font_size, text_groups_text_font_size); + DebugDraw2D.SetText("Simple text"); + DebugDraw2D.SetText("Text", "Value", 0, Colors.Aquamarine); + DebugDraw2D.SetText("Text out of order", null, -1, Colors.Silver); + DebugDraw2D.BeginTextGroup("-- Second Group --", 1, Colors.Beige); + DebugDraw2D.SetText("Rendered frames", Engine.GetFramesDrawn()); + DebugDraw2D.EndTextGroup(); + } + + if (text_groups_show_stats) + { + DebugDraw2D.BeginTextGroup("-- Stats --", 3, Colors.Wheat); + var render_stats = DebugDraw3D.GetRenderStats(); + + if (render_stats != null && text_groups_show_stats) + { + DebugDraw2D.SetText("Total", render_stats.TotalGeometry); + DebugDraw2D.SetText("Instances", render_stats.Instances, 1); + DebugDraw2D.SetText("Lines", render_stats.Lines, 2); + DebugDraw2D.SetText("Total Visible", render_stats.TotalVisible, 3); + DebugDraw2D.SetText("Visible Instances", render_stats.VisibleInstances, 4); + DebugDraw2D.SetText("Visible Lines", render_stats.VisibleLines, 5); + + DebugDraw2D.SetText("---", "", 12); + + DebugDraw2D.SetText("Culling time", $"{(render_stats.TotalTimeCullingUsec / 1000.0):F2} ms", 13); + DebugDraw2D.SetText("Filling instances buffer", $"{(render_stats.TimeFillingBuffersInstancesUsec / 1000.0):F2} ms", 14); + DebugDraw2D.SetText("Filling lines buffer", $"{(render_stats.TimeFillingBuffersLinesUsec / 1000.0):F2} ms", 15); + DebugDraw2D.SetText("Filling time", $"{(render_stats.TotalTimeFillingBuffersUsec / 1000.0):F2} ms", 16); + DebugDraw2D.SetText("Total time", $"{(render_stats.TotalTimeSpentUsec / 1000.0):F2} ms", 17); + + DebugDraw2D.SetText("----", null, 32); + + DebugDraw2D.SetText("Total Label3D", render_stats.NodesLabel3dExistsTotal, 33); + DebugDraw2D.SetText("Visible Label3D", render_stats.NodesLabel3dVisible + render_stats.NodesLabel3dVisiblePhysics, 34); + + DebugDraw2D.SetText("-----", null, 48); + + DebugDraw2D.SetText("Created scoped configs", $"{render_stats.CreatedScopedConfigs}", 49); + } + + if (text_groups_show_stats && text_groups_show_stats_2d) + { + DebugDraw2D.SetText("------", null, 64); + } + + var render_stats_2d = DebugDraw2D.GetRenderStats(); + if (render_stats_2d != null && text_groups_show_stats_2d) + { + DebugDraw2D.SetText("Text groups", render_stats_2d.OverlayTextGroups, 96); + DebugDraw2D.SetText("Text lines", render_stats_2d.OverlayTextLines, 97); + } + DebugDraw2D.EndTextGroup(); + } + + if (text_groups_show_hints) + { + DebugDraw2D.BeginTextGroup("controls", 1024, Colors.White, false); + if (!Engine.IsEditorHint()) + { + DebugDraw2D.SetText("WASD QE, LMB", "To move", 0); + } + DebugDraw2D.SetText("Alt: change render layers", DebugDraw3D.Config.GeometryRenderLayers, 1); + if (!OS.HasFeature("web")) + { + DebugDraw2D.SetText("Ctrl: toggle anti-aliasing", GetViewport().Msaa3D == Viewport.Msaa.Msaa4X ? "MSAA 4x" : "Disabled", 2); + } + DebugDraw2D.SetText("Down: freeze render", DebugDraw3D.Config.Freeze3dRender, 3); + if (Engine.IsEditorHint()) + { + DebugDraw2D.SetText("Up: use scene camera", DebugDraw3D.Config.ForceUseCameraFromScene, 4); + } + DebugDraw2D.SetText("1,2,3: toggle debug", $"{DebugDraw3D.DebugEnabled}, {DebugDraw2D.DebugEnabled} 😐, {DebugDrawManager.DebugEnabled} 😏", 5); + DebugDraw2D.SetText("Left: toggle frustum culling", DebugDraw3D.Config.UseFrustumCulling, 6); + DebugDraw2D.SetText("Right: draw bounds for culling", DebugDraw3D.Config.VisibleInstanceBounds, 7); + } + } + + void _draw_zone_title(Node3D node, string title) + { + if (draw_3d_text) + { + using var _s1 = DebugDraw3D.NewScopedConfig().SetTextOutlineSize(72); + DebugDraw3D.DrawText(node.GlobalPosition + node.GlobalBasis.Y * 0.85f, title, 128); + } + } + + void _draw_zone_title_pos(Vector3 pos, string title, int font_size = 128, int outline = 72) + { + if (draw_3d_text) + { + using var _s1 = DebugDraw3D.NewScopedConfig().SetTextOutlineSize(outline); + DebugDraw3D.DrawText(pos, title, font_size); + } + } + + const float _local_mul = 0.45f; + static readonly Vector3 _local_mul_vec = new(_local_mul, _local_mul, _local_mul); + Vector3[] __local_lines_cross_recursive = [new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f)]; + Transform3D __local_box_recursive = Transform3D.Identity.RotatedLocal(Vector3.Up, Mathf.DegToRad(30)).Translated(new Vector3(-0.25f, -0.55f, 0.25f)).Scaled(_local_mul_vec); + Transform3D __local_sphere_recursive = Transform3D.Identity.Translated(new Vector3(0.5f, 0.55f, -0.5f)).Scaled(_local_mul_vec); + + void _draw_local_xf_box(Transform3D xf, float thickness, int max_depth, int depth = 0) + { + if (depth >= max_depth) + return; + + using var _s1 = DebugDraw3D.NewScopedConfig().SetThickness(thickness).SetTransform(xf); + + // a box with a small offset + DebugDraw3D.DrawBoxXf(new Transform3D(Basis.Identity, new Vector3(0, 0.001f, 0)), Colors.Brown); + // a box and a stand for the next depth + DebugDraw3D.DrawBoxXf(__local_box_recursive, Colors.Chartreuse); + // just a sphere and lines + DebugDraw3D.DrawSphereXf(__local_sphere_recursive, Colors.DarkOrange); + + _s1.SetThickness(0); + + DebugDraw3D.DrawLines(__local_lines_cross_recursive, Colors.Crimson); + + // A simple animation generator with descent into the depth of the scene +#if false + { + Animation anim = pRecursiveTransformTest.GetAnimation("recursive"); + // clear keys + if (depth == 0) + for (var i = 0; i < anim.TrackGetKeyCount(0); i++) + { + anim.TrackRemoveKey(0, 0); + anim.TrackRemoveKey(1, 0); + } + + var time = depth * 2; + var s_xf = xf * __local_sphere_recursive; + var next_s_xf = (xf * __local_box_recursive.Translated(__local_box_recursive.Basis.Y)) * __local_sphere_recursive; + var get_sphere_pos = (Transform3D l_xf) => l_xf.Origin + (l_xf).Basis.Y; + + anim.PositionTrackInsertKey(0, time, get_sphere_pos(s_xf)); + anim.RotationTrackInsertKey(1, time, new Transform3D(Basis.Identity, get_sphere_pos(s_xf)).LookingAt(get_sphere_pos(next_s_xf), xf.Basis.Y).Basis.GetRotationQuaternion()); + } +#endif + + _draw_local_xf_box(xf * __local_box_recursive.Translated(__local_box_recursive.Basis.Y), thickness * _local_mul, max_depth, depth + 1); + } + + + void _draw_other_world() + { + using var s = DebugDraw3D.NewScopedConfig().SetViewport(dOtherWorldBox.GetViewport()); + DebugDraw3D.DrawBoxXf(dOtherWorldBox.GlobalTransform.RotatedLocal(new Vector3(1, 1, -1).Normalized(), Mathf.Wrap(Time.GetTicksMsec() / 1000.0f, 0f, Mathf.Tau)), Colors.SandyBrown); + DebugDraw3D.DrawBoxXf(dOtherWorldBox.GlobalTransform.RotatedLocal(new Vector3(-1, 1, -1).Normalized(), Mathf.Wrap(Time.GetTicksMsec() / 1000.0f, 0f, Mathf.Tau) - Mathf.Pi / 4), Colors.SandyBrown); + + if (draw_3d_text) + { + var angle = Mathf.Wrap(Time.GetTicksMsec() / 1000.0f, 0, Mathf.Tau); + using (var _w2 = DebugDraw3D.NewScopedConfig().SetTextFont(custom_3d_font)) + { + DebugDraw3D.DrawText(dOtherWorldBox.GlobalPosition + new Vector3(Mathf.Cos(angle), -0.25f, Mathf.Sin(angle)), "Hello world!", 32, Colors.Crimson, 0); + } + + using (var _w3 = DebugDraw3D.NewScopedConfig().SetNoDepthTest(true).SetTextOutlineColor(Colors.IndianRed).SetTextOutlineSize(6)) + { + DebugDraw3D.DrawText(dOtherWorldBox.GlobalPosition + new Vector3(Mathf.Cos(angle), +0.25f, Mathf.Sin(-angle)), "World without depth", 20, Colors.Pink, 0); + } + } + } + + void _draw_rays_casts() + { + // Line hits render + _draw_zone_title_pos(pHitTestSphere.GlobalPosition, "Line hits", 96, 36); + + foreach (var node in dHitTest_RayEmitter.GetChildren()) + { + if (node is RayCast3D ray) + { + ray.ForceRaycastUpdate(); + DebugDraw3D.DrawLineHit(ray.GlobalPosition, ray.ToGlobal(ray.TargetPosition), ray.GetCollisionPoint(), ray.IsColliding(), 0.3f); + } + } + } + + void _more_tests() + { + // Delayed line render + using (var s = DebugDraw3D.NewScopedConfig().SetThickness(0.035f)) + { + DebugDraw3D.DrawLine(dLagTest.GlobalPosition + Vector3.Up, dLagTest.GlobalPosition + new Vector3(0, 3, Mathf.Sin(Time.GetTicksMsec() / 50.0f)), null, 0.35f); + + if (draw_3d_text) + { + DebugDraw3D.DrawText(dLagTest.GlobalPosition + new Vector3(0, 3, Mathf.Sin(Time.GetTicksMsec() / 50.0f)), $"{Mathf.Sin(Time.GetTicksMsec() / 50.0f):F1}", 16, null, 0.35f); + } + } + + // Draw plane + using (var _s11 = DebugDraw3D.NewScopedConfig().SetThickness(0.02f).SetPlaneSize(10)) + { + var pl_node = GetNode("PlaneOrigin"); + var xf = pl_node.GlobalTransform; + var normal = xf.Basis.Y.Normalized(); + var plane = new Plane(normal, xf.Origin.Dot(normal)); + + var vp = GetViewport(); + if (Engine.IsEditorHint() && (Viewport)Engine.GetSingleton("EditorInterface").Call("get_editor_viewport_3d", 0) != null) + { + vp = (Viewport)Engine.GetSingleton("EditorInterface").Call("get_editor_viewport_3d", 0); + } + + var cam = vp.GetCamera3D(); + if (cam != null) + { + var dir = vp.GetCamera3D().ProjectRayNormal(vp.GetMousePosition()); + Vector3? intersect = plane.IntersectsRay(cam.GlobalPosition, dir); + + DebugDraw3D.DrawPlane(plane, Colors.Coral * new Color(1, 1, 1, 0.4f), pl_node.GlobalPosition); + if (intersect.HasValue && intersect.Value.DistanceTo(pl_node.GlobalPosition) < _s11.GetPlaneSize() * 0.5f) + { + // Need to test different colors on both sides of the plane + var col = plane.IsPointOver(cam.GlobalPosition) ? Colors.Firebrick : Colors.Aquamarine; + DebugDraw3D.DrawSphere(intersect.Value, 0.3f, col); + } + } + } + } + + void _draw_array_of_boxes() + { + // Lots of boxes to check performance.. + var x_size = 50; + var y_size = 50; + var z_size = 3; + var mul = 1.0f; + var cubes_max_time = 1.25f; + var show_text = draw_text_with_boxes; + using var cfg = DebugDraw3D.NewScopedConfig(); + + if (draw_1m_boxes) + { + x_size = 100; + y_size = 100; + z_size = 100; + mul = 4.0f; + cubes_max_time = 60f; + draw_text_with_boxes = false; + } + + var size = Vector3.One; + var half_size = size * 0.5f; + + if (timer_cubes <= 0) + { + var start_time = Time.GetTicksUsec(); + for (int x = 0; x < x_size; x++) + { + for (int y = 0; y < y_size; y++) + { + for (int z = 0; z < z_size; z++) + { + cfg.SetThickness(Random.Shared.NextSingle() * 0.1f); + var pos = new Vector3(x * mul, (-4 - z) * mul, y * mul) + GlobalPosition; + DebugDraw3D.DrawBox(pos, Quaternion.Identity, size, null, false, cubes_max_time); + + if (show_text && z == 0) + { + DebugDraw3D.DrawText(pos + half_size, pos.ToString(), 32, null, cubes_max_time); + } + } + } + } + //GD.Print($"Draw Cubes: {((Time.GetTicksUsec() - start_time) / 1000.0):F3}ms"); + timer_cubes = cubes_max_time; + } + } + + Node3D dHitTest; + CsgBox3D dLagTest; + PanelContainer dPanel; + Node3D dZones; + Node3D dSpherePosition; + Node3D dSphereTransform; + Node3D dSphereHDTransform; + Node3D dAABB; + Node3D dAABB_fixed; + Node3D dBox1; + Node3D dBox2; + Node3D dBox3; + Node3D dBoxAB; + Node3D dBoxABa; + Node3D dBoxABb; + Node3D dBoxABup; + Node3D dBoxABEdge; + Node3D dBoxABEdgea; + Node3D dBoxABEdgeb; + Node3D dBoxABEdgeup; + Node3D dLines_1; + Node3D dLines_2; + Node3D dLines_3; + Node3D dLines_4; + Node3D dLines_5; + Node3D dLines_6; + Node3D dLines_7; + Node3D dLines_8; + Node3D dLines_Target; + Node3D dLinePath; + Node3D dCylinder1; + Node3D dCylinder2; + Node3D dCylinder3a; + Node3D dCylinder3b; + + Node3D pSpheresBox; + Node3D pCylindersBox; + Node3D pBoxesBox; + Node3D pLinesBox; + Node3D pPathsBox; + Node3D pMiscBox; + + MeshInstance3D dPlaneOrigin; + MeshInstance3D pZDepthTestCube; + + MeshInstance3D dOtherWorld; + SubViewport dOtherWorldViewport; + Node3D dOtherWorldBox; + + Control dCustomCanvas; + Node3D dMisc_Arrow; + Camera3D dCamera; + Node3D dMisc_Billboard; + Node3D dMisc_Position; + Node3D dMisc_GizmoTransform; + Node3D dMisc_GizmoNormal; + Node3D dMisc_GizmoOneColor; + Node3D pLocalTransformRecursiveOrigin; + AnimationPlayer pRecursiveTransformTest; + + Node3D dGrids_Grid; + Node3D dGrids_Grid_Subdivision; + Node3D dGrids_GridCentered_Subdivision; + Node3D dGrids_GridCentered; + + MeshInstance3D dPostProcess; + AnimationPlayer dLagTest_RESET; + Node3D dHitTest_RayEmitter; + Node3D pHitTestSphere; + + void _get_nodes() + { + dHitTest = GetNode("HitTest"); + dLagTest = GetNode("LagTest"); + dPanel = GetNode("Panel"); + dZones = GetNode("Zones"); + dSpherePosition = GetNode("Spheres/SpherePosition"); + dSphereTransform = GetNode("Spheres/SphereTransform"); + dSphereHDTransform = GetNode("Spheres/SphereHDTransform"); + dAABB = GetNode("Boxes/AABB"); + dAABB_fixed = GetNode("Boxes/AABB_fixed"); + dBox1 = GetNode("Boxes/Box1"); + dBox2 = GetNode("Boxes/Box2"); + dBox3 = GetNode("Boxes/Box3"); + dBoxAB = GetNode("Boxes/BoxAB"); + dBoxABa = GetNode("Boxes/BoxAB/a"); + dBoxABb = GetNode("Boxes/BoxAB/b"); + dBoxABup = GetNode("Boxes/BoxAB/o/up"); + dBoxABEdge = GetNode("Boxes/BoxABEdge"); + dBoxABEdgea = GetNode("Boxes/BoxABEdge/a"); + dBoxABEdgeb = GetNode("Boxes/BoxABEdge/b"); + dBoxABEdgeup = GetNode("Boxes/BoxABEdge/o/up"); + dLines_1 = GetNode("Lines/1"); + dLines_2 = GetNode("Lines/2"); + dLines_3 = GetNode("Lines/3"); + dLines_4 = GetNode("Lines/4"); + dLines_5 = GetNode("Lines/5"); + dLines_6 = GetNode("Lines/6"); + dLines_7 = GetNode("Lines/7"); + dLines_8 = GetNode("Lines/8"); + dLines_Target = GetNode("Lines/Target"); + dLinePath = GetNode("LinePath"); + dCylinder1 = GetNode("Cylinders/Cylinder1"); + dCylinder2 = GetNode("Cylinders/Cylinder2"); + dCylinder3a = GetNode("Cylinders/Cylinder3/1"); + dCylinder3b = GetNode("Cylinders/Cylinder3/2"); + + pSpheresBox = GetNode("%SpheresBox"); + pCylindersBox = GetNode("%CylindersBox"); + pBoxesBox = GetNode("%BoxesBox"); + pLinesBox = GetNode("%LinesBox"); + pPathsBox = GetNode("%PathsBox"); + pMiscBox = GetNode("%MiscBox"); + + dPlaneOrigin = GetNode("PlaneOrigin"); + pZDepthTestCube = GetNode("%ZDepthTestCube"); + + dOtherWorld = GetNode("OtherWorld"); + dOtherWorldViewport = GetNode("OtherWorld/SubViewport"); + dOtherWorldBox = GetNode("OtherWorld/SubViewport/SubViewportContainer/SubViewport/OtherWorldBox"); + + dCustomCanvas = GetNode("CustomCanvas"); + dMisc_Arrow = GetNode("Misc/Arrow"); + dCamera = GetNode("Camera"); + dMisc_Billboard = GetNode("Misc/Billboard"); + dMisc_Position = GetNode("Misc/Position"); + dMisc_GizmoTransform = GetNode("Misc/GizmoTransform"); + dMisc_GizmoNormal = GetNode("Misc/GizmoNormal"); + dMisc_GizmoOneColor = GetNode("Misc/GizmoOneColor"); + pLocalTransformRecursiveOrigin = GetNode("%LocalTransformRecursiveOrigin"); + pRecursiveTransformTest = GetNode("%RecursiveTransformTest"); + + dGrids_Grid = GetNode("Grids/Grid"); + dGrids_Grid_Subdivision = GetNode("Grids/Grid/Subdivision"); + dGrids_GridCentered_Subdivision = GetNode("Grids/GridCentered/Subdivision"); + dGrids_GridCentered = GetNode("Grids/GridCentered"); + + dPostProcess = GetNode("PostProcess"); + + dLagTest_RESET = GetNode("LagTest/RESET"); + dHitTest_RayEmitter = GetNode("HitTest/RayEmitter"); + pHitTestSphere = GetNode("%HitTestSphere"); + } +} diff --git a/examples_dd3d/DebugDrawDemoSceneCS.cs.uid b/examples_dd3d/DebugDrawDemoSceneCS.cs.uid new file mode 100644 index 0000000..8576e05 --- /dev/null +++ b/examples_dd3d/DebugDrawDemoSceneCS.cs.uid @@ -0,0 +1 @@ +uid://dnf8ejsrnlvxb diff --git a/examples_dd3d/DebugDrawDemoSceneCS.tscn b/examples_dd3d/DebugDrawDemoSceneCS.tscn new file mode 100644 index 0000000..670c547 --- /dev/null +++ b/examples_dd3d/DebugDrawDemoSceneCS.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=3 format=3 uid="uid://sxtw8fme7g63"] + +[ext_resource type="PackedScene" uid="uid://c3sccy6x0ht5j" path="res://examples_dd3d/DebugDrawDemoScene.tscn" id="2"] +[ext_resource type="Script" path="res://examples_dd3d/DebugDrawDemoSceneCS.cs" id="2_ipqea"] + +[node name="DebugDrawDemoSceneCS" instance=ExtResource("2")] +script = ExtResource("2_ipqea") + +[node name="Settings" parent="." index="23"] +switch_to_scene = "res://examples_dd3d/DebugDrawDemoScene.tscn" + +[node name="Label" parent="Settings/HBox/VBoxContainer" index="1"] +text = "C# example" + +[node name="SwitchLang" parent="Settings/HBox/VBox/SettingsPanel/VBox" index="13"] +text = "Switch to GDScript" diff --git a/examples_dd3d/PixelatedElegance.ttf b/examples_dd3d/PixelatedElegance.ttf new file mode 100644 index 0000000..cdfeccf --- /dev/null +++ b/examples_dd3d/PixelatedElegance.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:277dd8b507c17c6274367153fc4229aed8a5de50d0299d99ffa7448dafcb01df +size 16336 diff --git a/examples_dd3d/PixelatedElegance.ttf.import b/examples_dd3d/PixelatedElegance.ttf.import new file mode 100644 index 0000000..16ce9d6 --- /dev/null +++ b/examples_dd3d/PixelatedElegance.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://7am1h57ldd6" +path="res://.godot/imported/PixelatedElegance.ttf-aac00801d681e5d2b42b23257b2692a7.fontdata" + +[deps] + +source_file="res://examples_dd3d/PixelatedElegance.ttf" +dest_files=["res://.godot/imported/PixelatedElegance.ttf-aac00801d681e5d2b42b23257b2692a7.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/examples_dd3d/Roboto-Bold.ttf b/examples_dd3d/Roboto-Bold.ttf new file mode 100644 index 0000000..5fdb6b6 --- /dev/null +++ b/examples_dd3d/Roboto-Bold.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d0b991ee3e0be7af01ad7ea8cd2beea6c00a25e679a0226b6737f079aafff86 +size 170760 diff --git a/examples_dd3d/Roboto-Bold.ttf.import b/examples_dd3d/Roboto-Bold.ttf.import new file mode 100644 index 0000000..f9fca34 --- /dev/null +++ b/examples_dd3d/Roboto-Bold.ttf.import @@ -0,0 +1,39 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://erdgllynwqkw" +path="res://.godot/imported/Roboto-Bold.ttf-3674de3d9ad3ee757cd4b4a89f1e126d.fontdata" + +[deps] + +source_file="res://examples_dd3d/Roboto-Bold.ttf" +dest_files=["res://.godot/imported/Roboto-Bold.ttf-3674de3d9ad3ee757cd4b4a89f1e126d.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[{ +"chars": [], +"glyphs": [], +"name": "New Configuration" +}] +language_support={} +script_support={} +opentype_features={} diff --git a/examples_dd3d/VisualizerAudioBus.tres b/examples_dd3d/VisualizerAudioBus.tres new file mode 100644 index 0000000..4c7b662 --- /dev/null +++ b/examples_dd3d/VisualizerAudioBus.tres @@ -0,0 +1,17 @@ +[gd_resource type="AudioBusLayout" load_steps=2 format=3 uid="uid://7sy4h4ibftrk"] + +[sub_resource type="AudioEffectSpectrumAnalyzer" id="AudioEffectSpectrumAnalyzer_odciy"] +resource_name = "SpectrumAnalyzer" +fft_size = 3 + +[resource] +bus/0/mute = true +bus/0/volume_db = -20.0 +bus/1/name = &"MusicAnalyzer" +bus/1/solo = false +bus/1/mute = false +bus/1/bypass_fx = false +bus/1/volume_db = 0.0 +bus/1/send = &"Master" +bus/1/effect/0/effect = SubResource("AudioEffectSpectrumAnalyzer_odciy") +bus/1/effect/0/enabled = true diff --git a/examples_dd3d/addon_icon.gd b/examples_dd3d/addon_icon.gd new file mode 100644 index 0000000..4283024 --- /dev/null +++ b/examples_dd3d/addon_icon.gd @@ -0,0 +1,11 @@ +@tool +extends Node3D + +func _process(delta: float) -> void: + var a = DebugDraw3D.new_scoped_config().set_thickness(0.015) + DebugDraw3D.draw_box_xf($box.global_transform, Color.GREEN) + DebugDraw3D.draw_gizmo($gizmo.global_transform) + DebugDraw3D.draw_grid_xf($gizmo/grid.global_transform, Vector2i(2,2), DebugDraw3D.empty_color, false) + DebugDraw3D.draw_sphere_xf($sphere.global_transform, Color.RED) + DebugDraw3D.draw_cylinder($cylinder.global_transform, Color.BLUE) + DebugDraw3D.draw_line_hit_offset($"line/1".global_transform.origin, $"line/2".global_transform.origin, true, 0.3, 0.1) diff --git a/examples_dd3d/addon_icon.gd.uid b/examples_dd3d/addon_icon.gd.uid new file mode 100644 index 0000000..c3fca43 --- /dev/null +++ b/examples_dd3d/addon_icon.gd.uid @@ -0,0 +1 @@ +uid://b2lj85riqyno0 diff --git a/examples_dd3d/addon_icon.tscn b/examples_dd3d/addon_icon.tscn new file mode 100644 index 0000000..b577312 --- /dev/null +++ b/examples_dd3d/addon_icon.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=3 format=3 uid="uid://1lhiwf8tgleh"] + +[ext_resource type="Script" path="res://examples_dd3d/addon_icon.gd" id="1_bq18y"] + +[sub_resource type="Environment" id="1"] +background_mode = 1 + +[node name="icon" type="Node3D"] +script = ExtResource("1_bq18y") + +[node name="Camera" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 5.39732) +environment = SubResource("1") +current = true + +[node name="box" type="Node3D" parent="."] +transform = Transform3D(0.316305, 0.0204714, -0.293415, -0.239575, 0.267896, -0.239575, 0.170631, 0.338191, 0.207538, -0.410294, 0.312541, 0.243199) + +[node name="gizmo" type="Node3D" parent="."] +transform = Transform3D(0.707107, 0, -0.707107, -0.294265, 0.909294, -0.294265, 0.642968, 0.416154, 0.642968, 0, 0, 0) + +[node name="grid" type="Node3D" parent="gizmo"] +transform = Transform3D(1, -2.98023e-08, 1.19209e-07, 0, 1, 0, 1.19209e-07, -2.98023e-08, 1, -0.0263093, -0.0170284, -0.0263093) + +[node name="sphere" type="Node3D" parent="."] +transform = Transform3D(0.401341, 0.207831, -0.437109, -0.449118, 0.371584, -0.235691, 0.180418, 0.46267, 0.385639, 0.466197, 0.322665, 0.200436) + +[node name="cylinder" type="Node3D" parent="."] +transform = Transform3D(0.155034, 0.231693, -0.112783, -0.160003, 0.264761, -0.0839674, 0.0232275, 0.277352, 0.174372, -0.0566943, -0.290515, 0.905274) + +[node name="line" type="Node3D" parent="."] + +[node name="1" type="Node3D" parent="line"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.568458, -0.615948, 0.653444) + +[node name="2" type="Node3D" parent="line"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0051975, 0.373791, 0.0974927) diff --git a/examples_dd3d/demo_camera_movement.gd b/examples_dd3d/demo_camera_movement.gd new file mode 100644 index 0000000..51f758d --- /dev/null +++ b/examples_dd3d/demo_camera_movement.gd @@ -0,0 +1,60 @@ +extends Camera3D + +@export var mouse_sensitivity := 0.25 +@export var camera_speed := 10.0 +@export var camera_speed_fast := 30.0 + +var btn_clicked := false +const hPI := PI/2 +var rot_x := 0.0 +var rot_y := 0.0 + + +func _ready(): + reset_input_rotation() + + +func _unhandled_input(event) -> void: + if event is InputEventMouseButton: + btn_clicked = event.pressed + + +func reset_input_rotation(): + rot_x = rotation.y + rot_y = rotation.x + + +func _input(event) -> void: + if btn_clicked: + if event is InputEventMouseMotion: + if event.button_mask == MOUSE_BUTTON_LEFT: + rot_x += -deg_to_rad(event.relative.x * mouse_sensitivity) + rot_y += -deg_to_rad(event.relative.y * mouse_sensitivity) + rot_y = clamp(rot_y, -hPI, hPI) + + transform.basis = Basis() + rotate_object_local(Vector3.UP, rot_x) + rotate_object_local(Vector3.RIGHT, rot_y) + + +func get_axis(neg : Array[Key], pos : Array[Key]) -> float: + var pressed = func (arr: Array[Key]): + var p: float = 0 + for k in arr: + if Input.is_physical_key_pressed(k): + p = 1 + break + return p + + return pressed.call(pos) - pressed.call(neg) + + +func _process(delta) -> void: + var motion := Vector2(get_axis([KEY_S], [KEY_W]), get_axis([KEY_A], [KEY_D])) + var lift := get_axis([KEY_Q, KEY_CTRL], [KEY_E, KEY_SPACE]) + var speed := camera_speed_fast if Input.is_physical_key_pressed(KEY_SHIFT) else camera_speed + motion = motion.limit_length() + + var b := global_transform.basis + var v := (-b.z * motion.x) + (b.x * motion.y) + (b.y * lift) + global_position += v.limit_length() * speed * delta diff --git a/examples_dd3d/demo_camera_movement.gd.uid b/examples_dd3d/demo_camera_movement.gd.uid new file mode 100644 index 0000000..03651ca --- /dev/null +++ b/examples_dd3d/demo_camera_movement.gd.uid @@ -0,0 +1 @@ +uid://b5mdrjubj0lg5 diff --git a/examples_dd3d/demo_music_visualizer.gd b/examples_dd3d/demo_music_visualizer.gd new file mode 100644 index 0000000..73e9867 --- /dev/null +++ b/examples_dd3d/demo_music_visualizer.gd @@ -0,0 +1,175 @@ +@tool +extends VBoxContainer + +@export_range(1, 128) var bars_count := 32 +var transform: Transform3D: + get: + return %AudioVisualizer.global_transform +@export_exp_easing("inout") var motion_smoothing := 0.025 +@export_range(0, 0.5) var bar_thickness := 0.065 +@export_range(0, 10) var bars_separation := 0.325 +@export_exp_easing("inout") var color_offset_speed := 0.4 +@export var colors: Gradient = null + +var MusicAnalyzerBus := &"MusicAnalyzer" +var MasterBus := &"Master" +var MAX_HZ := 16000.0 +var MIN_HZ := 20.0 +var MIN_DB := 60.0 +var spectrum: AudioEffectSpectrumAnalyzerInstance = null + +var smoothed_energy: Array[float] = [] +var color_offset := 0.0 + +var _on_data_loaded_callback = null + + +func _ready(): + var bus = AudioServer.get_bus_index(MusicAnalyzerBus) + if bus == -1: + print("'MusicVisualizer' audio bus not found.\nSet 'VisualizerAudioBus.tres' as the default bus to use the audio visualizer.") + + spectrum = AudioServer.get_bus_effect_instance(bus, 0) + %MuteMaster.button_pressed = AudioServer.is_bus_mute(AudioServer.get_bus_index(MasterBus)) + %VolumeSlider.value = db_to_linear(AudioServer.get_bus_volume_db(AudioServer.get_bus_index(MasterBus))) + + if OS.has_feature('web'): + motion_smoothing = motion_smoothing * 1.5 + + _on_data_loaded_callback = JavaScriptBridge.create_callback(_on_data_loaded) + # Retrieve the 'gd_callbacks' object + var gdcallbacks: JavaScriptObject = JavaScriptBridge.get_interface("gd_callbacks") + # Assign the callbacks + gdcallbacks.dataLoaded = _on_data_loaded_callback + + +func _process(_delta): + if %MusicPlayer.playing: + draw_spectrum() + + +func _pressed(): + var open_file = func(filepath: String): + print("Opening '%s'" % filepath) + var file = FileAccess.open(filepath, FileAccess.READ) + var data = file.get_buffer(file.get_length()) + open_stream(filepath.get_extension(), data) + + if DisplayServer.has_feature(DisplayServer.FEATURE_NATIVE_DIALOG): + DisplayServer.file_dialog_show("Select audio file", "", "", true, DisplayServer.FILE_DIALOG_MODE_OPEN_FILE, ["*.mp3"], + func (status: bool, selected: PackedStringArray, _fileter: int): + if status and selected.size(): + open_file.call(selected[0]) + ) + elif OS.has_feature('web'): + JavaScriptBridge.eval("loadData()") + else: + var fd := FileDialog.new() + add_child(fd) + + fd.title = "Select audio file" + fd.access = FileDialog.ACCESS_FILESYSTEM + fd.file_mode = FileDialog.FILE_MODE_OPEN_FILE + fd.current_dir = OS.get_system_dir(OS.SYSTEM_DIR_DOWNLOADS) + fd.add_filter("*.mp3") + fd.popup_centered_ratio(0.8) + + fd.file_selected.connect(func(path: String): + open_file.call(path) + ) + + fd.visibility_changed.connect(func(): + if not fd.visible: + fd.queue_free() + ) + + +func _on_data_loaded(data: Array) -> void: + # Make sure there is something + if (data.size() == 0): + return + + var file_name: String = data[0] + print("Opening '%s'" % file_name) + + var arr: PackedByteArray = JavaScriptBridge.eval("gd_callbacks.dataLoadedResult;") + open_stream(file_name.get_extension(), arr) + + +func open_stream(file_ext: String, data: PackedByteArray): + var stream: AudioStream = null + if file_ext == "mp3": + stream = AudioStreamMP3.new() + stream.data = data + + if not stream.data: + print("Failed to load MP3!") + return + + if not stream: + print("Failed to load music!") + return + + %MusicPlayer.stream = stream + %MusicPlayer.bus = MusicAnalyzerBus + %MusicPlayer.play() + + # Debugging frequencies + for ih in range(1, bars_count + 1): + var _hz: float = log_freq(ih / float(bars_count), MIN_HZ, MAX_HZ) + #print("%.0f hz %.2f" % [_hz, ih / float(bars_count)]) + + +func draw_spectrum(): + var _s1 = DebugDraw3D.scoped_config().set_thickness(bar_thickness).set_center_brightness(0.9) + var prev_hz = MIN_HZ + smoothed_energy.resize(bars_count) + + var xf := transform + var y := xf.basis.y + var h := y.length() + var x := xf.basis.x + var z := xf.basis.z + var origin := xf.origin - (x * bars_count + (x * bars_separation) * (bars_count - 1)) * 0.5 + var sum := 0.0 + + for ih in range(1, bars_count + 1): + var i := ih - 1 + var hz: float = log_freq(ih / float(bars_count), MIN_HZ, MAX_HZ) + var magnitude: float = spectrum.get_magnitude_for_frequency_range(prev_hz, hz, AudioEffectSpectrumAnalyzerInstance.MAGNITUDE_AVERAGE).length() + var energy: float = clampf((MIN_DB + linear_to_db(magnitude)) / MIN_DB, 0, 1) + var e: float = lerp(smoothed_energy[i], energy, clampf(get_process_delta_time() / motion_smoothing if motion_smoothing else 1.0, 0, 1)) + smoothed_energy[i] = e + var height: float = e * h + sum += e + + var s := x * bars_separation + + var a := origin + x * i + s * i + (z * 0.5) + var b := origin + x * (i + 1) + s * i + (z * -0.5) + xf.basis.y.normalized() * clampf(height, 0.001, h) + var c := Color.HOT_PINK + if colors: + c = colors.sample(wrapf(float(ih) / bars_count + color_offset, 0, 1)) + c.s = clamp(c.s - smoothed_energy[i] * 0.3, 0, 1.0) + + DebugDraw3D.draw_box_ab(a, b, y, c) + + prev_hz = hz + + color_offset = wrapf(color_offset + sum / smoothed_energy.size() * clampf(get_process_delta_time() / color_offset_speed if color_offset_speed else 1.0, 0, 1), 0, 1) + + +func log10(val: float) -> float: + return log(val) / 2.302585 + + +func log_freq(pos: float, min_hz: float, max_hz: float) -> float: + return pow(10, log10(min_hz) + (log10(max_hz) - log10(min_hz)) * pos) + + +func _on_volume_slider_value_changed(value): + AudioServer.set_bus_volume_db(AudioServer.get_bus_index(MasterBus), linear_to_db(value)) + + +func _on_mute_master_toggled(toggled_on): + AudioServer.set_bus_mute(AudioServer.get_bus_index(MasterBus), toggled_on) diff --git a/examples_dd3d/demo_music_visualizer.gd.uid b/examples_dd3d/demo_music_visualizer.gd.uid new file mode 100644 index 0000000..7463855 --- /dev/null +++ b/examples_dd3d/demo_music_visualizer.gd.uid @@ -0,0 +1 @@ +uid://bebbekatkxaoe diff --git a/examples_dd3d/demo_settings_panel.gd b/examples_dd3d/demo_settings_panel.gd new file mode 100644 index 0000000..4896b47 --- /dev/null +++ b/examples_dd3d/demo_settings_panel.gd @@ -0,0 +1,103 @@ +@tool +extends Control + +@export var switch_to_scene = "" +var is_ready := false + +func _ready(): + if Engine.is_editor_hint(): + return + + if ProjectSettings.has_setting("application/config/no_csharp_support"): + %SwitchLang.visible = false + + %SwitchLang.disabled = true + + %ThicknessSlider.value = get_parent().debug_thickness + %FrustumScaleSlider.value = get_parent().camera_frustum_scale + %UpdateInPhysics.text = "Update in physics (%d Ticks) *" % ProjectSettings.get_setting("physics/common/physics_ticks_per_second") + %UpdateInPhysics.button_pressed = get_parent().update_in_physics + + %ShowText.button_pressed = get_parent().test_text + %ShowExamples.button_pressed = get_parent().text_groups_show_examples + %ShowStats.button_pressed = get_parent().text_groups_show_stats + %ShowHints.button_pressed = get_parent().text_groups_show_hints + %Draw3DText.button_pressed = get_parent().draw_3d_text + + %DrawBoxes.button_pressed = get_parent().draw_array_of_boxes + %Draw1MBoxes.button_pressed = get_parent().draw_1m_boxes + %DrawBoxesAddText.button_pressed = get_parent().draw_text_with_boxes + + if get_tree(): + await get_tree().create_timer(0.2).timeout + + %SwitchLang.disabled = false + is_ready = true + + +func _on_Button_pressed() -> void: + get_tree().call_deferred("change_scene_to_file", switch_to_scene) + + +func _on_hide_show_panel_pressed(): + if %SettingsPanel.visible: + %SettingsPanel.hide() + %HideShowPanelButton.text = "Show panel" + else: + %SettingsPanel.show() + %HideShowPanelButton.text = "Hide panel" + + +func _on_thickness_slider_value_changed(value): + if not is_ready: return + + get_parent().debug_thickness = value + + +func _on_frustum_scale_slider_value_changed(value): + if not is_ready: return + + get_parent().camera_frustum_scale = value + + +func _on_update_in_physics_toggled(toggled_on): + get_parent().update_in_physics = toggled_on + + +func _on_show_text_toggled(toggled_on: bool) -> void: + get_parent().test_text = toggled_on + + +func _on_show_examples_toggled(toggled_on: bool) -> void: + get_parent().text_groups_show_examples = toggled_on + + +func _on_show_stats_toggled(toggled_on): + get_parent().text_groups_show_stats = toggled_on + + +func _on_show_hints_toggled(toggled_on: bool) -> void: + get_parent().text_groups_show_hints = toggled_on + + +func _on_draw_3d_text_toggled(toggled_on: bool) -> void: + get_parent().draw_3d_text = toggled_on + + +func _on_draw_boxes_toggled(toggled_on): + get_parent().draw_array_of_boxes = toggled_on + + DebugDraw3D.clear_all() + get_parent().timer_cubes = 0 + + +func _on_draw_1m_boxes_toggled(toggled_on): + get_parent().draw_1m_boxes = toggled_on + + if get_parent().draw_array_of_boxes: + DebugDraw3D.clear_all() + get_parent().timer_cubes = 0 + + +func _on_add_text_to_boxes_toggled(toggled_on: bool) -> void: + get_parent().draw_text_with_boxes = toggled_on diff --git a/examples_dd3d/demo_settings_panel.gd.uid b/examples_dd3d/demo_settings_panel.gd.uid new file mode 100644 index 0000000..3b41e62 --- /dev/null +++ b/examples_dd3d/demo_settings_panel.gd.uid @@ -0,0 +1 @@ +uid://83dhsep7l725 diff --git a/examples_dd3d/demo_web_docs_version_select.gd b/examples_dd3d/demo_web_docs_version_select.gd new file mode 100644 index 0000000..c63bc49 --- /dev/null +++ b/examples_dd3d/demo_web_docs_version_select.gd @@ -0,0 +1,42 @@ +extends HBoxContainer + +var _on_versions_loaded_callback = null +@onready var btn: OptionButton = $OptionButton + +func _enter_tree(): + hide() + + +func _ready(): + if OS.has_feature('web'): + _on_versions_loaded_callback = JavaScriptBridge.create_callback(_on_versions_loaded) + var versions_callbacks: JavaScriptObject = JavaScriptBridge.get_interface("versions_callbacks") + versions_callbacks.loaded = _on_versions_loaded_callback + + JavaScriptBridge.eval("loadVersions()") + + +func _on_versions_loaded(args: Array) -> void: + if (args.size() == 0): + return + + var current_version: String = args[0] + + var versions_str: String = JavaScriptBridge.eval("versions_callbacks.versions;") + var version_urls_str: String = JavaScriptBridge.eval("versions_callbacks.version_urls;") + var versions: PackedStringArray = versions_str.split(";", false) + var version_urls: PackedStringArray = version_urls_str.split(";", false) + + if versions: + show() + btn.clear() + btn.item_selected.connect(func(idx): + # move to another version + JavaScriptBridge.eval("window.location.href = \"%s\"" % version_urls[idx]) + ) + + for i in range(versions.size()): + btn.add_item(versions[i], i) + + if versions[i] == current_version: + btn.select(i) diff --git a/examples_dd3d/demo_web_docs_version_select.gd.uid b/examples_dd3d/demo_web_docs_version_select.gd.uid new file mode 100644 index 0000000..a058966 --- /dev/null +++ b/examples_dd3d/demo_web_docs_version_select.gd.uid @@ -0,0 +1 @@ +uid://hvx3t70syvkm -- 2.39.5 From 965b3f6c12bfac08cb4f5a4d9fa9e541c193f351 Mon Sep 17 00:00:00 2001 From: Niamh Nikali Date: Fri, 11 Jul 2025 21:43:03 -0600 Subject: [PATCH 2/4] Migrate binary TTF font files to LFS --- assets/fonts/Silkscreen/Silkscreen-Bold.ttf | Bin 30384 -> 130 bytes .../fonts/Silkscreen/Silkscreen-Regular.ttf | Bin 31960 -> 130 bytes assets/fonts/Silkscreen/Silkscreen-Sharp.ttf | Bin 31960 -> 130 bytes ...xtyfour-Regular-VariableFont_BLED,SCAN.ttf | Bin 70924 -> 130 bytes assets/fonts/VT323/VT323-Regular.ttf | Bin 149688 -> 131 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/fonts/Silkscreen/Silkscreen-Bold.ttf b/assets/fonts/Silkscreen/Silkscreen-Bold.ttf index e934b6faddd96d0c1e783cf7a5b68fdf0b630728..7e8550293545e19590ddc1519fd3b2a7edf2843c 100644 GIT binary patch literal 130 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

gA5 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 U_Ygma|Cdm%e_q2I{!-ol0k3j7KmY&$ diff --git a/assets/fonts/Silkscreen/Silkscreen-Regular.ttf b/assets/fonts/Silkscreen/Silkscreen-Regular.ttf index ecb242b3415bfc708e0b1d189b540241c25f435b..a63060d3bfdefc495bfcc2b2e15490d2eff3a761 100644 GIT binary patch literal 130 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 r|8sThJ6x=kmI~gz_0!lpWsG| diff --git a/assets/fonts/Silkscreen/Silkscreen-Sharp.ttf b/assets/fonts/Silkscreen/Silkscreen-Sharp.ttf index ecb242b3415bfc708e0b1d189b540241c25f435b..a63060d3bfdefc495bfcc2b2e15490d2eff3a761 100644 GIT binary patch literal 130 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 r|8sThJ6x=kmI~gz_0!lpWsG| diff --git a/assets/fonts/Sixtyfour/Sixtyfour-Regular-VariableFont_BLED,SCAN.ttf b/assets/fonts/Sixtyfour/Sixtyfour-Regular-VariableFont_BLED,SCAN.ttf index 5e3941a941044d224dc3311828f69da627aa408c..eac3b945553189d4f811ded9483de7a83f9b219b 100644 GIT binary patch literal 130 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 -- 2.39.5 From f425461a1eabd3575d2c496fda1d13d9dfba48b1 Mon Sep 17 00:00:00 2001 From: Niamh Nikali Date: Fri, 11 Jul 2025 21:43:04 -0600 Subject: [PATCH 3/4] Emit gunk cubes from laser-gunk collision --- .gitattributes | 5 +++++ project.godot | 4 ++++ src/effects/gunk_dust.tscn | 2 ++ src/equipment/laser_cast/laser_cast.gd | 28 ++++++++++++++++++++++++ src/equipment/laser_cast/laser_cast.tscn | 9 +++++++- src/world/gunkable/gunk_dust.gd | 2 +- src/world/gunkable/gunkable.tscn | 5 +---- 7 files changed, 49 insertions(+), 6 deletions(-) diff --git a/.gitattributes b/.gitattributes index 6a215c4..671289a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,8 @@ *.wav filter=lfs diff=lfs merge=lfs -text *.ogg filter=lfs diff=lfs merge=lfs -text *.dds filter=lfs diff=lfs merge=lfs -text +*.dylib filter=lfs diff=lfs merge=lfs -text +*.so filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.dll filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text diff --git a/project.godot b/project.godot index 3bfe520..fd0642f 100644 --- a/project.godot +++ b/project.godot @@ -39,6 +39,10 @@ gdscript/warnings/unsafe_method_access=2 gdscript/warnings/unsafe_cast=1 gdscript/warnings/unsafe_call_argument=2 +[debug_draw_3d] + +settings/addon_root_folder="res://addons/debug_draw_3d" + [display] window/size/viewport_width=1920 diff --git a/src/effects/gunk_dust.tscn b/src/effects/gunk_dust.tscn index 9b0ddc1..923963e 100644 --- a/src/effects/gunk_dust.tscn +++ b/src/effects/gunk_dust.tscn @@ -24,6 +24,8 @@ point_count = 2 curve = SubResource("Curve_smx5b") [sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_ykxlg"] +emission_shape = 4 +emission_point_count = 5 angle_min = -184.7 angle_max = 239.3 direction = Vector3(0, 0, -1) diff --git a/src/equipment/laser_cast/laser_cast.gd b/src/equipment/laser_cast/laser_cast.gd index bcf3525..f997455 100644 --- a/src/equipment/laser_cast/laser_cast.gd +++ b/src/equipment/laser_cast/laser_cast.gd @@ -5,8 +5,13 @@ const NORMAL_OFFSET = 0.05 @export var parent_tool: Spray +# Currently gunking +var gunk_rid: RID +var gunkable: Gunkable + @onready var laser_dust: GPUParticles3D = %LaserDust @onready var glow_light: OmniLight3D = %GlowLight +@onready var gunk_dust: GunkDust = %GunkDust func _process(_delta: float) -> void: @@ -16,6 +21,29 @@ func _process(_delta: float) -> void: if c is Node3D: (c as Node3D).global_position = child_pos + var new_gunk_rid: RID = get_collider_rid() + if new_gunk_rid != gunk_rid: + gunk_rid = new_gunk_rid + if gunkable: + # Disconnect old signals to avoid emitting from previous node and accumulating connections + if gunkable.painted_at_point.is_connected(gunk_dust._on_gunkable_painted_at_point): + gunkable.painted_at_point.disconnect(gunk_dust._on_gunkable_painted_at_point) + if gunkable.clear_total_updated.is_connected( + gunk_dust._on_gunkable_clear_total_updated + ): + gunkable.clear_total_updated.disconnect( + gunk_dust._on_gunkable_clear_total_updated + ) + gunkable = Gunkable.get_component(get_collider()) + if gunkable: + # Connect signals of new gunkable to our gunk dust + if !gunkable.painted_at_point.is_connected(gunk_dust._on_gunkable_painted_at_point): + gunkable.painted_at_point.connect(gunk_dust._on_gunkable_painted_at_point) + if !gunkable.clear_total_updated.is_connected( + gunk_dust._on_gunkable_clear_total_updated + ): + gunkable.clear_total_updated.connect(gunk_dust._on_gunkable_clear_total_updated) + laser_dust.emitting = true glow_light.visible = true # TODO: tween maybe? diff --git a/src/equipment/laser_cast/laser_cast.tscn b/src/equipment/laser_cast/laser_cast.tscn index 10117ae..9f27c89 100644 --- a/src/equipment/laser_cast/laser_cast.tscn +++ b/src/equipment/laser_cast/laser_cast.tscn @@ -1,8 +1,10 @@ -[gd_scene load_steps=4 format=3 uid="uid://b8vradbaw61ga"] +[gd_scene load_steps=6 format=3 uid="uid://b8vradbaw61ga"] [ext_resource type="Script" uid="uid://bqgi5p5nh6k1l" path="res://src/equipment/laser_cast/laser_cast.gd" id="1_xntcr"] [ext_resource type="PackedScene" uid="uid://oc6t5ubyybsa" path="res://src/effects/laser_dust.tscn" id="2_m5xmf"] [ext_resource type="Script" uid="uid://br7war1wh7wfd" path="res://src/equipment/laser_cast/flicker_light.gd" id="3_bkg64"] +[ext_resource type="PackedScene" uid="uid://c3iv00vmdqxp0" path="res://src/effects/gunk_dust.tscn" id="4_ekmqg"] +[ext_resource type="Script" uid="uid://b88k7m1mwrd0v" path="res://src/world/gunkable/gunk_dust.gd" id="5_r1geq"] [node name="LaserCast" type="RayCast3D"] target_position = Vector3(0, 0, -2) @@ -25,3 +27,8 @@ shadow_caster_mask = 4294967293 omni_range = 1.0 omni_attenuation = 0.7 script = ExtResource("3_bkg64") + +[node name="GunkDust" parent="." instance=ExtResource("4_ekmqg")] +unique_name_in_owner = true +emitting = false +script = ExtResource("5_r1geq") diff --git a/src/world/gunkable/gunk_dust.gd b/src/world/gunkable/gunk_dust.gd index f766d8d..d6e8857 100644 --- a/src/world/gunkable/gunk_dust.gd +++ b/src/world/gunkable/gunk_dust.gd @@ -1,4 +1,4 @@ -extends GPUParticles3D +class_name GunkDust extends GPUParticles3D @export var emit_scale := 0.1 diff --git a/src/world/gunkable/gunkable.tscn b/src/world/gunkable/gunkable.tscn index 7d5e881..da61cb7 100644 --- a/src/world/gunkable/gunkable.tscn +++ b/src/world/gunkable/gunkable.tscn @@ -1,9 +1,8 @@ -[gd_scene load_steps=6 format=3 uid="uid://cdi5sl60mw1po"] +[gd_scene load_steps=5 format=3 uid="uid://cdi5sl60mw1po"] [ext_resource type="Script" uid="uid://co0g2klfmor48" path="res://src/world/gunkable/gunkable.gd" id="1_47xoo"] [ext_resource type="Script" uid="uid://bom5qysgfvap1" path="res://src/world/gunkable/draw_controller.gd" id="2_srn13"] [ext_resource type="PackedScene" uid="uid://c3iv00vmdqxp0" path="res://src/effects/gunk_dust.tscn" id="3_vad3y"] -[ext_resource type="Script" uid="uid://b88k7m1mwrd0v" path="res://src/world/gunkable/gunk_dust.gd" id="4_3mpo3"] [sub_resource type="CapsuleMesh" id="CapsuleMesh_3mpo3"] radius = 0.1 @@ -53,8 +52,6 @@ top_level = true emitting = false amount = 64 lifetime = 1.2 -script = ExtResource("4_3mpo3") -emit_scale = 0.08 [node name="DebugMesh" type="MeshInstance3D" parent="GunkDust"] transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0) -- 2.39.5 From d9fe33311fa032fb6881162f555688f1544a625b Mon Sep 17 00:00:00 2001 From: Niamh Nikali Date: Sat, 12 Jul 2025 10:59:35 -0600 Subject: [PATCH 4/4] Possibly better to use instance ID of collider rather than RID --- src/equipment/laser_cast/laser_cast.gd | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/equipment/laser_cast/laser_cast.gd b/src/equipment/laser_cast/laser_cast.gd index f997455..67eb81a 100644 --- a/src/equipment/laser_cast/laser_cast.gd +++ b/src/equipment/laser_cast/laser_cast.gd @@ -6,7 +6,7 @@ const NORMAL_OFFSET = 0.05 @export var parent_tool: Spray # Currently gunking -var gunk_rid: RID +var gunk_id: int var gunkable: Gunkable @onready var laser_dust: GPUParticles3D = %LaserDust @@ -21,9 +21,12 @@ func _process(_delta: float) -> void: if c is Node3D: (c as Node3D).global_position = child_pos - var new_gunk_rid: RID = get_collider_rid() - if new_gunk_rid != gunk_rid: - gunk_rid = new_gunk_rid + var new_gunk_id: int = 0 + var collider: Object = get_collider() + if collider: + new_gunk_id = collider.get_instance_id() + if new_gunk_id != gunk_id: + gunk_id = new_gunk_id if gunkable: # Disconnect old signals to avoid emitting from previous node and accumulating connections if gunkable.painted_at_point.is_connected(gunk_dust._on_gunkable_painted_at_point): @@ -34,7 +37,7 @@ func _process(_delta: float) -> void: gunkable.clear_total_updated.disconnect( gunk_dust._on_gunkable_clear_total_updated ) - gunkable = Gunkable.get_component(get_collider()) + gunkable = Gunkable.get_component(collider) if gunkable: # Connect signals of new gunkable to our gunk dust if !gunkable.painted_at_point.is_connected(gunk_dust._on_gunkable_painted_at_point): -- 2.39.5