diff --git a/Scenes/main.tscn b/Scenes/main.tscn index a4504a9..ca0a049 100644 --- a/Scenes/main.tscn +++ b/Scenes/main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=11 format=3 uid="uid://bj7y7q2qkpnci"] +[gd_scene load_steps=18 format=3 uid="uid://bj7y7q2qkpnci"] [ext_resource type="ArrayMesh" uid="uid://622ethh2pdfa" path="res://Blends/road/road.obj" id="4_jjvhh"] [ext_resource type="PackedScene" uid="uid://dim2geqhn6d35" path="res://Scenes/Prefabs/cart.tscn" id="6_21xkr"] @@ -36,6 +36,69 @@ size = Vector2(0.5, 0.5) [sub_resource type="BoxShape3D" id="BoxShape3D_21xkr"] +[sub_resource type="Gradient" id="Gradient_jjvhh"] +offsets = PackedFloat32Array(0.2, 1) +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_kry3j"] +noise_type = 2 +frequency = 0.03 +cellular_jitter = 3.0 +cellular_return_type = 0 +domain_warp_enabled = true +domain_warp_type = 1 +domain_warp_amplitude = 50.0 +domain_warp_fractal_type = 2 +domain_warp_fractal_lacunarity = 1.5 +domain_warp_fractal_gain = 1.0 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_21xkr"] +seamless = true +color_ramp = SubResource("Gradient_jjvhh") +noise = SubResource("FastNoiseLite_kry3j") + +[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_6bp64"] +_shader_parameters = { +&"bias_distance": 512.0, +&"blend_sharpness": 0.5, +&"depth_blur": 0.0, +&"enable_macro_variation": true, +&"enable_projection": true, +&"flat_terrain_normals": false, +&"macro_variation1": Color(1, 1, 1, 1), +&"macro_variation2": Color(1, 1, 1, 1), +&"macro_variation_slope": 0.333, +&"mipmap_bias": 1.0, +&"noise1_angle": 0.0, +&"noise1_offset": Vector2(0.5, 0.5), +&"noise1_scale": 0.04, +&"noise2_scale": 0.076, +&"noise_texture": SubResource("NoiseTexture2D_21xkr"), +&"projection_threshold": 0.8 +} +show_checkered = true + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_344ge"] +transparency = 4 +cull_mode = 2 +vertex_color_use_as_albedo = true +backlight_enabled = true +backlight = Color(0.5, 0.5, 0.5, 1) +distance_fade_mode = 1 +distance_fade_min_distance = 128.0 +distance_fade_max_distance = 96.0 + +[sub_resource type="Terrain3DMeshAsset" id="Terrain3DMeshAsset_ynf5e"] +generated_type = 1 +height_offset = 0.5 +material_override = SubResource("StandardMaterial3D_344ge") +last_lod = 0 +last_shadow_lod = 0 +lod0_range = 128.0 + +[sub_resource type="Terrain3DAssets" id="Terrain3DAssets_hptm8"] +mesh_list = Array[Terrain3DMeshAsset]([SubResource("Terrain3DMeshAsset_ynf5e")]) + [node name="Main" type="Node3D"] [node name="WorldEnvironment" type="WorldEnvironment" parent="."] @@ -111,3 +174,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 20.3213, 36.9694, -59.4263) [node name="ground2" parent="." instance=ExtResource("6_344ge")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 180.354, 36.969, -59.426) + +[node name="Terrain3D" type="Terrain3D" parent="."] +data_directory = "res://Terrain_data" +material = SubResource("Terrain3DMaterial_6bp64") +assets = SubResource("Terrain3DAssets_hptm8") +show_checkered = true +top_level = true +metadata/_edit_lock_ = true diff --git a/addons/terrain_3d/LICENSE.txt b/addons/terrain_3d/LICENSE.txt new file mode 100644 index 0000000..368567b --- /dev/null +++ b/addons/terrain_3d/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Cory Petkovsek, Roope Palmroos, and Contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/addons/terrain_3d/README.md b/addons/terrain_3d/README.md new file mode 100644 index 0000000..1260ae0 --- /dev/null +++ b/addons/terrain_3d/README.md @@ -0,0 +1,52 @@ +![Terrain3D Logo](/doc/docs/images/terrain3d.jpg) + +# Terrain3D +A high performance, editable terrain system for Godot 4. + + +## Features +* Written in C++ as a GDExtension addon, which works with official builds of Godot Engine +* [Can be accessed](https://terrain3d.readthedocs.io/en/stable/docs/programming_languages.html) by GDScript, C#, and any language Godot supports +* Terrains as small as 64x64m up to 65.5x65.5km (4295km^2) in non-contiguous and variable sized regions +* Up to 32 textures +* Up to 10 levels of detail for the terrain mesh +* Foliage instancing, with up to 10 levels of detail, and a shadow impostor +* Sculpting, holes, texture painting, texture detiling, painting colors and wetness +* Imports heightmaps from [HTerrain](https://github.com/Zylann/godot_heightmap_plugin/), Gaea, World Creator, World Machine, Unity, Unreal and any tool that can export a heightmap. See [heightmaps](https://terrain3d.readthedocs.io/en/stable/docs/heightmaps.html) + + +## Games Using Terrain3D + +Please see the [featured games using Terrain3D](https://terrain3d.readthedocs.io/en/latest/docs/games.html) for examples of what it can do. + + +## Getting Started + +1. Read the [Introduction](https://terrain3d.readthedocs.io/en/stable/docs/introduction.html) to understand how this terrain system works. + +2. Read the [Installation & Upgrade](https://terrain3d.readthedocs.io/en/stable/docs/installation.html) instructions. + +3. Watch the [tutorial videos](https://terrain3d.readthedocs.io/en/stable/docs/tutorial_videos.html) and read through the documentation. + +4. For support, read [Getting Help](https://terrain3d.readthedocs.io/en/stable/docs/getting_help.html) and join our [Discord server](https://tokisan.com/discord). + + +## Credit +Developed for the Godot community by: + +||| +|--|--| +| **Cory Petkovsek, Tokisan Games** | [](https://twitter.com/TokisanGames) [](https://github.com/TokisanGames) [](https://tokisan.com/) [](https://tokisan.com/discord) [](https://www.youtube.com/@TokisanGames)| +| **Roope Palmroos, Outobugi Games** | [](https://twitter.com/outobugi) [](https://github.com/outobugi) [](https://outobugi.com/) [](https://www.youtube.com/@outobugi)| + +And the contribution team in [AUTHORS.md](https://terrain3d.readthedocs.io/en/stable/docs/authors.html) and on the right of the github page. + + +## Contributing + +Please see [CONTRIBUTING.md](https://github.com/TokisanGames/Terrain3D/blob/main/CONTRIBUTING.md) if you would like to help make Terrain3D the best terrain system for Godot. + + +## License + +This addon has been released under the [MIT License](https://github.com/TokisanGames/Terrain3D/blob/main/LICENSE.txt). diff --git a/addons/terrain_3d/bin/libterrain.android.debug.arm32.so b/addons/terrain_3d/bin/libterrain.android.debug.arm32.so new file mode 100644 index 0000000..73873d2 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.android.debug.arm32.so differ diff --git a/addons/terrain_3d/bin/libterrain.android.debug.arm64.so b/addons/terrain_3d/bin/libterrain.android.debug.arm64.so new file mode 100644 index 0000000..12a2dda Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.android.debug.arm64.so differ diff --git a/addons/terrain_3d/bin/libterrain.android.release.arm32.so b/addons/terrain_3d/bin/libterrain.android.release.arm32.so new file mode 100644 index 0000000..0820e70 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.android.release.arm32.so differ diff --git a/addons/terrain_3d/bin/libterrain.android.release.arm64.so b/addons/terrain_3d/bin/libterrain.android.release.arm64.so new file mode 100644 index 0000000..5824276 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.android.release.arm64.so differ diff --git a/addons/terrain_3d/bin/libterrain.ios.debug.universal.dylib b/addons/terrain_3d/bin/libterrain.ios.debug.universal.dylib new file mode 100644 index 0000000..1268f1e Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.ios.debug.universal.dylib differ diff --git a/addons/terrain_3d/bin/libterrain.ios.release.universal.dylib b/addons/terrain_3d/bin/libterrain.ios.release.universal.dylib new file mode 100644 index 0000000..433e104 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.ios.release.universal.dylib differ diff --git a/addons/terrain_3d/bin/libterrain.linux.debug.x86_64.so b/addons/terrain_3d/bin/libterrain.linux.debug.x86_64.so new file mode 100644 index 0000000..67f9efc Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.linux.debug.x86_64.so differ diff --git a/addons/terrain_3d/bin/libterrain.linux.release.x86_64.so b/addons/terrain_3d/bin/libterrain.linux.release.x86_64.so new file mode 100644 index 0000000..55aad2f Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.linux.release.x86_64.so differ diff --git a/addons/terrain_3d/bin/libterrain.macos.debug.framework/libterrain.macos.debug b/addons/terrain_3d/bin/libterrain.macos.debug.framework/libterrain.macos.debug new file mode 100644 index 0000000..ae20905 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.macos.debug.framework/libterrain.macos.debug differ diff --git a/addons/terrain_3d/bin/libterrain.macos.release.framework/libterrain.macos.release b/addons/terrain_3d/bin/libterrain.macos.release.framework/libterrain.macos.release new file mode 100644 index 0000000..3253c76 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.macos.release.framework/libterrain.macos.release differ diff --git a/addons/terrain_3d/bin/libterrain.web.debug.wasm32.wasm b/addons/terrain_3d/bin/libterrain.web.debug.wasm32.wasm new file mode 100644 index 0000000..8517ee3 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.web.debug.wasm32.wasm differ diff --git a/addons/terrain_3d/bin/libterrain.web.release.wasm32.wasm b/addons/terrain_3d/bin/libterrain.web.release.wasm32.wasm new file mode 100644 index 0000000..45ac636 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.web.release.wasm32.wasm differ diff --git a/addons/terrain_3d/bin/libterrain.windows.debug.x86_64.dll b/addons/terrain_3d/bin/libterrain.windows.debug.x86_64.dll new file mode 100644 index 0000000..78f7c45 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.windows.debug.x86_64.dll differ diff --git a/addons/terrain_3d/bin/libterrain.windows.release.x86_64.dll b/addons/terrain_3d/bin/libterrain.windows.release.x86_64.dll new file mode 100644 index 0000000..8aa37c5 Binary files /dev/null and b/addons/terrain_3d/bin/libterrain.windows.release.x86_64.dll differ diff --git a/addons/terrain_3d/brushes/.gdignore b/addons/terrain_3d/brushes/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/addons/terrain_3d/brushes/acrylic1.exr b/addons/terrain_3d/brushes/acrylic1.exr new file mode 100644 index 0000000..14b66d6 Binary files /dev/null and b/addons/terrain_3d/brushes/acrylic1.exr differ diff --git a/addons/terrain_3d/brushes/circle0.exr b/addons/terrain_3d/brushes/circle0.exr new file mode 100644 index 0000000..78937f1 Binary files /dev/null and b/addons/terrain_3d/brushes/circle0.exr differ diff --git a/addons/terrain_3d/brushes/circle1.exr b/addons/terrain_3d/brushes/circle1.exr new file mode 100644 index 0000000..e91d97e Binary files /dev/null and b/addons/terrain_3d/brushes/circle1.exr differ diff --git a/addons/terrain_3d/brushes/circle2.exr b/addons/terrain_3d/brushes/circle2.exr new file mode 100644 index 0000000..f6931ba Binary files /dev/null and b/addons/terrain_3d/brushes/circle2.exr differ diff --git a/addons/terrain_3d/brushes/circle3.exr b/addons/terrain_3d/brushes/circle3.exr new file mode 100644 index 0000000..477ab7e Binary files /dev/null and b/addons/terrain_3d/brushes/circle3.exr differ diff --git a/addons/terrain_3d/brushes/circle4.exr b/addons/terrain_3d/brushes/circle4.exr new file mode 100644 index 0000000..b466f92 Binary files /dev/null and b/addons/terrain_3d/brushes/circle4.exr differ diff --git a/addons/terrain_3d/brushes/hill1.exr b/addons/terrain_3d/brushes/hill1.exr new file mode 100644 index 0000000..a668ab6 Binary files /dev/null and b/addons/terrain_3d/brushes/hill1.exr differ diff --git a/addons/terrain_3d/brushes/hill2.exr b/addons/terrain_3d/brushes/hill2.exr new file mode 100644 index 0000000..068e22b Binary files /dev/null and b/addons/terrain_3d/brushes/hill2.exr differ diff --git a/addons/terrain_3d/brushes/mountain1.exr b/addons/terrain_3d/brushes/mountain1.exr new file mode 100644 index 0000000..be71748 Binary files /dev/null and b/addons/terrain_3d/brushes/mountain1.exr differ diff --git a/addons/terrain_3d/brushes/mountain2.exr b/addons/terrain_3d/brushes/mountain2.exr new file mode 100644 index 0000000..ca30373 Binary files /dev/null and b/addons/terrain_3d/brushes/mountain2.exr differ diff --git a/addons/terrain_3d/brushes/mountain3.exr b/addons/terrain_3d/brushes/mountain3.exr new file mode 100644 index 0000000..ca07a1e Binary files /dev/null and b/addons/terrain_3d/brushes/mountain3.exr differ diff --git a/addons/terrain_3d/brushes/mountain4.exr b/addons/terrain_3d/brushes/mountain4.exr new file mode 100644 index 0000000..f8197fe Binary files /dev/null and b/addons/terrain_3d/brushes/mountain4.exr differ diff --git a/addons/terrain_3d/brushes/peak1.exr b/addons/terrain_3d/brushes/peak1.exr new file mode 100644 index 0000000..49d341e Binary files /dev/null and b/addons/terrain_3d/brushes/peak1.exr differ diff --git a/addons/terrain_3d/brushes/peak2.exr b/addons/terrain_3d/brushes/peak2.exr new file mode 100644 index 0000000..db74297 Binary files /dev/null and b/addons/terrain_3d/brushes/peak2.exr differ diff --git a/addons/terrain_3d/brushes/peak3.exr b/addons/terrain_3d/brushes/peak3.exr new file mode 100644 index 0000000..9383681 Binary files /dev/null and b/addons/terrain_3d/brushes/peak3.exr differ diff --git a/addons/terrain_3d/brushes/ring1.exr b/addons/terrain_3d/brushes/ring1.exr new file mode 100644 index 0000000..6396804 Binary files /dev/null and b/addons/terrain_3d/brushes/ring1.exr differ diff --git a/addons/terrain_3d/brushes/smoke.exr b/addons/terrain_3d/brushes/smoke.exr new file mode 100644 index 0000000..021947b Binary files /dev/null and b/addons/terrain_3d/brushes/smoke.exr differ diff --git a/addons/terrain_3d/brushes/square1.exr b/addons/terrain_3d/brushes/square1.exr new file mode 100644 index 0000000..3aff9cd Binary files /dev/null and b/addons/terrain_3d/brushes/square1.exr differ diff --git a/addons/terrain_3d/brushes/square2.exr b/addons/terrain_3d/brushes/square2.exr new file mode 100644 index 0000000..230113c Binary files /dev/null and b/addons/terrain_3d/brushes/square2.exr differ diff --git a/addons/terrain_3d/brushes/square3.exr b/addons/terrain_3d/brushes/square3.exr new file mode 100644 index 0000000..6da88b8 Binary files /dev/null and b/addons/terrain_3d/brushes/square3.exr differ diff --git a/addons/terrain_3d/brushes/square4.exr b/addons/terrain_3d/brushes/square4.exr new file mode 100644 index 0000000..350cd7d Binary files /dev/null and b/addons/terrain_3d/brushes/square4.exr differ diff --git a/addons/terrain_3d/brushes/square5.exr b/addons/terrain_3d/brushes/square5.exr new file mode 100644 index 0000000..f0832e0 Binary files /dev/null and b/addons/terrain_3d/brushes/square5.exr differ diff --git a/addons/terrain_3d/brushes/stones.exr b/addons/terrain_3d/brushes/stones.exr new file mode 100644 index 0000000..7ef5977 Binary files /dev/null and b/addons/terrain_3d/brushes/stones.exr differ diff --git a/addons/terrain_3d/brushes/terrain1.exr b/addons/terrain_3d/brushes/terrain1.exr new file mode 100644 index 0000000..8366b52 Binary files /dev/null and b/addons/terrain_3d/brushes/terrain1.exr differ diff --git a/addons/terrain_3d/brushes/terrain2.exr b/addons/terrain_3d/brushes/terrain2.exr new file mode 100644 index 0000000..d11a069 Binary files /dev/null and b/addons/terrain_3d/brushes/terrain2.exr differ diff --git a/addons/terrain_3d/brushes/terrain3.exr b/addons/terrain_3d/brushes/terrain3.exr new file mode 100644 index 0000000..61bfe0f Binary files /dev/null and b/addons/terrain_3d/brushes/terrain3.exr differ diff --git a/addons/terrain_3d/brushes/terrain4.exr b/addons/terrain_3d/brushes/terrain4.exr new file mode 100644 index 0000000..e8f4ce4 Binary files /dev/null and b/addons/terrain_3d/brushes/terrain4.exr differ diff --git a/addons/terrain_3d/brushes/terrain5.exr b/addons/terrain_3d/brushes/terrain5.exr new file mode 100644 index 0000000..ad3fe5b Binary files /dev/null and b/addons/terrain_3d/brushes/terrain5.exr differ diff --git a/addons/terrain_3d/brushes/terrain6.exr b/addons/terrain_3d/brushes/terrain6.exr new file mode 100644 index 0000000..0a15419 Binary files /dev/null and b/addons/terrain_3d/brushes/terrain6.exr differ diff --git a/addons/terrain_3d/brushes/texture1.exr b/addons/terrain_3d/brushes/texture1.exr new file mode 100644 index 0000000..f456b77 Binary files /dev/null and b/addons/terrain_3d/brushes/texture1.exr differ diff --git a/addons/terrain_3d/brushes/texture2.exr b/addons/terrain_3d/brushes/texture2.exr new file mode 100644 index 0000000..2624d3b Binary files /dev/null and b/addons/terrain_3d/brushes/texture2.exr differ diff --git a/addons/terrain_3d/brushes/texture3.exr b/addons/terrain_3d/brushes/texture3.exr new file mode 100644 index 0000000..690fe5e Binary files /dev/null and b/addons/terrain_3d/brushes/texture3.exr differ diff --git a/addons/terrain_3d/brushes/texture4.exr b/addons/terrain_3d/brushes/texture4.exr new file mode 100644 index 0000000..a2d96aa Binary files /dev/null and b/addons/terrain_3d/brushes/texture4.exr differ diff --git a/addons/terrain_3d/brushes/texture5.exr b/addons/terrain_3d/brushes/texture5.exr new file mode 100644 index 0000000..62aad60 Binary files /dev/null and b/addons/terrain_3d/brushes/texture5.exr differ diff --git a/addons/terrain_3d/brushes/vegetation1.exr b/addons/terrain_3d/brushes/vegetation1.exr new file mode 100644 index 0000000..d65bc6e Binary files /dev/null and b/addons/terrain_3d/brushes/vegetation1.exr differ diff --git a/addons/terrain_3d/extras/3rd_party/import_sgt.gd b/addons/terrain_3d/extras/3rd_party/import_sgt.gd new file mode 100644 index 0000000..44bb685 --- /dev/null +++ b/addons/terrain_3d/extras/3rd_party/import_sgt.gd @@ -0,0 +1,42 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Import From SimpleGrassTextured +# +# This script demonstrates how to import transforms from SimpleGrassTextured. To use it: +# +# 1. Setup the mesh asset you wish to use in the asset dock. +# 1. Select your Terrain3D node. +# 1. In the inspector, click Script (very bottom) and Quick Load import_sgt.gd. +# 1. At the very top, assign your SimpleGrassTextured node. +# 1. Input the desired mesh asset ID. +# 1. Click import. The output window and console will report when finished. +# 1. Clear the script from your Terrain3D node, and save your scene. +# +# The instance transforms are now stored in your region files. +# +# Use clear_instances to erase all instances that match the assign_mesh_id. +# +# The add_transforms function (called by add_multimesh) applies the height_offset specified in the +# Terrain3DMeshAsset. +# Once the transforms are imported, you can reassign any mesh you like into this mesh slot. + +@tool +extends Terrain3D + +@export var simple_grass_textured: MultiMeshInstance3D +@export var assign_mesh_id: int +@export var import: bool = false : set = import_sgt +@export var clear_instances: bool = false : set = clear_multimeshes + + +func clear_multimeshes(value: bool) -> void: + get_instancer().clear_by_mesh(assign_mesh_id) + + +func import_sgt(value: bool) -> void: + var sgt_mm: MultiMesh = simple_grass_textured.multimesh + var global_xform: Transform3D = simple_grass_textured.global_transform + print("Starting to import %d instances from SimpleGrassTextured using mesh id %d" % [ sgt_mm.instance_count, assign_mesh_id]) + var time: int = Time.get_ticks_msec() + get_instancer().add_multimesh(assign_mesh_id, sgt_mm, simple_grass_textured.global_transform) + print("Import complete in %.2f seconds" % [ float(Time.get_ticks_msec() - time)/1000. ]) + diff --git a/addons/terrain_3d/extras/3rd_party/import_sgt.gd.uid b/addons/terrain_3d/extras/3rd_party/import_sgt.gd.uid new file mode 100644 index 0000000..00b3868 --- /dev/null +++ b/addons/terrain_3d/extras/3rd_party/import_sgt.gd.uid @@ -0,0 +1 @@ +uid://bllcuwetve45k diff --git a/addons/terrain_3d/extras/3rd_party/project_on_terrain3d.gd b/addons/terrain_3d/extras/3rd_party/project_on_terrain3d.gd new file mode 100644 index 0000000..860014e --- /dev/null +++ b/addons/terrain_3d/extras/3rd_party/project_on_terrain3d.gd @@ -0,0 +1,137 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# This script is an addon for HungryProton's Scatter https://github.com/HungryProton/scatter +# It provides a `Project on Terrain3D` modifier, which allows Scatter +# to detect the terrain height from Terrain3D without using collision. +# +# Copy this file into /addons/proton_scatter/src/modifiers +# Then uncomment everything below (select, press CTRL+K) +# In the editor, add this modifier to Scatter, then set your Terrain3D node + +#@tool +#extends "base_modifier.gd" +# +# +#signal projection_completed +# +# +#@export var terrain_node : NodePath +#@export var align_with_collision_normal : bool = false +#@export_range(0.0, 90.0, 0.1) var max_slope : float = 90.0 +#@export var enable_texture_filtering : bool = false +#@export_range(0, 31) var target_texture_id : int = 0 +#@export var not_target_texture : bool = false +#@export_range(0.0, 1.0, 0.01) var texture_threshold : float = 0.8 +# +#var _terrain: Terrain3D +# +# +#func _init() -> void: + #display_name = "Project On Terrain3D" + #category = "Edit" + #can_restrict_height = false + #global_reference_frame_available = true + #local_reference_frame_available = true + #individual_instances_reference_frame_available = true + #use_global_space_by_default() +# + #documentation.add_paragraph( + #"This is a modified version of `Project on Colliders` that queries Terrain3D + #for heights without using collision. It constrains placement by slope or texture. +# + #This modifier must have terrain_node set to a Terrain3D node.") +# + #var p := documentation.add_parameter("Terrain Node") + #p.set_type("NodePath") + #p.set_description("Set your Terrain3D node.") + # + #p = documentation.add_parameter("Align with collision normal") + #p.set_type("bool") + #p.set_description( + #"Rotate the transform to align it with the collision normal in case + #the ray cast hit a collider.") + # + #p = documentation.add_parameter("Enable Texture Filtering") + #p.set_type("bool") + #p.set_description( + #"If enabled, objects will only be placed based on the ground texture specified.") + # + #p = documentation.add_parameter("Target Texture ID") + #p.set_type("int") + #p.set_description( + #"The ID of the texture to place objects on (0-31). Objects will only be placed on this texture.") + # + #p = documentation.add_parameter("Not Target Texture") + #p.set_type("bool") + #p.set_description( + #"If true, objects will be placed on all textures EXCEPT the target texture.") + # + #p = documentation.add_parameter("Texture Threshold") + #p.set_type("float") + #p.set_description("The blend value required for placement on the texture.") +# +# +#func _process_transforms(transforms, domain, _seed) -> void: + #if transforms.is_empty(): + #return +# + #if terrain_node: + #_terrain = domain.get_root().get_node_or_null(terrain_node) +# + #if not _terrain: + #warning += """No Terrain3D node found""" + #return +# + #if not _terrain.data: + #warning += """Terrain3DData is not initialized""" + #return +# + ## Review transforms + #var gt: Transform3D = domain.get_global_transform() + #var gt_inverse := gt.affine_inverse() + #var new_transforms_array: Array[Transform3D] = [] + #var remapped_max_slope: float = remap(max_slope, 0.0, 90.0, 0.0, 1.0) + #for i in transforms.list.size(): + #var t: Transform3D = transforms.list[i] + # + #var location: Vector3 = (gt * t).origin + #var height: float = _terrain.data.get_height(location) + #if is_nan(height): + #continue + # + #var normal: Vector3 = _terrain.data.get_normal(location) + #if not abs(Vector3.UP.dot(normal)) >= (1.0 - remapped_max_slope): + #continue + # + #if enable_texture_filtering: + #var texture_info: Vector3 = _terrain.data.get_texture_id(location) + #var base_id: int = int(texture_info.x) + #var overlay_id: int = int(texture_info.y) + #var blend_value: float = texture_info.z + ## Skip if overlay or blend != target texture, unless inverted + #if ((overlay_id != target_texture_id or blend_value < texture_threshold) and \ + #(base_id != target_texture_id or blend_value >= texture_threshold)) != not_target_texture: + #continue +# + #if align_with_collision_normal and not is_nan(normal.x): + #t.basis.y = normal + #t.basis.x = -t.basis.z.cross(normal) + #t.basis = t.basis.orthonormalized() +# + #t.origin.y = height - gt.origin.y + #new_transforms_array.push_back(t) +# + #transforms.list.clear() + #transforms.list.append_array(new_transforms_array) +# + #if transforms.is_empty(): + #warning += """All transforms have been removed. Possible reasons include: \n""" + #if enable_texture_filtering: + #warning += """+ No matching texture found at any position. + #+ Texture threshold may be too high. + #""" + #warning += """+ No collider is close enough to the shapes. + #+ Ray length is too short. + #+ Ray direction is incorrect. + #+ Collision mask is not set properly. + #+ Max slope is too low. + #""" diff --git a/addons/terrain_3d/extras/3rd_party/project_on_terrain3d.gd.uid b/addons/terrain_3d/extras/3rd_party/project_on_terrain3d.gd.uid new file mode 100644 index 0000000..6911309 --- /dev/null +++ b/addons/terrain_3d/extras/3rd_party/project_on_terrain3d.gd.uid @@ -0,0 +1 @@ +uid://g3opjh3m3iww diff --git a/addons/terrain_3d/extras/particle_example/Terrain3DParticles.tscn b/addons/terrain_3d/extras/particle_example/Terrain3DParticles.tscn new file mode 100644 index 0000000..0b5e615 --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/Terrain3DParticles.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=5 format=3 uid="uid://d3sr0a7dxfkr8"] + +[ext_resource type="Script" uid="uid://bp7r4ppgq1m0g" path="res://addons/terrain_3d/extras/particle_example/terrain_3D_particles.gd" id="1_gl3qg"] +[ext_resource type="Material" uid="uid://el5y10hnh13g" path="res://addons/terrain_3d/extras/particle_example/process_material.tres" id="2_2gon1"] +[ext_resource type="Material" uid="uid://ljo1wt61kbkq" path="res://addons/terrain_3d/extras/particle_example/grass_material.tres" id="3_qyjnw"] + +[sub_resource type="RibbonTrailMesh" id="RibbonTrailMesh_fwrtk"] +shape = 0 +section_length = 0.18 +section_segments = 1 + +[node name="Terrain3DParticles" type="Node3D"] +script = ExtResource("1_gl3qg") +instance_spacing = 0.25 +cell_width = 24.0 +grid_width = 5 +rows = 96 +amount = 9216 +process_material = ExtResource("2_2gon1") +mesh = SubResource("RibbonTrailMesh_fwrtk") +shadow_mode = 0 +mesh_material_override = ExtResource("3_qyjnw") +min_draw_distance = 60.0 +particle_count = 230400 +metadata/_edit_lock_ = true diff --git a/addons/terrain_3d/extras/particle_example/grass.gdshader b/addons/terrain_3d/extras/particle_example/grass.gdshader new file mode 100644 index 0000000..a149fd6 --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/grass.gdshader @@ -0,0 +1,69 @@ +// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. + +shader_type spatial; + +render_mode skip_vertex_transform, cull_disabled, blend_mix; + +uniform vec2 wind_direction = vec2(1.0, 1.0); + +varying vec4 data; + +// A lot of hard coded things here atm. +void vertex() { + // Wind effect from model data, in this case no vertex colors, + // so just use vertex Y component, including mesh offset + data[2] = (VERTEX.y + 0.55); + data[2] *= data[2]; // make non-linear + + // Ribbon used as a grass mesh.. so pinch the top. + VERTEX.xz *= (1.0 - data[2]); + + // Brighten tips + COLOR = mix(COLOR, vec4(1.0), smoothstep(0.9, 1.0, data[2])); + // Darken base, skip is scale is less than threshold, as this means "grow in" is occuring. + COLOR *= INSTANCE_CUSTOM[3] < 0.35 ? 1. : mix(1.0, 0.75, smoothstep(0.35, 0.0, data[2])); + // Save red/green shift for fragment + data.rg = INSTANCE_CUSTOM.rg; + + // World space vertex + vec3 w_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; + // Get wind force and scale from process() + float scale = pow(INSTANCE_CUSTOM[3] * INSTANCE_CUSTOM[3], 0.707); + float force = INSTANCE_CUSTOM[2] * data[2] * scale; + // Add some cheap jitter at high wind values + force -= fract(force * 256.0) * force * 0.05; + // Curve the result + force = pow(force, 0.707); + + // These 2 combined result in a decent bend without resorting to matrices or pivot data. + // Lateral move and wobble + float lateral_wobble = sin(TIME * 2.0 * (1.0 + data.r + data.g)) * 0.25 * (1.0 - INSTANCE_CUSTOM[2]); + vec2 direction = normalize(wind_direction); + w_vertex.xz -= (vec2(-direction.y, direction.x) * lateral_wobble + direction) * force; + // Flatten + w_vertex.y -= INSTANCE_CUSTOM[2] * force * data[2]; + + // Save final wind force value for fragment. + data[3] = force; + + VERTEX = (VIEW_MATRIX * vec4(w_vertex, 1.0)).xyz; + NORMAL = MODELVIEW_NORMAL_MATRIX * NORMAL; + BINORMAL = MODELVIEW_NORMAL_MATRIX * BINORMAL; + TANGENT = MODELVIEW_NORMAL_MATRIX * TANGENT; +} + +void fragment() { + // Hard coded color. + ALBEDO = vec3(0.20, 0.22, 0.05) * (data[2] * 0.5 + 0.5); + ALBEDO.rg *= (data.rg * 0.3 + 0.9); + ALBEDO *= pow(COLOR.rgb, vec3(2.2)); + // Modify roughness / specular based on wind force for added detail + float spec_rough = clamp(max(data[2], data[3]), 0., 1.); + ROUGHNESS = 1. - spec_rough; + SPECULAR = clamp(spec_rough * 0.25, 0., .15); + + BACKLIGHT = vec3(0.33); + #if CURRENT_RENDERER == RENDERER_COMPATIBILITY + ALBEDO = pow(ALBEDO, vec3(0.4)); + #endif +} diff --git a/addons/terrain_3d/extras/particle_example/grass.gdshader.uid b/addons/terrain_3d/extras/particle_example/grass.gdshader.uid new file mode 100644 index 0000000..94b0237 --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/grass.gdshader.uid @@ -0,0 +1 @@ +uid://dq3lfyp3u5oxt diff --git a/addons/terrain_3d/extras/particle_example/grass_material.tres b/addons/terrain_3d/extras/particle_example/grass_material.tres new file mode 100644 index 0000000..2fd2fe8 --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/grass_material.tres @@ -0,0 +1,8 @@ +[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://ljo1wt61kbkq"] + +[ext_resource type="Shader" uid="uid://dq3lfyp3u5oxt" path="res://addons/terrain_3d/extras/particle_example/grass.gdshader" id="1_nkru0"] + +[resource] +render_priority = 0 +shader = ExtResource("1_nkru0") +shader_parameter/wind_direction = Vector2(1, 1) diff --git a/addons/terrain_3d/extras/particle_example/particles.gdshader b/addons/terrain_3d/extras/particle_example/particles.gdshader new file mode 100644 index 0000000..300198c --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/particles.gdshader @@ -0,0 +1,275 @@ +// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. + +// This is an example particle shader designed to procedurally place +// particles like grass, small rocks, and other ground effects, on the terrain +// surface by reading the Terrain3D data maps. It works in tandem with the +// provided GDScript. + +shader_type particles; +render_mode disable_velocity, disable_force; + +group_uniforms options; +uniform sampler2D main_noise; +uniform float main_noise_scale = 0.01; +uniform vec3 position_offset = vec3(0.); +uniform bool align_to_normal = true; +uniform float normal_strength : hint_range(0.01, 1.0, 0.01) = 0.3; +uniform bool random_rotation = true; +uniform float random_spacing : hint_range(0.0, 1.0, 0.01) = 0.5; +uniform vec3 min_scale = vec3(1.0); +uniform vec3 max_scale = vec3(1.0); + +group_uniforms wind; +uniform float noise_scale = 0.0041; +uniform float wind_speed = 0.025; +uniform float wind_strength : hint_range(0.0, 1.0, 0.01) = 1.0; +uniform float wind_dithering = 4.0; +uniform vec2 wind_direction = vec2(1.0,1.0); + +group_uniforms shapeing; +uniform float clod_scale_boost = 3.0; +uniform float clod_min_threshold : hint_range(0.0, 1.0, 0.001) = 0.2; +uniform float clod_max_threshold : hint_range(0.0, 1.0, 0.001) = 0.5; +uniform float patch_min_threshold : hint_range(0.0, 1.0, 0.001) = 0.025; +uniform float patch_max_threshold : hint_range(0.0, 1.0, 0.001) = 0.2; + +group_uniforms filtering; +uniform float condition_dither_range : hint_range(0.0, 1.0, 0.01) = 0.15; +uniform float surface_slope_min : hint_range(0.0, 1.0, 0.01) = 0.87; +uniform float distance_fade_ammount : hint_range(0.0, 1.0, 0.01) = 0.5; + +group_uniforms private; +uniform float max_dist = 1.; +uniform vec3 camera_position = vec3(0.); +uniform uint instance_rows = 1; +uniform float instance_spacing = 0.5; +uniform uint _background_mode = 0u; +uniform float _vertex_spacing = 1.0; +uniform float _vertex_density = 1.0; // = 1/_vertex_spacing +uniform float _region_size = 1024.0; +uniform float _region_texel_size = 0.0009765625; // = 1/REGION_SIZE +uniform int _region_map_size = 32; +uniform int _region_map[1024]; +uniform vec2 _region_locations[1024]; +uniform highp sampler2DArray _height_maps : repeat_disable; +uniform highp sampler2DArray _control_maps : repeat_disable; +uniform highp sampler2DArray _color_maps : repeat_disable; + +// Defined Constants +#define SKIP_PASS 0 +#define VERTEX_PASS 1 +#define FRAGMENT_PASS 2 + +// Takes in world space XZ (UV) coordinates & search depth (only applicable for background mode none) +// Returns ivec3 with: +// XY: (0 to _region_size - 1) coordinates within a region +// Z: layer index used for texturearrays, -1 if not in a region +ivec3 get_index_coord(const vec2 uv, const int search) { + vec2 r_uv = round(uv); + vec2 o_uv = mod(r_uv,_region_size); + ivec2 pos; + int bounds, layer_index = -1; + for (int i = -1; i < 0; i++) { + if ((layer_index == -1 && _background_mode == 0u) || i < 0) { + r_uv -= i == -1 ? vec2(0.0) : vec2(float(o_uv.x <= o_uv.y), float(o_uv.y <= o_uv.x)); + pos = ivec2(floor((r_uv) * _region_texel_size)) + (_region_map_size / 2); + bounds = int(uint(pos.x | pos.y) < uint(_region_map_size)); + layer_index = (_region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1); + } + } + return ivec3(ivec2(mod(r_uv,_region_size)), layer_index); +} + +#if CURRENT_RENDERER == RENDERER_COMPATIBILITY + #define fma(a, b, c) ((a) * (b) + (c)) +#endif +float random(vec2 v) { + return fract(1e4 * sin(fma(17.0, v.x, v.y * 0.1)) * (0.1 + abs(sin(fma(v.y, 13.0, v.x))))); +} + +mat3 rotation_matrix(vec3 axis, float angle) { + float c = cos(angle); + float s = sin(angle); + float t = 1.0 - c; + vec3 n = normalize(axis); + float x = n.x; + float y = n.y; + float z = n.z; + + return mat3( + vec3(t * x * x + c, t * x * y - z * s, t * x * z + y * s), + vec3(t * x * y + z * s, t * y * y + c, t * y * z - x * s), + vec3(t * x * z - y * s, t * y * z + x * s, t * z * z + c)); +} + +mat3 align_to_vector(vec3 normal) { + vec3 up = vec3(0.0, 1.0, 0.0); + if (abs(dot(normal, up)) > 0.9999) { // Avoid singularity + up = vec3(1.0, 0.0, 0.0); + } + vec3 tangent = normalize(cross(up, normal)); + vec3 bitangent = normalize(cross(tangent, normal)); + return mat3(tangent, normal, bitangent); +} + +void start() { + // Create centered a grid + vec3 pos = vec3(float(INDEX % instance_rows), 0.0, float(INDEX / instance_rows)) - float(instance_rows >> 1u); + + // Apply spcaing + pos *= instance_spacing; + // Move the grid to the emitter, snapping is handled CPU side + pos.xz += EMISSION_TRANSFORM[3].xz; + + // Create random values per-instance, incorporating the seed, mask bits to avoid NAN/INF + float seed = fract(uintBitsToFloat(RANDOM_SEED & 0x7EFFFFFFu)); + vec3 r = fract(vec3(random(pos.xz), random(pos.xz + vec2(0.5)), random(pos.xz - vec2(0.5))) + seed); + // Randomize instance spacing + pos.x += ((r.x * 2.0) - 1.0) * random_spacing * instance_spacing; + pos.z += ((r.z * 2.0) - 1.0) * random_spacing * instance_spacing; + + // Lookup offsets, ID and blend weight + const vec3 offsets = vec3(0, 1, 2); + vec2 index_id = floor(pos.xz * _vertex_density); + vec2 weight = fract(pos.xz * _vertex_density); + vec2 invert = 1.0 - weight; + vec4 weights = vec4( + invert.x * weight.y, // 0 + weight.x * weight.y, // 1 + weight.x * invert.y, // 2 + invert.x * invert.y // 3 + ); + + ivec3 index[4]; + // Map lookups + index[0] = get_index_coord(index_id + offsets.xy, VERTEX_PASS); + index[1] = get_index_coord(index_id + offsets.yy, VERTEX_PASS); + index[2] = get_index_coord(index_id + offsets.yx, VERTEX_PASS); + index[3] = get_index_coord(index_id + offsets.xx, VERTEX_PASS); + + highp float h[8]; + h[0] = texelFetch(_height_maps, index[0], 0).r; // 0 (0,1) + h[1] = texelFetch(_height_maps, index[1], 0).r; // 1 (1,1) + h[2] = texelFetch(_height_maps, index[2], 0).r; // 2 (1,0) + h[3] = texelFetch(_height_maps, index[3], 0).r; // 3 (0,0) + h[4] = texelFetch(_height_maps, get_index_coord(index_id + offsets.yz, VERTEX_PASS), 0).r; // 4 (1,2) + h[5] = texelFetch(_height_maps, get_index_coord(index_id + offsets.zy, VERTEX_PASS), 0).r; // 5 (2,1) + h[6] = texelFetch(_height_maps, get_index_coord(index_id + offsets.zx, VERTEX_PASS), 0).r; // 6 (2,0) + h[7] = texelFetch(_height_maps, get_index_coord(index_id + offsets.xz, VERTEX_PASS), 0).r; // 7 (0,2) + vec3 index_normal[4]; + index_normal[0] = vec3(h[0] - h[1], _vertex_spacing, h[0] - h[7]); + index_normal[1] = vec3(h[1] - h[5], _vertex_spacing, h[1] - h[4]); + index_normal[2] = vec3(h[2] - h[6], _vertex_spacing, h[2] - h[1]); + index_normal[3] = vec3(h[3] - h[2], _vertex_spacing, h[3] - h[0]); + vec3 w_normal = normalize( + index_normal[0] * weights[0] + + index_normal[1] * weights[1] + + index_normal[2] * weights[2] + + index_normal[3] * weights[3]); + + // Set the height according to the heightmap data + pos.y = + h[0] * weights[0] + + h[1] * weights[1] + + h[2] * weights[2] + + h[3] * weights[3] ; + + // Offset, Rotation, Alignment. + TRANSFORM = mat4(1.0); + vec3 orientation = vec3(0., 1., 0.); + + vec2 uv = (pos.xz) * main_noise_scale; + float noise = textureLod(main_noise, uv, 0.0).r; + float clods = smoothstep(clod_min_threshold, clod_max_threshold, noise) * clod_scale_boost; + float patch = smoothstep(patch_min_threshold, patch_max_threshold, noise); + float width_modifier = 1.0 + 3.0 * smoothstep(0., max_dist, length(camera_position - pos)); + + // Calculate scale + vec3 scale = vec3( + mix(min_scale.x, max_scale.x, r.x) * width_modifier, + mix(min_scale.y, max_scale.y, r.y) + clods, + mix(min_scale.z, max_scale.z, r.z) * width_modifier) * patch; + + // Apply scale to offset + vec3 offset = position_offset * scale; + + // Apply normal orientation + if (align_to_normal) { + orientation = mix(orientation, w_normal, normal_strength); + mat3 alignment = align_to_vector(orientation); + offset = alignment * offset; + TRANSFORM = mat4(alignment); + } + + // Apply rotation around orientation + if (random_rotation) { + mat3 rotation = rotation_matrix(orientation, r.x * TAU); + TRANSFORM = mat4(rotation) * TRANSFORM; + } + + // Filtering - Causes some particles to be rendered as degenerate triangles + // via 0./0. - Particles filtered this way are still processed by the GPU. + // For compatibility it seems we must shift as well. + // Surface slope filtering + if (surface_slope_min > w_normal.y + (r.y - 0.5) * condition_dither_range) { + pos.y = 0. / 0.; + pos.xz = vec2(100000.0); + } + + // Read color map + highp vec4 c[4]; + #define COLOR_MAP vec4(1., 1., 1., 0.5) + c[0] = index[0].z >= 0 ? texelFetch(_color_maps, index[0], 0) : COLOR_MAP; // 0 (0,1) + c[1] = index[1].z >= 0 ? texelFetch(_color_maps, index[1], 0) : COLOR_MAP; // 1 (1,1) + c[2] = index[2].z >= 0 ? texelFetch(_color_maps, index[2], 0) : COLOR_MAP; // 2 (1,0) + c[3] = index[3].z >= 0 ? texelFetch(_color_maps, index[3], 0) : COLOR_MAP; // 3 (0,0) + vec4 color_map = + c[0] * weights[0] + + c[1] * weights[1] + + c[2] * weights[2] + + c[3] * weights[3] ; + + COLOR = color_map; + + // Read control map + uint control = floatBitsToUint(texelFetch(_control_maps, index[3], 0).r); + bool auto = bool(control & 0x1u); + int base = int(control >>27u & 0x1Fu); + int over = int(control >> 22u & 0x1Fu); + float blend = float(control >> 14u & 0xFFu) * 0.003921568627450; // 1. / 255. + + // Hardcoded example, hand painted texture id 0 is filtered out. + if (!auto && ((base == 0 && blend < 0.7) || (over == 0 && blend >= 0.3))) { + pos.y = 0. / 0.; + pos.xz = vec2(100000.0); + } + + if (length(camera_position - pos) > max_dist) { + pos.y = 0. / 0.; + pos.xz = vec2(100000.0); + } else { + float fade_factor = 1.0 - smoothstep(max_dist * distance_fade_ammount, max_dist + 0.0001, length(camera_position - pos)) + 0.001; + scale.y *= fade_factor; + offset *= fade_factor; + } + + // Apply scale + TRANSFORM[0] *= scale.x; + TRANSFORM[1] *= scale.y; + TRANSFORM[2] *= scale.z; + + // Apply the position + TRANSFORM[3].xyz = pos.xyz + offset; + + // Save Fixed 2 Random values for Reg/Green color randomness + CUSTOM.rg = r.rg; + // Save Y component scale pre-rotation + CUSTOM[3] = scale.y; +} + +void process() { + // Extract world space UV from Transform Matrix + vec2 uv = (TRANSFORM[3].xz + CUSTOM.rg * wind_dithering) * noise_scale; + // Scaled wind noise, updated per instance, at process FPS. Passed to Vertex() + CUSTOM[2] = textureLod(main_noise, uv + TIME * wind_speed * normalize(wind_direction), 0.0).r * wind_strength; +} diff --git a/addons/terrain_3d/extras/particle_example/particles.gdshader.uid b/addons/terrain_3d/extras/particle_example/particles.gdshader.uid new file mode 100644 index 0000000..595a815 --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/particles.gdshader.uid @@ -0,0 +1 @@ +uid://dce675i014xcn diff --git a/addons/terrain_3d/extras/particle_example/process_material.tres b/addons/terrain_3d/extras/particle_example/process_material.tres new file mode 100644 index 0000000..ad7e259 --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/process_material.tres @@ -0,0 +1,49 @@ +[gd_resource type="ShaderMaterial" load_steps=4 format=3 uid="uid://el5y10hnh13g"] + +[ext_resource type="Shader" uid="uid://dce675i014xcn" path="res://addons/terrain_3d/extras/particle_example/particles.gdshader" id="1_t55me"] + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_544iv"] +noise_type = 2 +frequency = 0.0145 +cellular_return_type = 4 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_544iv"] +seamless = true +noise = SubResource("FastNoiseLite_544iv") + +[resource] +shader = ExtResource("1_t55me") +shader_parameter/main_noise = SubResource("NoiseTexture2D_544iv") +shader_parameter/main_noise_scale = 0.01 +shader_parameter/position_offset = Vector3(0, 0.45, 0) +shader_parameter/align_to_normal = true +shader_parameter/normal_strength = 0.3 +shader_parameter/random_rotation = true +shader_parameter/random_spacing = 0.5 +shader_parameter/min_scale = Vector3(0.125, 0.5, 0.125) +shader_parameter/max_scale = Vector3(0.125, 1, 0.125) +shader_parameter/noise_scale = 0.0041 +shader_parameter/wind_speed = 0.025 +shader_parameter/wind_strength = 1.0 +shader_parameter/wind_dithering = 4.0 +shader_parameter/wind_direction = Vector2(1, 1) +shader_parameter/clod_scale_boost = 2.0 +shader_parameter/clod_min_threshold = 0.2 +shader_parameter/clod_max_threshold = 0.8 +shader_parameter/patch_min_threshold = 0.025 +shader_parameter/patch_max_threshold = 0.2 +shader_parameter/condition_dither_range = 0.15 +shader_parameter/surface_slope_min = 0.87 +shader_parameter/distance_fade_ammount = 0.66 +shader_parameter/max_dist = 1.0 +shader_parameter/camera_position = Vector3(0, 0, 0) +shader_parameter/instance_rows = 1 +shader_parameter/instance_spacing = 0.5 +shader_parameter/_background_mode = 0 +shader_parameter/_vertex_spacing = 1.0 +shader_parameter/_vertex_density = 1.0 +shader_parameter/_region_size = 1024.0 +shader_parameter/_region_texel_size = 0.000976563 +shader_parameter/_region_map_size = 32 +shader_parameter/_region_map = PackedInt32Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +shader_parameter/_region_locations = PackedVector2Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) diff --git a/addons/terrain_3d/extras/particle_example/terrain_3D_particles.gd b/addons/terrain_3d/extras/particle_example/terrain_3D_particles.gd new file mode 100644 index 0000000..46f7572 --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/terrain_3D_particles.gd @@ -0,0 +1,237 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# +# This is an example of using a particle shader with Terrain3D. +# To use it, add `Terrain3DParticles.tscn` to your scene and assign the terrain. +# Then customize the settings, materials and shader to extend it and make it your own. + +@tool +extends Node3D + + +#region settings +## Auto set if attached as a child of a Terrain3D node +@export var terrain: Terrain3D: + set(value): + terrain = value + _create_grid() + + +## Distance between instances +@export_range(0.125, 2.0, 0.015625) var instance_spacing: float = 0.5: + set(value): + instance_spacing = clamp(round(value * 64.0) * 0.015625, 0.125, 2.0) + rows = maxi(int(cell_width / instance_spacing), 1) + amount = rows * rows + _set_offsets() + + +## Width of an individual cell of the grid +@export_range(8.0, 256.0, 1.0) var cell_width: float = 32.0: + set(value): + cell_width = clamp(value, 8.0, 256.0) + rows = maxi(int(cell_width / instance_spacing), 1) + amount = rows * rows + min_draw_distance = 1.0 + # Have to update aabb + if terrain and terrain.data: + var height_range: Vector2 = terrain.data.get_height_range() + var height: float = height_range[0] - height_range[1] + var aabb: AABB = AABB() + aabb.size = Vector3(cell_width, height, cell_width) + aabb.position = aabb.size * -0.5 + aabb.position.y = height_range[1] + for p in particle_nodes: + p.custom_aabb = aabb + _set_offsets() + + +## Grid width. Must be odd. +## Higher values cull slightly better, draw further out. +@export_range(1, 15, 2) var grid_width: int = 9: + set(value): + grid_width = value + particle_count = 1 + min_draw_distance = 1.0 + _create_grid() + + +@export_storage var rows: int = 1 + +@export_storage var amount: int = 1: + set(value): + amount = value + particle_count = value + last_pos = Vector3.ZERO + for p in particle_nodes: + p.amount = amount + + +@export_range(1, 256, 1) var process_fixed_fps: int = 30: + set(value): + process_fixed_fps = maxi(value, 1) + for p in particle_nodes: + p.fixed_fps = process_fixed_fps + p.preprocess = 1.0 / float(process_fixed_fps) + + +## Access to process material parameters +@export var process_material: ShaderMaterial + +## The mesh that each particle will render +@export var mesh: Mesh + +@export var shadow_mode: GeometryInstance3D.ShadowCastingSetting = ( + GeometryInstance3D.ShadowCastingSetting.SHADOW_CASTING_SETTING_ON): + set(value): + shadow_mode = value + for p in particle_nodes: + p.cast_shadow = value + + +## Override material for the particle mesh +@export_custom( + PROPERTY_HINT_RESOURCE_TYPE, + "BaseMaterial3D,ShaderMaterial") var mesh_material_override: Material: + set(value): + mesh_material_override = value + for p in particle_nodes: + p.material_override = mesh_material_override + + +@export_group("Info") +## The minimum distance that particles will be drawn upto +## If using fade out effects like pixel alpha this is the limit to use. +@export var min_draw_distance: float = 1.0: + set(value): + min_draw_distance = float(cell_width * grid_width) * 0.5 + + +## Displays current total particle count based on Cell Width and Instance Spacing +@export var particle_count: int = 1: + set(value): + particle_count = amount * grid_width * grid_width + +#endregion + + +var offsets: Array[Vector3] +var last_pos: Vector3 = Vector3.ZERO +var particle_nodes: Array[GPUParticles3D] + + +func _ready() -> void: + if not terrain: + var parent: Node = get_parent() + if parent is Terrain3D: + terrain = parent + _create_grid() + + +func _notification(what: int) -> void: + if what == NOTIFICATION_PREDELETE: + _destroy_grid() + + +func _physics_process(delta: float) -> void: + if terrain: + var camera: Camera3D = terrain.get_camera() + if camera: + if last_pos.distance_squared_to(camera.global_position) > 1.0: + var pos: Vector3 = camera.global_position.snapped(Vector3.ONE) + _position_grid(pos) + RenderingServer.material_set_param(process_material.get_rid(), "camera_position", pos ) + last_pos = camera.global_position + _update_process_parameters() + else: + set_physics_process(false) + + +func _create_grid() -> void: + _destroy_grid() + if not terrain: + return + set_physics_process(true) + _set_offsets() + var hr: Vector2 = terrain.data.get_height_range() + var height: float = hr.x - hr.y + var aabb: AABB = AABB() + aabb.size = Vector3(cell_width, height, cell_width) + aabb.position = aabb.size * -0.5 + aabb.position.y = hr.y + var half_grid: int = grid_width / 2 + # Iterating the array like this allows identifying grid position, in case setting + # different mesh or materials is desired for LODs etc. + for x in range(-half_grid, half_grid + 1): + for z in range(-half_grid, half_grid + 1): + #var ring: int = maxi(maxi(absi(x), absi(z)), 0) + var particle_node = GPUParticles3D.new() + particle_node.lifetime = 600.0 + particle_node.amount = amount + particle_node.explosiveness = 1.0 + particle_node.amount_ratio = 1.0 + particle_node.process_material = process_material + particle_node.draw_pass_1 = mesh + particle_node.speed_scale = 1.0 + particle_node.custom_aabb = aabb + particle_node.cast_shadow = shadow_mode + particle_node.fixed_fps = process_fixed_fps + # This prevent minor grid alignment errors when the camera is moving very fast + particle_node.preprocess = 1.0 / float(process_fixed_fps) + if mesh_material_override: + particle_node.material_override = mesh_material_override + particle_node.use_fixed_seed = true + if (x > -half_grid and z > -half_grid): # Use the same seed across all nodes + particle_node.seed = particle_nodes[0].seed + self.add_child(particle_node) + particle_node.emitting = true + particle_nodes.push_back(particle_node) + last_pos = Vector3.ZERO + + +func _set_offsets() -> void: + var half_grid: int = grid_width / 2 + offsets.clear() + for x in range(-half_grid, half_grid + 1): + for z in range(-half_grid, half_grid + 1): + var offset := Vector3( + float(x * rows) * instance_spacing, + 0.0, + float(z * rows) * instance_spacing + ) + offsets.append(offset) + + +func _destroy_grid() -> void: + for node: GPUParticles3D in particle_nodes: + if is_instance_valid(node): + node.queue_free() + particle_nodes.clear() + + +func _position_grid(pos: Vector3) -> void: + for i in particle_nodes.size(): + var node: GPUParticles3D = particle_nodes[i] + var snap = Vector3(pos.x, 0, pos.z).snapped(Vector3.ONE) + offsets[i] + node.global_position = (snap / instance_spacing).round() * instance_spacing + node.reset_physics_interpolation() + node.restart(true) # keep the same seed. + + +func _update_process_parameters() -> void: + if process_material: + var process_rid: RID = process_material.get_rid() + if terrain and process_rid.is_valid(): + RenderingServer.material_set_param(process_rid, "_background_mode", terrain.material.world_background) + RenderingServer.material_set_param(process_rid, "_vertex_spacing", terrain.vertex_spacing) + RenderingServer.material_set_param(process_rid, "_vertex_density", 1.0 / terrain.vertex_spacing) + RenderingServer.material_set_param(process_rid, "_region_size", terrain.region_size) + RenderingServer.material_set_param(process_rid, "_region_texel_size", 1.0 / terrain.region_size) + RenderingServer.material_set_param(process_rid, "_region_map_size", 32) + RenderingServer.material_set_param(process_rid, "_region_map", terrain.data.get_region_map()) + RenderingServer.material_set_param(process_rid, "_region_locations", terrain.data.get_region_locations()) + RenderingServer.material_set_param(process_rid, "_height_maps", terrain.data.get_height_maps_rid()) + RenderingServer.material_set_param(process_rid, "_control_maps", terrain.data.get_control_maps_rid()) + RenderingServer.material_set_param(process_rid, "_color_maps", terrain.data.get_color_maps_rid()) + RenderingServer.material_set_param(process_rid, "instance_spacing", instance_spacing) + RenderingServer.material_set_param(process_rid, "instance_rows", rows) + RenderingServer.material_set_param(process_rid, "max_dist", min_draw_distance) diff --git a/addons/terrain_3d/extras/particle_example/terrain_3D_particles.gd.uid b/addons/terrain_3d/extras/particle_example/terrain_3D_particles.gd.uid new file mode 100644 index 0000000..b365859 --- /dev/null +++ b/addons/terrain_3d/extras/particle_example/terrain_3D_particles.gd.uid @@ -0,0 +1 @@ +uid://bp7r4ppgq1m0g diff --git a/addons/terrain_3d/extras/shaders/hex_grid.gdshaderinc b/addons/terrain_3d/extras/shaders/hex_grid.gdshaderinc new file mode 100644 index 0000000..2163989 --- /dev/null +++ b/addons/terrain_3d/extras/shaders/hex_grid.gdshaderinc @@ -0,0 +1,67 @@ +// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +// This shader snippet draws a hex grid + +// To use it, add this line to the top of your shader: +// #include "res://addons/terrain_3d/extras/shaders/hex_grid.gdshaderinc" + +// And this line at the bottom of your shader: +// draw_hex_grid(uv2, _region_texel_size, w_normal, ALBEDO); + +mat2 rotate2d(float _angle) { + return mat2(vec2(cos(_angle),-sin(_angle)), vec2(sin(_angle), cos(_angle))); +} + +void draw_hex_grid(vec2 uv, float texel_size, vec3 normal, inout vec3 albedo) { + float hex_size = 0.02; + float line_thickness = 0.04; + + vec2 guv = (uv - vec2(0.5 * texel_size)) / hex_size; + + // Convert UV to axial hex coordinates + float q = (sqrt(3.0) / 3.0 * guv.x - 1.0 / 3.0 * guv.y); + float r = (2.0 / 3.0 * guv.y); + + // Cube coordinates for the hex (q, r, -q-r) + float x = q; + float z = r; + float y = -x - z; + + // Round to the nearest hex center + vec3 rounded = round(vec3(x, y, z)); + vec3 diff = abs(vec3(x, y, z) - rounded); + + // Fix rounding errors + if (diff.x > diff.y && diff.x > diff.z) { + rounded.x = -rounded.y - rounded.z; + } else if (diff.y > diff.z) { + rounded.y = -rounded.x - rounded.z; + } else { + rounded.z = -rounded.x - rounded.y; + } + + // Find the hex center in UV space + vec2 hex_center = vec2( + sqrt(3.0) * rounded.x + sqrt(3.0) / 2.0 * rounded.z, + 3.0 / 2.0 * rounded.z + ); + + // Relative position within the hex + vec2 local_pos = guv - hex_center; + vec2 lines_uv = local_pos; + float line = 1.0; + + for (int i = 0; i < 6; i++) { + vec2 luv = lines_uv * rotate2d(radians(60.0 * float(i) + 30.0)); + float dist = abs(dot(luv + vec2(0.90), vec2(0.0, 1.0))); + line = min(line, dist); + } + + // Filter lines by slope + float slope = 4.; // Can also assign to (auto_slope * 4.) to match grass placement + float slope_factor = clamp(dot(vec3(0., 1., 0.), slope * (normal - 1.) + 1.), 0., 1.); + + // Draw hex grid + albedo = mix(albedo, vec3(1.0), smoothstep(line_thickness + 0.02, line_thickness, line) * slope_factor); + // Draw Hex center dot + albedo = mix(albedo, vec3(0.0, 0.5, 0.5), smoothstep(0.11, 0.10, length(local_pos)) * slope_factor); +} \ No newline at end of file diff --git a/addons/terrain_3d/extras/shaders/hex_grid.gdshaderinc.uid b/addons/terrain_3d/extras/shaders/hex_grid.gdshaderinc.uid new file mode 100644 index 0000000..feee7f6 --- /dev/null +++ b/addons/terrain_3d/extras/shaders/hex_grid.gdshaderinc.uid @@ -0,0 +1 @@ +uid://mri8pfoj2mfk diff --git a/addons/terrain_3d/extras/shaders/lightweight.gdshader b/addons/terrain_3d/extras/shaders/lightweight.gdshader new file mode 100644 index 0000000..7a4087c --- /dev/null +++ b/addons/terrain_3d/extras/shaders/lightweight.gdshader @@ -0,0 +1,367 @@ +shader_type spatial; +render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx,skip_vertex_transform; + +/* This is an example stripped down shader with maximum performance in mind. + * Only Autoshader/Base/Over/Blend/Holes/Colormap are supported. + * All terrain normal calculations take place in vetex(). + * + * Control map indices are processed such that each ID only requires reading ONCE. + * The following features: projection, detiling, and paintable rotation / scale + * cannot work with this method, without the additional samples required for blending + * between same ID textures with different values across indices. + */ + +// Defined Constants +#define SKIP_PASS 0 +#define VERTEX_PASS 1 +#define FRAGMENT_PASS 2 +#define COLOR_MAP vec4(1.0, 1.0, 1.0, 0.5) +#define DIV_255 0.003921568627450 // 1. / 255. + +// Inline Functions +#define DECODE_BLEND(control) float(control >> 14u & 0xFFu) * DIV_255 +#define DECODE_AUTO(control) bool(control & 0x1u) +#define DECODE_BASE(control) int(control >> 27u & 0x1Fu) +#define DECODE_OVER(control) int(control >> 22u & 0x1Fu) +#define DECODE_HOLE(control) bool(control >>2u & 0x1u) + +#if CURRENT_RENDERER == RENDERER_COMPATIBILITY + #define fma(a, b, c) ((a) * (b) + (c)) + #define dFdxCoarse(a) dFdx(a) + #define dFdyCoarse(a) dFdy(a) +#endif + +// Private uniforms +uniform vec3 _camera_pos = vec3(0.f); +uniform float _mesh_size = 48.f; +uniform uint _background_mode = 1u; // NONE = 0, FLAT = 1, NOISE = 2 +uniform uint _mouse_layer = 0x80000000u; // Layer 32 +uniform float _vertex_spacing = 1.0; +uniform float _vertex_density = 1.0; // = 1./_vertex_spacing +uniform float _region_size = 1024.0; +uniform float _region_texel_size = 0.0009765625; // = 1./region_size +uniform int _region_map_size = 32; +uniform int _region_map[1024]; +uniform vec2 _region_locations[1024]; +uniform float _texture_normal_depth_array[32]; +uniform float _texture_ao_strength_array[32]; +uniform float _texture_roughness_mod_array[32]; +uniform float _texture_uv_scale_array[32]; +uniform vec4 _texture_color_array[32]; +uniform highp sampler2DArray _height_maps : repeat_disable; +uniform highp sampler2DArray _control_maps : repeat_disable; +uniform highp sampler2DArray _color_maps : source_color, filter_linear_mipmap_anisotropic, repeat_disable; +uniform highp sampler2DArray _texture_array_albedo : source_color, filter_linear_mipmap_anisotropic, repeat_enable; +uniform highp sampler2DArray _texture_array_normal : hint_normal, filter_linear_mipmap_anisotropic, repeat_enable; + +// Public uniforms +uniform bool enable_texturing = true; +uniform float blend_sharpness : hint_range(0, 1) = 0.5; +uniform bool flat_terrain_normals = false; +// Autoshader +uniform float auto_slope : hint_range(0, 10) = 1.0; +uniform float auto_height_reduction : hint_range(0, 1) = 0.1; +uniform int auto_base_texture : hint_range(0, 31) = 0; +uniform int auto_overlay_texture : hint_range(0, 31) = 1; +// Macro Variation +uniform bool enable_macro_variation = true; +uniform vec3 macro_variation1 : source_color = vec3(1.); +uniform vec3 macro_variation2 : source_color = vec3(1.); +uniform float macro_variation_slope : hint_range(0., 1.) = 0.333; +uniform highp sampler2D noise_texture : source_color, filter_linear_mipmap_anisotropic, repeat_enable; +uniform float noise1_scale : hint_range(0.001, 1.) = 0.04; // Used for macro variation 1. Scaled up 10x +uniform float noise1_angle : hint_range(0, 6.283) = 0.; +uniform vec2 noise1_offset = vec2(0.5); +uniform float noise2_scale : hint_range(0.001, 1.) = 0.076; // Used for macro variation 2. Scaled up 10x + +// Varyings & Types +varying vec3 v_normal; +varying vec3 v_vertex; +varying mat3 TBN; + +//////////////////////// +// Vertex +//////////////////////// + +// Takes in world space XZ (UV) coordinates & search depth (only applicable for background mode none) +// Returns ivec3 with: +// XY: (0 to _region_size - 1) coordinates within a region +// Z: layer index used for texturearrays, -1 if not in a region +ivec3 get_index_coord(const vec2 uv, const int search) { + vec2 r_uv = round(uv); + vec2 o_uv = mod(r_uv,_region_size); + ivec2 pos; + int bounds, layer_index = -1; + for (int i = -1; i < clamp(search, SKIP_PASS, FRAGMENT_PASS); i++) { + if ((layer_index == -1 && _background_mode == 0u ) || i < 0) { + r_uv -= i == -1 ? vec2(0.0) : vec2(float(o_uv.x <= o_uv.y), float(o_uv.y <= o_uv.x)); + pos = ivec2(floor((r_uv) * _region_texel_size)) + (_region_map_size / 2); + bounds = int(uint(pos.x | pos.y) < uint(_region_map_size)); + layer_index = (_region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1); + } + } + return ivec3(ivec2(mod(r_uv,_region_size)), layer_index); +} + +// Takes in descaled (world_space / region_size) world to region space XZ (UV2) coordinates, returns vec3 with: +// XY: (0. to 1.) coordinates within a region +// Z: layer index used for texturearrays, -1 if not in a region +vec3 get_index_uv(const vec2 uv2) { + ivec2 pos = ivec2(floor(uv2)) + (_region_map_size / 2); + int bounds = int(uint(pos.x | pos.y) < uint(_region_map_size)); + int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1; + return vec3(uv2 - _region_locations[layer_index], float(layer_index)); +} + +void vertex() { + // Get vertex of flat plane in world coordinates and set world UV + v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; + + // Camera distance to vertex on flat plane + float v_vertex_xz_dist = length(v_vertex.xz - _camera_pos.xz); + + // Geomorph vertex, set end and start for linear height interpolate + float scale = MODEL_MATRIX[0][0]; + float vertex_lerp = smoothstep(0.55, 0.95, (v_vertex_xz_dist / scale - _mesh_size - 4.0) / (_mesh_size - 2.0)); + vec2 v_fract = fract(VERTEX.xz * 0.5) * 2.0; + // For LOD0 morph from a regular grid to an alternating grid to align with LOD1+ + vec2 shift = (scale < _vertex_spacing + 1e-6) ? // LOD0 or not + // Shift from regular to symetric + mix(v_fract, vec2(v_fract.x, -v_fract.y), + round(fract(round(mod(v_vertex.z * _vertex_density, 4.0)) * + round(mod(v_vertex.x * _vertex_density, 4.0)) * 0.25)) + ) : + // Symetric shift + v_fract * round((fract(v_vertex.xz * 0.25 / scale) - 0.5) * 4.0); + vec2 start_pos = v_vertex.xz * _vertex_density; + vec2 end_pos = (v_vertex.xz - shift * scale) * _vertex_density; + v_vertex.xz -= shift * scale * vertex_lerp; + + // UV coordinates in world space. Values are 0 to _region_size within regions + UV = v_vertex.xz * _vertex_density; + + // UV coordinates in region space + texel offset. Values are 0 to 1 within regions + UV2 = fma(UV, vec2(_region_texel_size), vec2(0.5 * _region_texel_size)); + + // Discard vertices for Holes. 1 lookup + ivec3 v_region = get_index_coord(start_pos, VERTEX_PASS); + uint control = floatBitsToUint(texelFetch(_control_maps, v_region, 0)).r; + bool hole = DECODE_HOLE(control); + + // Show holes to all cameras except mouse camera (on exactly 1 layer) + if ( !(CAMERA_VISIBLE_LAYERS == _mouse_layer) && + (hole || (_background_mode == 0u && v_region.z == -1))) { + v_vertex.x = 0. / 0.; + } else { + // Set final vertex height & calculate vertex normals. 3 lookups + ivec3 uv_a = get_index_coord(start_pos, VERTEX_PASS); + ivec3 uv_b = get_index_coord(end_pos, VERTEX_PASS); + float h = mix(texelFetch(_height_maps, uv_a, 0).r,texelFetch(_height_maps, uv_b, 0).r,vertex_lerp); + v_vertex.y = h; + + // Vertex normals + float u = mix(texelFetch(_height_maps, get_index_coord(start_pos + vec2(1,0), VERTEX_PASS), 0).r, + texelFetch(_height_maps, get_index_coord(end_pos + vec2(1,0), VERTEX_PASS), 0).r, vertex_lerp); + float v = mix(texelFetch(_height_maps, get_index_coord(start_pos + vec2(0,1), VERTEX_PASS), 0).r, + texelFetch(_height_maps, get_index_coord(end_pos + vec2(0,1), VERTEX_PASS), 0).r, vertex_lerp); + + v_normal = normalize(vec3(h - u, _vertex_spacing, h - v)); + } + + // Convert model space to view space w/ skip_vertex_transform render mode + VERTEX = (VIEW_MATRIX * vec4(v_vertex, 1.0)).xyz; + + // Apply terrain normals + vec3 w_tangent = normalize(cross(v_normal, vec3(0.0, 0.0, 1.0))); + vec3 w_binormal = normalize(cross(v_normal, w_tangent)); + TBN = mat3(w_tangent, w_binormal, v_normal); + + NORMAL = normalize((VIEW_MATRIX * vec4(v_normal, 0.0)).xyz); + BINORMAL = normalize((VIEW_MATRIX * vec4(w_binormal, 0.0)).xyz); + TANGENT = normalize((VIEW_MATRIX * vec4(w_tangent, 0.0)).xyz); +} + +//////////////////////// +// Fragment +//////////////////////// + +mat2 rotate_plane(float angle) { + float c = cos(angle), s = sin(angle); + return mat2(vec2(c, s), vec2(-s, c)); +} + +void fragment() { + // Recover UVs + vec2 uv = UV; + vec2 uv2 = UV2; + + // Lookup offsets, ID and blend weight + vec3 region_uv = get_index_uv(uv2); + const vec3 offsets = vec3(0, 1, 2); + vec2 index_id = floor(uv); + vec2 weight = fract(uv); + vec2 invert = 1.0 - weight; + vec4 weights = vec4( + invert.x * weight.y, // 0 + weight.x * weight.y, // 1 + weight.x * invert.y, // 2 + invert.x * invert.y // 3 + ); + + ivec3 index[4]; + // control map lookups, used for some normal lookups as well + index[0] = get_index_coord(index_id + offsets.xy, FRAGMENT_PASS); + index[1] = get_index_coord(index_id + offsets.yy, FRAGMENT_PASS); + index[2] = get_index_coord(index_id + offsets.yx, FRAGMENT_PASS); + index[3] = get_index_coord(index_id + offsets.xx, FRAGMENT_PASS); + + vec3 base_ddx = dFdxCoarse(v_vertex); + vec3 base_ddy = dFdyCoarse(v_vertex); + vec4 base_dd = vec4(base_ddx.xz, base_ddy.xz); + // Calculate the effective mipmap for regionspace + float region_mip = log2(max(length(base_ddx.xz), length(base_ddy.xz)) * _vertex_density); + + // Color map + vec4 color_map = region_uv.z > -1.0 ? textureLod(_color_maps, region_uv, region_mip) : COLOR_MAP; + + if (flat_terrain_normals) { + NORMAL = normalize(cross(dFdyCoarse(VERTEX),dFdxCoarse(VERTEX))); + TANGENT = normalize(cross(NORMAL, VIEW_MATRIX[2].xyz)); + BINORMAL = normalize(cross(NORMAL, TANGENT)); + } + + // defaults + vec4 normal_rough = vec4(0., 1., 0., 0.7); + vec4 albedo_height = vec4(1.); + float normal_map_depth = 1.; + float ao_strength = 0.; + + if (enable_texturing) { + // set to zero before accumulation + albedo_height = vec4(0.); + normal_rough = vec4(0.); + normal_map_depth = 0.; + ao_strength = 0.; + float total_weight = 0.; + float sharpness = fma(56., blend_sharpness, 8.); + + // Get index control data + // 1 - 4 lookups + uvec4 control = floatBitsToUint(vec4( + texelFetch(_control_maps, index[0], 0).r, + texelFetch(_control_maps, index[1], 0).r, + texelFetch(_control_maps, index[2], 0).r, + texelFetch(_control_maps, index[3], 0).r)); + + { + // Auto blend calculation + float auto_blend = clamp(fma(auto_slope * 2.0, (v_normal.y - 1.0), 1.0) + - auto_height_reduction * 0.01 * v_vertex.y, 0.0, 1.0); + // Enable Autoshader if outside regions or painted in regions, otherwise manual painted + uvec4 is_auto = (control & uvec4(0x1u)) | uvec4(uint(region_uv.z < 0.0)); + uint u_auto = + ((uint(auto_base_texture) & 0x1Fu) << 27u) | + ((uint(auto_overlay_texture) & 0x1Fu) << 22u) | + ((uint(fma(auto_blend, 255.0 , 0.5)) & 0xFFu) << 14u); + control = control * (1u - is_auto) + u_auto * is_auto; + } + + + // Texture weights + // Vectorised Deocode of all texture IDs, then swizzle to per index mapping. + ivec4 t_id[2] = {ivec4(control >> uvec4(27u) & uvec4(0x1Fu)), + ivec4(control >> uvec4(22u) & uvec4(0x1Fu))}; + ivec2 texture_ids[4] = ivec2[4]( + ivec2(t_id[0].x, t_id[1].x), + ivec2(t_id[0].y, t_id[1].y), + ivec2(t_id[0].z, t_id[1].z), + ivec2(t_id[0].w, t_id[1].w)); + + // interpolated weights. + vec4 weights_id_1 = vec4(control >> uvec4(14u) & uvec4(0xFFu)) * DIV_255 * weights; + vec4 weights_id_0 = weights - weights_id_1; + vec2 t_weights[4] = {vec2(0), vec2(0), vec2(0), vec2(0)}; + for (int i = 0; i < 4; i++) { + vec2 w_0 = vec2(weights_id_0[i]); + vec2 w_1 = vec2(weights_id_1[i]); + ivec2 id_0 = texture_ids[i].xx; + ivec2 id_1 = texture_ids[i].yy; + t_weights[0] += fma(w_0, vec2(equal(texture_ids[0], id_0)), w_1 * vec2(equal(texture_ids[0], id_1))); + t_weights[1] += fma(w_0, vec2(equal(texture_ids[1], id_0)), w_1 * vec2(equal(texture_ids[1], id_1))); + t_weights[2] += fma(w_0, vec2(equal(texture_ids[2], id_0)), w_1 * vec2(equal(texture_ids[2], id_1))); + t_weights[3] += fma(w_0, vec2(equal(texture_ids[3], id_0)), w_1 * vec2(equal(texture_ids[3], id_1))); + } + + + // Process control data to determine each texture ID present, so that only + // a single sample will be needed later, as all id are contiguous when features + // like detiling, scale, rotation, and projection are not present. + // 2 to 16 lookups + uint id_read = 0u; // 1 bit per possible ID + // world normal adjustment requires acess to previous id during next iteration + vec4 nrm = vec4(0.0, 1.0, 0.0, 1.0); + // adjust uv scale to account for vertex spacing + uv *= _vertex_spacing; + for (int i = 0; i < 4; i++) { + for (int t = 0; t < 2; t++) { + int id = texture_ids[i][t]; + uint mask = 1u << uint(id); + if ((id_read & mask) == 0u) { + // Set this id bit + id_read |= mask; + float id_w = t_weights[i][t]; + float id_scale = _texture_uv_scale_array[id] * 0.5; + vec2 id_uv = fma(uv, vec2(id_scale), vec2(0.5)); + vec4 i_dd = base_dd * id_scale; + vec4 alb = textureGrad(_texture_array_albedo, vec3(id_uv, float(id)), i_dd.xy, i_dd.zw); + float world_normal = clamp(fma(TBN[0], vec3(nrm.x), fma(TBN[1], vec3(nrm.z), v_normal * vec3(nrm.y))).y, 0., 1.); + nrm = textureGrad(_texture_array_normal, vec3(id_uv, float(id)), i_dd.xy, i_dd.zw); + alb.rgb *= _texture_color_array[id].rgb; + nrm.a = clamp(nrm.a + _texture_roughness_mod_array[id], 0., 1.); + // Unpack normal map for blending. + nrm.xyz = fma(nrm.xzy, vec3(2.0), vec3(-1.0)); + // height weight modifier. + float id_weight = exp2(sharpness * log2(id_w + alb.a * world_normal)); + albedo_height += alb * id_weight; + normal_rough += nrm * id_weight; + normal_map_depth += _texture_normal_depth_array[id] * id_weight; + ao_strength += _texture_ao_strength_array[id] * id_weight; + total_weight += id_weight; + } + } + } + // normalize accumulated values back to 0.0 - 1.0 range. + float weight_inv = 1.0 / total_weight; + albedo_height *= weight_inv; + normal_rough *= weight_inv; + normal_map_depth *= weight_inv; + ao_strength *= weight_inv; + } + + // Macro variation. 2 lookups + vec3 macrov = vec3(1.); + if (enable_macro_variation) { + float noise1 = texture(noise_texture, (uv * noise1_scale * .1 + noise1_offset) * rotate_plane(noise1_angle)).r; + float noise2 = texture(noise_texture, uv * noise2_scale * .1).r; + macrov = mix(macro_variation1, vec3(1.), noise1); + macrov *= mix(macro_variation2, vec3(1.), noise2); + macrov = mix(vec3(1.0), macrov, clamp(v_normal.y + macro_variation_slope, 0., 1.)); + } + + // Wetness/roughness modifier, converting 0 - 1 range to -1 to 1 range, clamped to Godot roughness values + float roughness = clamp(fma(color_map.a - 0.5, 2.0, normal_rough.a), 0., 1.); + + // Apply PBR + ALBEDO = albedo_height.rgb * color_map.rgb * macrov; + ROUGHNESS = roughness; + SPECULAR = 1. - normal_rough.a; + // Repack final normal map value. + NORMAL_MAP = fma(normalize(normal_rough.xzy), vec3(0.5), vec3(0.5)); + NORMAL_MAP_DEPTH = normal_map_depth; + + // Higher and/or facing up, less occluded. + float ao = (1. - (albedo_height.a * log(2.1 - ao_strength))) * (1. - normal_rough.y); + AO = clamp(1. - ao * ao_strength, albedo_height.a, 1.0); + AO_LIGHT_AFFECT = (1.0 - albedo_height.a) * clamp(normal_rough.y, 0., 1.); + +} diff --git a/addons/terrain_3d/extras/shaders/lightweight.gdshader.uid b/addons/terrain_3d/extras/shaders/lightweight.gdshader.uid new file mode 100644 index 0000000..b4cd1db --- /dev/null +++ b/addons/terrain_3d/extras/shaders/lightweight.gdshader.uid @@ -0,0 +1 @@ +uid://bbx2xhanpq5l3 diff --git a/addons/terrain_3d/extras/shaders/minimum.gdshader b/addons/terrain_3d/extras/shaders/minimum.gdshader new file mode 100644 index 0000000..b7a95e7 --- /dev/null +++ b/addons/terrain_3d/extras/shaders/minimum.gdshader @@ -0,0 +1,217 @@ +// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +// This shader is the minimum needed to allow the terrain to function, without any texturing. + +shader_type spatial; +render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx,skip_vertex_transform; + +// Defined Constants +#define SKIP_PASS 0 +#define VERTEX_PASS 1 +#define FRAGMENT_PASS 2 + +#if CURRENT_RENDERER == RENDERER_COMPATIBILITY + #define fma(a, b, c) ((a) * (b) + (c)) + #define dFdxCoarse(a) dFdx(a) + #define dFdyCoarse(a) dFdy(a) +#endif + +// Private uniforms +// Commented uniforms aren't needed for this shader, but are available for your own needs. +uniform vec3 _camera_pos = vec3(0.f); +uniform float _mesh_size = 48.f; +uniform uint _background_mode = 1u; // NONE = 0, FLAT = 1, NOISE = 2 +uniform uint _mouse_layer = 0x80000000u; // Layer 32 +uniform float _vertex_spacing = 1.0; +uniform float _vertex_density = 1.0; // = 1/_vertex_spacing +uniform float _region_size = 1024.0; +uniform float _region_texel_size = 0.0009765625; // = 1/1024 +uniform int _region_map_size = 32; +uniform int _region_map[1024]; +//uniform vec2 _region_locations[1024]; +//uniform float _texture_uv_scale_array[32]; +//uniform float _texture_detile_array[32]; +//uniform vec4 _texture_color_array[32]; +uniform highp sampler2DArray _height_maps : repeat_disable; +uniform highp sampler2DArray _control_maps : repeat_disable; +//uniform highp sampler2DArray _color_maps : source_color, filter_linear_mipmap_anisotropic, repeat_disable; +//uniform highp sampler2DArray _texture_array_albedo : source_color, filter_linear_mipmap_anisotropic, repeat_enable; +//uniform highp sampler2DArray _texture_array_normal : hint_normal, filter_linear_mipmap_anisotropic, repeat_enable; + +// Public Uniforms +uniform bool flat_terrain_normals = false; + +// Varyings & Types +// Some are required for editor functions +varying float v_vertex_xz_dist; +varying vec3 v_vertex; + +//////////////////////// +// Vertex +//////////////////////// + +// Takes in world space XZ (UV) coordinates & search depth (only applicable for background mode none) +// Returns ivec3 with: +// XY: (0 to _region_size - 1) coordinates within a region +// Z: layer index used for texturearrays, -1 if not in a region +ivec3 get_index_coord(const vec2 uv, const int search) { + vec2 r_uv = round(uv); + vec2 o_uv = mod(r_uv,_region_size); + ivec2 pos; + int bounds, layer_index = -1; + for (int i = -1; i < clamp(search, SKIP_PASS, FRAGMENT_PASS); i++) { + if ((layer_index == -1 && _background_mode == 0u ) || i < 0) { + r_uv -= i == -1 ? vec2(0.0) : vec2(float(o_uv.x <= o_uv.y), float(o_uv.y <= o_uv.x)); + pos = ivec2(floor((r_uv) * _region_texel_size)) + (_region_map_size / 2); + bounds = int(uint(pos.x | pos.y) < uint(_region_map_size)); + layer_index = (_region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1); + } + } + return ivec3(ivec2(mod(r_uv,_region_size)), layer_index); +} + +void vertex() { + // Get vertex of flat plane in world coordinates and set world UV + v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; + + // Camera distance to vertex on flat plane + v_vertex_xz_dist = length(v_vertex.xz - _camera_pos.xz); + + // Geomorph vertex, set end and start for linear height interpolate + float scale = MODEL_MATRIX[0][0]; + float vertex_lerp = smoothstep(0.55, 0.95, (v_vertex_xz_dist / scale - _mesh_size - 4.0) / (_mesh_size - 2.0)); + vec2 v_fract = fract(VERTEX.xz * 0.5) * 2.0; + // For LOD0 morph from a regular grid to an alternating grid to align with LOD1+ + vec2 shift = (scale < _vertex_spacing + 1e-6) ? // LOD0 or not + // Shift from regular to symetric + mix(v_fract, vec2(v_fract.x, -v_fract.y), + round(fract(round(mod(v_vertex.z * _vertex_density, 4.0)) * + round(mod(v_vertex.x * _vertex_density, 4.0)) * 0.25)) + ) : + // Symetric shift + v_fract * round((fract(v_vertex.xz * 0.25 / scale) - 0.5) * 4.0); + vec2 start_pos = v_vertex.xz * _vertex_density; + vec2 end_pos = (v_vertex.xz - shift * scale) * _vertex_density; + v_vertex.xz -= shift * scale * vertex_lerp; + + // UV coordinates in world space. Values are 0 to _region_size within regions + UV = v_vertex.xz * _vertex_density; + + // UV coordinates in region space + texel offset. Values are 0 to 1 within regions + UV2 = fma(UV, vec2(_region_texel_size), vec2(0.5 * _region_texel_size)); + + // Discard vertices for Holes. 1 lookup + ivec3 v_region = get_index_coord(start_pos, VERTEX_PASS); + uint control = floatBitsToUint(texelFetch(_control_maps, v_region, 0)).r; + bool hole = bool(control >>2u & 0x1u); + + // Show holes to all cameras except mouse camera (on exactly 1 layer) + if ( !(CAMERA_VISIBLE_LAYERS == _mouse_layer) && + (hole || (_background_mode == 0u && v_region.z < 0))) { + v_vertex.x = 0. / 0.; + } else { + // Interpolate Geomorph Start & End, set height. 2 Lookups. + ivec3 uv_a = get_index_coord(start_pos, VERTEX_PASS); + ivec3 uv_b = get_index_coord(end_pos, VERTEX_PASS); + float h = mix(texelFetch(_height_maps, uv_a, 0).r, texelFetch(_height_maps, uv_b, 0).r, vertex_lerp); + v_vertex.y = h; + } + + // Convert model space to view space w/ skip_vertex_transform render mode + VERTEX = (VIEW_MATRIX * vec4(v_vertex, 1.0)).xyz; + NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz); + BINORMAL = normalize((MODELVIEW_MATRIX * vec4(BINORMAL, 0.0)).xyz); + TANGENT = normalize((MODELVIEW_MATRIX * vec4(TANGENT, 0.0)).xyz); +} + +//////////////////////// +// Fragment +//////////////////////// + +void fragment() { + // Recover UVs + vec2 uv = UV; + //vec2 uv2 = UV2; + + // Lookup offsets, ID and blend weight + const vec3 offsets = vec3(0, 1, 2); + vec2 index_id = floor(uv); + vec2 weight = fract(uv); + vec2 invert = 1.0 - weight; + vec4 weights = vec4( + invert.x * weight.y, // 0 + weight.x * weight.y, // 1 + weight.x * invert.y, // 2 + invert.x * invert.y // 3 + ); + + vec3 base_ddx = dFdxCoarse(v_vertex); + vec3 base_ddy = dFdyCoarse(v_vertex); + //vec4 base_derivatives = vec4(base_ddx.xz, base_ddy.xz); + // Calculate the effective mipmap for regionspace, and if less than 0, + // skip all extra lookups required for bilinear blend. + float region_mip = log2(max(length(base_ddx.xz), length(base_ddy.xz)) * _vertex_density); + bool bilerp = region_mip < 0.0; + + ivec3 index[4]; + // control map lookups, used for some normal lookups as well + index[0] = get_index_coord(index_id + offsets.xy, FRAGMENT_PASS); + index[1] = get_index_coord(index_id + offsets.yy, FRAGMENT_PASS); + index[2] = get_index_coord(index_id + offsets.yx, FRAGMENT_PASS); + index[3] = get_index_coord(index_id + offsets.xx, FRAGMENT_PASS); + + // Terrain normals + vec3 index_normal[4]; + float h[4]; + // allows additional derivatives, eg world noise, brush previews etc + float u = 0.0; + float v = 0.0; + + // Re-use index[] for the first lookups, skipping some math. 3 lookups + h[3] = texelFetch(_height_maps, index[3], 0).r; // 0 (0,0) + h[2] = texelFetch(_height_maps, index[2], 0).r; // 1 (1,0) + h[0] = texelFetch(_height_maps, index[0], 0).r; // 2 (0,1) + index_normal[3] = normalize(vec3(h[3] - h[2] + u, _vertex_spacing, h[3] - h[0] + v)); + + // Set flat world normal - overriden if bilerp is true + vec3 w_normal = index_normal[3]; + + // Branching smooth normals must be done seperatley for correct normals at all 4 index ids + if (bilerp) { + // 5 lookups + // Fetch the additional required height values for smooth normals + h[1] = texelFetch(_height_maps, index[1], 0).r; // 3 (1,1) + float h_4 = texelFetch(_height_maps, get_index_coord(index_id + offsets.yz, FRAGMENT_PASS), 0).r; // 4 (1,2) + float h_5 = texelFetch(_height_maps, get_index_coord(index_id + offsets.zy, FRAGMENT_PASS), 0).r; // 5 (2,1) + float h_6 = texelFetch(_height_maps, get_index_coord(index_id + offsets.zx, FRAGMENT_PASS), 0).r; // 6 (2,0) + float h_7 = texelFetch(_height_maps, get_index_coord(index_id + offsets.xz, FRAGMENT_PASS), 0).r; // 7 (0,2) + + // Calculate the normal for the remaining index ids. + index_normal[0] = normalize(vec3(h[0] - h[1] + u, _vertex_spacing, h[0] - h_7 + v)); + index_normal[1] = normalize(vec3(h[1] - h_5 + u, _vertex_spacing, h[1] - h_4 + v)); + index_normal[2] = normalize(vec3(h[2] - h_6 + u, _vertex_spacing, h[2] - h[1] + v)); + + // Set interpolated world normal + w_normal = + index_normal[0] * weights[0] + + index_normal[1] * weights[1] + + index_normal[2] * weights[2] + + index_normal[3] * weights[3] ; + } + + // Apply terrain normals + vec3 w_tangent = normalize(cross(w_normal, vec3(0.0, 0.0, 1.0))); + vec3 w_binormal = normalize(cross(w_normal, w_tangent)); + NORMAL = mat3(VIEW_MATRIX) * w_normal; + TANGENT = mat3(VIEW_MATRIX) * w_tangent; + BINORMAL = mat3(VIEW_MATRIX) * w_binormal; + + if (flat_terrain_normals) { + NORMAL = normalize(cross(dFdyCoarse(VERTEX),dFdxCoarse(VERTEX))); + TANGENT = normalize(cross(NORMAL, VIEW_MATRIX[2].xyz)); + BINORMAL = normalize(cross(NORMAL, TANGENT)); + } + + // Apply PBR + ALBEDO = vec3(.2); + ROUGHNESS = .7; +} diff --git a/addons/terrain_3d/extras/shaders/minimum.gdshader.uid b/addons/terrain_3d/extras/shaders/minimum.gdshader.uid new file mode 100644 index 0000000..8d390b2 --- /dev/null +++ b/addons/terrain_3d/extras/shaders/minimum.gdshader.uid @@ -0,0 +1 @@ +uid://01qauauvd8aa diff --git a/addons/terrain_3d/icons/autoshader.svg b/addons/terrain_3d/icons/autoshader.svg new file mode 100644 index 0000000..5e6ee1a --- /dev/null +++ b/addons/terrain_3d/icons/autoshader.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/autoshader.svg.import b/addons/terrain_3d/icons/autoshader.svg.import new file mode 100644 index 0000000..1551553 --- /dev/null +++ b/addons/terrain_3d/icons/autoshader.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bdwolwswwy8wr" +path="res://.godot/imported/autoshader.svg-9998e61bbc6afd5b134b767acd17a425.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/autoshader.svg" +dest_files=["res://.godot/imported/autoshader.svg-9998e61bbc6afd5b134b767acd17a425.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/color_paint.svg b/addons/terrain_3d/icons/color_paint.svg new file mode 100644 index 0000000..317b742 --- /dev/null +++ b/addons/terrain_3d/icons/color_paint.svg @@ -0,0 +1,175 @@ + +image/svg+xml diff --git a/addons/terrain_3d/icons/color_paint.svg.import b/addons/terrain_3d/icons/color_paint.svg.import new file mode 100644 index 0000000..56d0d5d --- /dev/null +++ b/addons/terrain_3d/icons/color_paint.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://krrmpalen8xu" +path="res://.godot/imported/color_paint.svg-2a416ebf35da04135017e5c6ef53ea57.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/color_paint.svg" +dest_files=["res://.godot/imported/color_paint.svg-2a416ebf35da04135017e5c6ef53ea57.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/height_add.svg b/addons/terrain_3d/icons/height_add.svg new file mode 100644 index 0000000..299a1b8 --- /dev/null +++ b/addons/terrain_3d/icons/height_add.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/height_add.svg.import b/addons/terrain_3d/icons/height_add.svg.import new file mode 100644 index 0000000..e1bbbad --- /dev/null +++ b/addons/terrain_3d/icons/height_add.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcmbqryggekg1" +path="res://.godot/imported/height_add.svg-9e680ce71fa4c541748e081b99167369.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/height_add.svg" +dest_files=["res://.godot/imported/height_add.svg-9e680ce71fa4c541748e081b99167369.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/height_div.svg b/addons/terrain_3d/icons/height_div.svg new file mode 100644 index 0000000..79a6111 --- /dev/null +++ b/addons/terrain_3d/icons/height_div.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/height_div.svg.import b/addons/terrain_3d/icons/height_div.svg.import new file mode 100644 index 0000000..c894274 --- /dev/null +++ b/addons/terrain_3d/icons/height_div.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://danh7tb2v6rx7" +path="res://.godot/imported/height_div.svg-449a465f9fdd11ab59f2f1c78815408c.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/height_div.svg" +dest_files=["res://.godot/imported/height_div.svg-449a465f9fdd11ab59f2f1c78815408c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/height_flat.svg b/addons/terrain_3d/icons/height_flat.svg new file mode 100644 index 0000000..98973fe --- /dev/null +++ b/addons/terrain_3d/icons/height_flat.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/height_flat.svg.import b/addons/terrain_3d/icons/height_flat.svg.import new file mode 100644 index 0000000..fd0e685 --- /dev/null +++ b/addons/terrain_3d/icons/height_flat.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://crj0xfyiyr45u" +path="res://.godot/imported/height_flat.svg-be726a006bf06e05a7a8867510f3996e.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/height_flat.svg" +dest_files=["res://.godot/imported/height_flat.svg-be726a006bf06e05a7a8867510f3996e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/height_mul.svg b/addons/terrain_3d/icons/height_mul.svg new file mode 100644 index 0000000..ef4f92e --- /dev/null +++ b/addons/terrain_3d/icons/height_mul.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/height_mul.svg.import b/addons/terrain_3d/icons/height_mul.svg.import new file mode 100644 index 0000000..b20aadc --- /dev/null +++ b/addons/terrain_3d/icons/height_mul.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bu3q0645kb3el" +path="res://.godot/imported/height_mul.svg-2dca20fa42a85408713e9bfe411f3c79.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/height_mul.svg" +dest_files=["res://.godot/imported/height_mul.svg-2dca20fa42a85408713e9bfe411f3c79.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/height_slope.svg b/addons/terrain_3d/icons/height_slope.svg new file mode 100644 index 0000000..fe2903d --- /dev/null +++ b/addons/terrain_3d/icons/height_slope.svg @@ -0,0 +1,105 @@ + + + + diff --git a/addons/terrain_3d/icons/height_slope.svg.import b/addons/terrain_3d/icons/height_slope.svg.import new file mode 100644 index 0000000..ed55b14 --- /dev/null +++ b/addons/terrain_3d/icons/height_slope.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://0cd7so4kw7da" +path="res://.godot/imported/height_slope.svg-e20540c5538d0c57a9d229a772b3d1b3.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/height_slope.svg" +dest_files=["res://.godot/imported/height_slope.svg-e20540c5538d0c57a9d229a772b3d1b3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/height_smooth.svg b/addons/terrain_3d/icons/height_smooth.svg new file mode 100644 index 0000000..81154c3 --- /dev/null +++ b/addons/terrain_3d/icons/height_smooth.svg @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/addons/terrain_3d/icons/height_smooth.svg.import b/addons/terrain_3d/icons/height_smooth.svg.import new file mode 100644 index 0000000..eef9e53 --- /dev/null +++ b/addons/terrain_3d/icons/height_smooth.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://chrbx4xnxyiel" +path="res://.godot/imported/height_smooth.svg-d8fc43572f5984eef64c886a49988c06.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/height_smooth.svg" +dest_files=["res://.godot/imported/height_smooth.svg-d8fc43572f5984eef64c886a49988c06.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/height_sub.svg b/addons/terrain_3d/icons/height_sub.svg new file mode 100644 index 0000000..bb0d2a7 --- /dev/null +++ b/addons/terrain_3d/icons/height_sub.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/height_sub.svg.import b/addons/terrain_3d/icons/height_sub.svg.import new file mode 100644 index 0000000..4dc17eb --- /dev/null +++ b/addons/terrain_3d/icons/height_sub.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://mo3hnbk3ffjs" +path="res://.godot/imported/height_sub.svg-1a14a9bb856f3db0faa02dba3c807b50.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/height_sub.svg" +dest_files=["res://.godot/imported/height_sub.svg-1a14a9bb856f3db0faa02dba3c807b50.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/holes.svg b/addons/terrain_3d/icons/holes.svg new file mode 100644 index 0000000..da639d9 --- /dev/null +++ b/addons/terrain_3d/icons/holes.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/addons/terrain_3d/icons/holes.svg.import b/addons/terrain_3d/icons/holes.svg.import new file mode 100644 index 0000000..8117195 --- /dev/null +++ b/addons/terrain_3d/icons/holes.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bsmaxekrmnuy2" +path="res://.godot/imported/holes.svg-a7cb97bb50d7879cd274646e207b9213.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/holes.svg" +dest_files=["res://.godot/imported/holes.svg-a7cb97bb50d7879cd274646e207b9213.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/layers.svg b/addons/terrain_3d/icons/layers.svg new file mode 100644 index 0000000..5c9c4c9 --- /dev/null +++ b/addons/terrain_3d/icons/layers.svg @@ -0,0 +1,102 @@ + + diff --git a/addons/terrain_3d/icons/layers.svg.import b/addons/terrain_3d/icons/layers.svg.import new file mode 100644 index 0000000..559cd21 --- /dev/null +++ b/addons/terrain_3d/icons/layers.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cs1la1mashf2e" +path="res://.godot/imported/layers.svg-4a679bb626c5179d3773f33e77e4a5e4.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/layers.svg" +dest_files=["res://.godot/imported/layers.svg-4a679bb626c5179d3773f33e77e4a5e4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/multimesh.svg b/addons/terrain_3d/icons/multimesh.svg new file mode 100644 index 0000000..a62e5f9 --- /dev/null +++ b/addons/terrain_3d/icons/multimesh.svg @@ -0,0 +1,40 @@ + + + + + + diff --git a/addons/terrain_3d/icons/multimesh.svg.import b/addons/terrain_3d/icons/multimesh.svg.import new file mode 100644 index 0000000..1493feb --- /dev/null +++ b/addons/terrain_3d/icons/multimesh.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cjlcl5lf20ve0" +path="res://.godot/imported/multimesh.svg-5487b93b04ddbaae37b5d3e91f10750b.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/multimesh.svg" +dest_files=["res://.godot/imported/multimesh.svg-5487b93b04ddbaae37b5d3e91f10750b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/navigation.svg b/addons/terrain_3d/icons/navigation.svg new file mode 100644 index 0000000..1056202 --- /dev/null +++ b/addons/terrain_3d/icons/navigation.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/navigation.svg.import b/addons/terrain_3d/icons/navigation.svg.import new file mode 100644 index 0000000..d8ac263 --- /dev/null +++ b/addons/terrain_3d/icons/navigation.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://f3po5pogkv2b" +path="res://.godot/imported/navigation.svg-1e4cf210c589be8d2911c522d4a17d78.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/navigation.svg" +dest_files=["res://.godot/imported/navigation.svg-1e4cf210c589be8d2911c522d4a17d78.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/picker_checked.svg b/addons/terrain_3d/icons/picker_checked.svg new file mode 100644 index 0000000..653d57e --- /dev/null +++ b/addons/terrain_3d/icons/picker_checked.svg @@ -0,0 +1,43 @@ + + + + + + + diff --git a/addons/terrain_3d/icons/picker_checked.svg.import b/addons/terrain_3d/icons/picker_checked.svg.import new file mode 100644 index 0000000..ff53b15 --- /dev/null +++ b/addons/terrain_3d/icons/picker_checked.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bg8x6o32ggt88" +path="res://.godot/imported/picker_checked.svg-81f35b6ae38bccc8aa9e7ae22b530168.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/picker_checked.svg" +dest_files=["res://.godot/imported/picker_checked.svg-81f35b6ae38bccc8aa9e7ae22b530168.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/region_add.svg b/addons/terrain_3d/icons/region_add.svg new file mode 100644 index 0000000..56d7c92 --- /dev/null +++ b/addons/terrain_3d/icons/region_add.svg @@ -0,0 +1,95 @@ + +image/svg+xml diff --git a/addons/terrain_3d/icons/region_add.svg.import b/addons/terrain_3d/icons/region_add.svg.import new file mode 100644 index 0000000..e50c30b --- /dev/null +++ b/addons/terrain_3d/icons/region_add.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0tn453fsckv5" +path="res://.godot/imported/region_add.svg-a05dc161a452dd3e024f9835a737d9f0.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/region_add.svg" +dest_files=["res://.godot/imported/region_add.svg-a05dc161a452dd3e024f9835a737d9f0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/region_remove.svg b/addons/terrain_3d/icons/region_remove.svg new file mode 100644 index 0000000..315657d --- /dev/null +++ b/addons/terrain_3d/icons/region_remove.svg @@ -0,0 +1,102 @@ + +image/svg+xml diff --git a/addons/terrain_3d/icons/region_remove.svg.import b/addons/terrain_3d/icons/region_remove.svg.import new file mode 100644 index 0000000..6ded856 --- /dev/null +++ b/addons/terrain_3d/icons/region_remove.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cbpo5eamf3bx2" +path="res://.godot/imported/region_remove.svg-5710e8aeb34f1eaa06e637634f4a7d16.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/region_remove.svg" +dest_files=["res://.godot/imported/region_remove.svg-5710e8aeb34f1eaa06e637634f4a7d16.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/terrain3d.svg b/addons/terrain_3d/icons/terrain3d.svg new file mode 100644 index 0000000..ca8c661 --- /dev/null +++ b/addons/terrain_3d/icons/terrain3d.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/terrain3d.svg.import b/addons/terrain_3d/icons/terrain3d.svg.import new file mode 100644 index 0000000..c077de1 --- /dev/null +++ b/addons/terrain_3d/icons/terrain3d.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bnsydn4jkyeyn" +path="res://.godot/imported/terrain3d.svg-eb45756f1a003759fda81eaa1db10769.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/terrain3d.svg" +dest_files=["res://.godot/imported/terrain3d.svg-eb45756f1a003759fda81eaa1db10769.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/texture_paint.svg b/addons/terrain_3d/icons/texture_paint.svg new file mode 100644 index 0000000..908d3f4 --- /dev/null +++ b/addons/terrain_3d/icons/texture_paint.svg @@ -0,0 +1,151 @@ + +image/svg+xml diff --git a/addons/terrain_3d/icons/texture_paint.svg.import b/addons/terrain_3d/icons/texture_paint.svg.import new file mode 100644 index 0000000..8a09d92 --- /dev/null +++ b/addons/terrain_3d/icons/texture_paint.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://duo8valena3a2" +path="res://.godot/imported/texture_paint.svg-72da4fd2096377e625a8fe09cdacb0e4.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/texture_paint.svg" +dest_files=["res://.godot/imported/texture_paint.svg-72da4fd2096377e625a8fe09cdacb0e4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/texture_spray.svg b/addons/terrain_3d/icons/texture_spray.svg new file mode 100644 index 0000000..bfc3e82 --- /dev/null +++ b/addons/terrain_3d/icons/texture_spray.svg @@ -0,0 +1,165 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/texture_spray.svg.import b/addons/terrain_3d/icons/texture_spray.svg.import new file mode 100644 index 0000000..c4acc6f --- /dev/null +++ b/addons/terrain_3d/icons/texture_spray.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://16yfxe7xe703" +path="res://.godot/imported/texture_spray.svg-326fee11cf418653e621bc222a470861.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/texture_spray.svg" +dest_files=["res://.godot/imported/texture_spray.svg-326fee11cf418653e621bc222a470861.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/icons/wetness.svg b/addons/terrain_3d/icons/wetness.svg new file mode 100644 index 0000000..90c3d03 --- /dev/null +++ b/addons/terrain_3d/icons/wetness.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/terrain_3d/icons/wetness.svg.import b/addons/terrain_3d/icons/wetness.svg.import new file mode 100644 index 0000000..9379330 --- /dev/null +++ b/addons/terrain_3d/icons/wetness.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcgg0srmqsh3n" +path="res://.godot/imported/wetness.svg-9b2ddec096ab7734492b77b20c75c82b.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/terrain_3d/icons/wetness.svg" +dest_files=["res://.godot/imported/wetness.svg-9b2ddec096ab7734492b77b20c75c82b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/terrain_3d/menu/bake_lod_dialog.gd b/addons/terrain_3d/menu/bake_lod_dialog.gd new file mode 100644 index 0000000..ada4fb2 --- /dev/null +++ b/addons/terrain_3d/menu/bake_lod_dialog.gd @@ -0,0 +1,30 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Bake LOD Dialog for Terrain3D +@tool +extends ConfirmationDialog + +var lod: int = 0 +var description: String = "" + + +func _ready() -> void: + set_unparent_when_invisible(true) + about_to_popup.connect(_on_about_to_popup) + visibility_changed.connect(_on_visibility_changed) + %LodBox.value_changed.connect(_on_lod_box_value_changed) + + +func _on_about_to_popup() -> void: + lod = %LodBox.value + + +func _on_visibility_changed() -> void: + # Change text on the autowrap label only when the popup is visible. + # Works around Godot issue #47005: + # https://github.com/godotengine/godot/issues/47005 + if visible: + %DescriptionLabel.text = description + + +func _on_lod_box_value_changed(p_value: float) -> void: + lod = %LodBox.value diff --git a/addons/terrain_3d/menu/bake_lod_dialog.gd.uid b/addons/terrain_3d/menu/bake_lod_dialog.gd.uid new file mode 100644 index 0000000..08c194f --- /dev/null +++ b/addons/terrain_3d/menu/bake_lod_dialog.gd.uid @@ -0,0 +1 @@ +uid://cqmt8f5x5c2ad diff --git a/addons/terrain_3d/menu/bake_lod_dialog.tscn b/addons/terrain_3d/menu/bake_lod_dialog.tscn new file mode 100644 index 0000000..bad26f1 --- /dev/null +++ b/addons/terrain_3d/menu/bake_lod_dialog.tscn @@ -0,0 +1,43 @@ +[gd_scene load_steps=2 format=3 uid="uid://bhvrrmb8bk1bt"] + +[ext_resource type="Script" path="res://addons/terrain_3d/menu/bake_lod_dialog.gd" id="1_sf76d"] + +[node name="bake_lod_dialog" type="ConfirmationDialog"] +title = "Bake Terrain3D Mesh" +position = Vector2i(0, 36) +size = Vector2i(400, 155) +visible = true +script = ExtResource("1_sf76d") + +[node name="MarginContainer" type="MarginContainer" parent="."] +offset_left = 8.0 +offset_top = 8.0 +offset_right = 392.0 +offset_bottom = 106.0 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 20 + +[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "LOD:" + +[node name="LodBox" type="SpinBox" parent="MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +max_value = 8.0 +value = 4.0 + +[node name="DescriptionLabel" type="Label" parent="MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +autowrap_mode = 2 diff --git a/addons/terrain_3d/menu/baker.gd b/addons/terrain_3d/menu/baker.gd new file mode 100644 index 0000000..08064b6 --- /dev/null +++ b/addons/terrain_3d/menu/baker.gd @@ -0,0 +1,398 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Baker for Terrain3D +extends Node + +const BakeLodDialog: PackedScene = preload("res://addons/terrain_3d/menu/bake_lod_dialog.tscn") +const BAKE_MESH_DESCRIPTION: String = "This will create a child MeshInstance3D. LOD4+ is recommended. LOD0 is slow and dense with vertices every 1 unit. It is not an optimal mesh." +const BAKE_OCCLUDER_DESCRIPTION: String = "This will create a child OccluderInstance3D. LOD4+ is recommended and will take 5+ seconds per region to generate. LOD0 is unnecessarily dense and slow." +const SET_UP_NAVIGATION_DESCRIPTION: String = "This operation will: + +- Create a NavigationRegion3D node, +- Assign it a blank NavigationMesh resource, +- Move the Terrain3D node to be a child of the new node, +- And bake the nav mesh. + +Once setup is complete, you can modify the settings on your nav mesh, and rebake +without having to run through the setup again. + +If preferred, this setup can be canceled and the steps performed manually. For +the best results, adjust the settings on the NavigationMesh resource to match +the settings of your navigation agents and collisions." + +var plugin: EditorPlugin +var bake_method: Callable +var bake_lod_dialog: ConfirmationDialog +var confirm_dialog: ConfirmationDialog + + +func _enter_tree() -> void: + bake_lod_dialog = BakeLodDialog.instantiate() + bake_lod_dialog.hide() + bake_lod_dialog.confirmed.connect(func(): bake_method.call()) + bake_lod_dialog.set_unparent_when_invisible(true) + + confirm_dialog = ConfirmationDialog.new() + confirm_dialog.hide() + confirm_dialog.confirmed.connect(func(): bake_method.call()) + confirm_dialog.set_unparent_when_invisible(true) + + +func _exit_tree() -> void: + bake_lod_dialog.queue_free() + confirm_dialog.queue_free() + + +func bake_mesh_popup() -> void: + if plugin.terrain: + bake_method = _bake_mesh + bake_lod_dialog.description = BAKE_MESH_DESCRIPTION + EditorInterface.popup_dialog_centered(bake_lod_dialog) + + +func _bake_mesh() -> void: + if plugin.terrain.data.get_region_count() == 0: + push_error("Terrain3D has no active regions to bake") + return + var mesh: Mesh = plugin.terrain.bake_mesh(bake_lod_dialog.lod, Terrain3DData.HEIGHT_FILTER_NEAREST) + if !mesh: + push_error("Failed to bake mesh from Terrain3D") + return + + var undo: EditorUndoRedoManager = plugin.get_undo_redo() + undo.create_action("Terrain3D Bake ArrayMesh") + + var mesh_instance := plugin.terrain.get_node_or_null(^"MeshInstance3D") as MeshInstance3D + if !mesh_instance: + mesh_instance = MeshInstance3D.new() + mesh_instance.name = &"MeshInstance3D" + mesh_instance.set_skeleton_path(NodePath()) + mesh_instance.mesh = mesh + + undo.add_do_method(plugin.terrain, &"add_child", mesh_instance, true) + undo.add_undo_method(plugin.terrain, &"remove_child", mesh_instance) + undo.add_do_property(mesh_instance, &"owner", EditorInterface.get_edited_scene_root()) + undo.add_do_reference(mesh_instance) + + else: + undo.add_do_property(mesh_instance, &"mesh", mesh) + undo.add_undo_property(mesh_instance, &"mesh", mesh_instance.mesh) + + if mesh_instance.mesh.resource_path: + var path := mesh_instance.mesh.resource_path + undo.add_do_method(mesh, &"take_over_path", path) + undo.add_undo_method(mesh_instance.mesh, &"take_over_path", path) + undo.add_do_method(ResourceSaver, &"save", mesh) + undo.add_undo_method(ResourceSaver, &"save", mesh_instance.mesh) + + undo.commit_action() + + +func bake_occluder_popup() -> void: + if plugin.terrain: + bake_method = _bake_occluder + bake_lod_dialog.description = BAKE_OCCLUDER_DESCRIPTION + EditorInterface.popup_dialog_centered(bake_lod_dialog) + + +func _bake_occluder() -> void: + if plugin.terrain.data.get_region_count() == 0: + push_error("Terrain3D has no active regions to bake") + return + var mesh: Mesh = plugin.terrain.bake_mesh(bake_lod_dialog.lod, Terrain3DData.HEIGHT_FILTER_MINIMUM) + if !mesh: + push_error("Failed to bake mesh from Terrain3D") + return + assert(mesh.get_surface_count() == 1) + + var undo: EditorUndoRedoManager = plugin.get_undo_redo() + undo.create_action("Terrain3D Bake Occluder3D") + + var occluder := ArrayOccluder3D.new() + var arrays: Array = mesh.surface_get_arrays(0) + assert(arrays.size() > Mesh.ARRAY_INDEX) + assert(arrays[Mesh.ARRAY_INDEX] != null) + occluder.set_arrays(arrays[Mesh.ARRAY_VERTEX], arrays[Mesh.ARRAY_INDEX]) + + var occluder_instance := plugin.terrain.get_node_or_null(^"OccluderInstance3D") as OccluderInstance3D + if !occluder_instance: + occluder_instance = OccluderInstance3D.new() + occluder_instance.name = &"OccluderInstance3D" + occluder_instance.occluder = occluder + + undo.add_do_method(plugin.terrain, &"add_child", occluder_instance, true) + undo.add_undo_method(plugin.terrain, &"remove_child", occluder_instance) + undo.add_do_property(occluder_instance, &"owner", EditorInterface.get_edited_scene_root()) + undo.add_do_reference(occluder_instance) + + else: + undo.add_do_property(occluder_instance, &"occluder", occluder) + undo.add_undo_property(occluder_instance, &"occluder", occluder_instance.occluder) + + if occluder_instance.occluder.resource_path: + var path := occluder_instance.occluder.resource_path + undo.add_do_method(occluder, &"take_over_path", path) + undo.add_undo_method(occluder_instance.occluder, &"take_over_path", path) + undo.add_do_method(ResourceSaver, &"save", occluder) + undo.add_undo_method(ResourceSaver, &"save", occluder_instance.occluder) + + undo.commit_action() + + +func find_nav_region_terrains(p_nav_region: NavigationRegion3D) -> Array[Terrain3D]: + var result: Array[Terrain3D] = [] + if not p_nav_region.navigation_mesh: + return result + + var source_mode: NavigationMesh.SourceGeometryMode + source_mode = p_nav_region.navigation_mesh.geometry_source_geometry_mode + if source_mode == NavigationMesh.SOURCE_GEOMETRY_ROOT_NODE_CHILDREN: + result.append_array(p_nav_region.find_children("", "Terrain3D", true, true)) + return result + + var group_nodes: Array = p_nav_region.get_tree().get_nodes_in_group(p_nav_region.navigation_mesh.geometry_source_group_name) + for node in group_nodes: + if node is Terrain3D: + result.push_back(node) + if source_mode == NavigationMesh.SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN: + result.append_array(node.find_children("", "Terrain3D", true, true)) + + return result + + +func find_terrain_nav_regions(p_terrain: Terrain3D) -> Array[NavigationRegion3D]: + var result: Array[NavigationRegion3D] = [] + var root: Node = EditorInterface.get_edited_scene_root() + if not root: + return result + for nav_region in root.find_children("", "NavigationRegion3D", true, true): + if find_nav_region_terrains(nav_region).has(p_terrain): + result.push_back(nav_region) + return result + + +func bake_nav_mesh() -> void: + if plugin.nav_region: + # A NavigationRegion3D is selected. We only need to bake that one navmesh. + _bake_nav_region_nav_mesh(plugin.nav_region) + print("Terrain3DNavigation: Finished baking 1 NavigationMesh.") + + elif plugin.terrain: + if plugin.terrain.data.get_region_count() == 0: + push_error("Terrain3D has no active regions to bake") + return + # A Terrain3D is selected. There are potentially multiple navmeshes to bake and we need to + # find them all. (The multiple navmesh use-case is likely on very large scenes with lots of + # geometry. Each navmesh in this case would define its own, non-overlapping, baking AABB, to + # cut down on the amount of geometry to bake. In a large open-world RPG, for instance, there + # could be a navmesh for each town.) + var nav_regions: Array[NavigationRegion3D] = find_terrain_nav_regions(plugin.terrain) + for nav_region in nav_regions: + _bake_nav_region_nav_mesh(nav_region) + print("Terrain3DNavigation: Finished baking %d NavigationMesh(es)." % nav_regions.size()) + + +func _bake_nav_region_nav_mesh(p_nav_region: NavigationRegion3D) -> void: + var nav_mesh: NavigationMesh = p_nav_region.navigation_mesh + assert(nav_mesh != null) + + var source_geometry_data := NavigationMeshSourceGeometryData3D.new() + NavigationServer3D.parse_source_geometry_data(nav_mesh, source_geometry_data, p_nav_region) + + for terrain in find_nav_region_terrains(p_nav_region): + var aabb: AABB = nav_mesh.filter_baking_aabb + aabb.position += nav_mesh.filter_baking_aabb_offset + aabb = p_nav_region.global_transform * aabb + var faces: PackedVector3Array = terrain.generate_nav_mesh_source_geometry(aabb) + if not faces.is_empty(): + source_geometry_data.add_faces(faces, Transform3D.IDENTITY) + + NavigationServer3D.bake_from_source_geometry_data(nav_mesh, source_geometry_data) + + _postprocess_nav_mesh(nav_mesh) + + # Assign null first to force the debug display to actually update: + p_nav_region.set_navigation_mesh(null) + p_nav_region.set_navigation_mesh(nav_mesh) + + # Trigger save to disk if it is saved as an external file + if not nav_mesh.get_path().is_empty(): + ResourceSaver.save(nav_mesh, nav_mesh.get_path(), ResourceSaver.FLAG_COMPRESS) + + # Let other editor plugins and tool scripts know the nav mesh was just baked: + p_nav_region.bake_finished.emit() + + +func _postprocess_nav_mesh(p_nav_mesh: NavigationMesh) -> void: + # Post-process the nav mesh to work around Godot issue #85548 + + # Round all the vertices in the nav_mesh to the nearest cell_size/cell_height so that it doesn't + # contain any edges shorter than cell_size/cell_height (one cause of #85548). + var vertices: PackedVector3Array = _postprocess_nav_mesh_round_vertices(p_nav_mesh) + + # Rounding vertices can collapse some edges to 0 length. We remove these edges, and any polygons + # that have been reduced to 0 area. + var polygons: Array[PackedInt32Array] = _postprocess_nav_mesh_remove_empty_polygons(p_nav_mesh, vertices) + + # Another cause of #85548 is baking producing overlapping polygons. We remove these. + _postprocess_nav_mesh_remove_overlapping_polygons(p_nav_mesh, vertices, polygons) + + p_nav_mesh.clear_polygons() + p_nav_mesh.set_vertices(vertices) + for polygon in polygons: + p_nav_mesh.add_polygon(polygon) + + +func _postprocess_nav_mesh_round_vertices(p_nav_mesh: NavigationMesh) -> PackedVector3Array: + assert(p_nav_mesh != null) + assert(p_nav_mesh.cell_size > 0.0) + assert(p_nav_mesh.cell_height > 0.0) + + var cell_size: Vector3 = Vector3(p_nav_mesh.cell_size, p_nav_mesh.cell_height, p_nav_mesh.cell_size) + + # Round a little harder to avoid rounding errors with non-power-of-two cell_size/cell_height + # causing the navigation map to put two non-matching edges in the same cell: + var round_factor := cell_size * 1.001 + + var vertices: PackedVector3Array = p_nav_mesh.get_vertices() + for i in range(vertices.size()): + vertices[i] = (vertices[i] / round_factor).floor() * round_factor + return vertices + + +func _postprocess_nav_mesh_remove_empty_polygons(p_nav_mesh: NavigationMesh, p_vertices: PackedVector3Array) -> Array[PackedInt32Array]: + var polygons: Array[PackedInt32Array] = [] + + for i in range(p_nav_mesh.get_polygon_count()): + var old_polygon: PackedInt32Array = p_nav_mesh.get_polygon(i) + var new_polygon: PackedInt32Array = [] + + # Remove duplicate vertices (introduced by rounding) from the polygon: + var polygon_vertices: PackedVector3Array = [] + for index in old_polygon: + var vertex: Vector3 = p_vertices[index] + if polygon_vertices.has(vertex): + continue + polygon_vertices.push_back(vertex) + new_polygon.push_back(index) + + # If we removed some vertices, we might be able to remove the polygon too: + if new_polygon.size() <= 2: + continue + polygons.push_back(new_polygon) + + return polygons + + +func _postprocess_nav_mesh_remove_overlapping_polygons(p_nav_mesh: NavigationMesh, p_vertices: PackedVector3Array, p_polygons: Array[PackedInt32Array]) -> void: + # Occasionally, a baked nav mesh comes out with overlapping polygons: + # https://github.com/godotengine/godot/issues/85548#issuecomment-1839341071 + # Until the bug is fixed in the engine, this function attempts to detect and remove overlapping + # polygons. + + # This function has to make a choice of which polygon to remove when an overlap is detected, + # because in this case the nav mesh is ambiguous. To do this it uses a heuristic: + # (1) an 'overlap' is defined as an edge that is shared by 3 or more polygons. + # (2) a 'bad polygon' is defined as a polygon that contains 2 or more 'overlaps'. + # The function removes the 'bad polygons', which in practice seems to be enough to remove all + # overlaps without creating holes in the nav mesh. + + var cell_size: Vector3 = Vector3(p_nav_mesh.cell_size, p_nav_mesh.cell_height, p_nav_mesh.cell_size) + + # `edges` is going to map edges (vertex pairs) to arrays of polygons that contain that edge. + var edges: Dictionary = {} + + for polygon_index in range(p_polygons.size()): + var polygon: PackedInt32Array = p_polygons[polygon_index] + for j in range(polygon.size()): + var vertex: Vector3 = p_vertices[polygon[j]] + var next_vertex: Vector3 = p_vertices[polygon[(j + 1) % polygon.size()]] + + # edge_key is a key we can use in the edges dictionary that uniquely identifies the + # edge. We use cell coordinates here (Vector3i) because with a non-power-of-two + # cell_size, rounding errors can cause Vector3 vertices to not be equal. + # Array.sort IS defined for vector types - see the Godot docs. It's necessary here + # because polygons that share an edge can have their vertices in a different order. + var edge_key: Array = [Vector3i(vertex / cell_size), Vector3i(next_vertex / cell_size)] + edge_key.sort() + + if !edges.has(edge_key): + edges[edge_key] = [] + edges[edge_key].push_back(polygon_index) + + var overlap_count: Dictionary = {} + for connections in edges.values(): + if connections.size() <= 2: + continue + for polygon_index in connections: + overlap_count[polygon_index] = overlap_count.get(polygon_index, 0) + 1 + + var bad_polygons: Array = [] + for polygon_index in overlap_count.keys(): + if overlap_count[polygon_index] >= 2: + bad_polygons.push_back(polygon_index) + + bad_polygons.sort() + for i in range(bad_polygons.size() - 1, -1, -1): + p_polygons.remove_at(bad_polygons[i]) + + +func set_up_navigation_popup() -> void: + if plugin.terrain: + bake_method = _set_up_navigation + confirm_dialog.dialog_text = SET_UP_NAVIGATION_DESCRIPTION + EditorInterface.popup_dialog_centered(confirm_dialog) + + +func _set_up_navigation() -> void: + assert(plugin.terrain) + if plugin.terrain == EditorInterface.get_edited_scene_root(): + push_error("Terrain3D Navigation setup not possible if Terrain3D node is scene root") + return + if plugin.terrain.data.get_region_count() == 0: + push_error("Terrain3D has no active regions") + return + var terrain: Terrain3D = plugin.terrain + + var nav_region := NavigationRegion3D.new() + nav_region.name = &"NavigationRegion3D" + nav_region.navigation_mesh = NavigationMesh.new() + + var undo_redo: EditorUndoRedoManager = plugin.get_undo_redo() + + undo_redo.create_action("Terrain3D Set up Navigation") + undo_redo.add_do_method(self, &"_do_set_up_navigation", nav_region, terrain) + undo_redo.add_undo_method(self, &"_undo_set_up_navigation", nav_region, terrain) + undo_redo.add_do_reference(nav_region) + undo_redo.commit_action() + + EditorInterface.inspect_object(nav_region) + assert(plugin.nav_region == nav_region) + + bake_nav_mesh() + + +func _do_set_up_navigation(p_nav_region: NavigationRegion3D, p_terrain: Terrain3D) -> void: + var parent: Node = p_terrain.get_parent() + var index: int = p_terrain.get_index() + var t_owner: Node = p_terrain.owner + + parent.add_child(p_nav_region, true) + p_terrain.reparent(p_nav_region) + parent.move_child(p_nav_region, index) + + p_nav_region.owner = t_owner + p_terrain.owner = t_owner + + +func _undo_set_up_navigation(p_nav_region: NavigationRegion3D, p_terrain: Terrain3D) -> void: + assert(p_terrain.get_parent() == p_nav_region) + + var parent: Node = p_nav_region.get_parent() + var index: int = p_nav_region.get_index() + var t_owner: Node = p_nav_region.get_owner() + + p_terrain.reparent(parent) + parent.remove_child(p_nav_region) + parent.move_child(p_terrain, index) + + p_terrain.owner = t_owner diff --git a/addons/terrain_3d/menu/baker.gd.uid b/addons/terrain_3d/menu/baker.gd.uid new file mode 100644 index 0000000..0f2ed94 --- /dev/null +++ b/addons/terrain_3d/menu/baker.gd.uid @@ -0,0 +1 @@ +uid://4ulaeevj5jvi diff --git a/addons/terrain_3d/menu/channel_packer.gd b/addons/terrain_3d/menu/channel_packer.gd new file mode 100644 index 0000000..24fb5a8 --- /dev/null +++ b/addons/terrain_3d/menu/channel_packer.gd @@ -0,0 +1,465 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Channel Packer for Terrain3D +extends RefCounted + +const WINDOW_SCENE: String = "res://addons/terrain_3d/menu/channel_packer.tscn" +const TEMPLATE_PATH: String = "res://addons/terrain_3d/menu/channel_packer_import_template.txt" +const DRAG_DROP_SCRIPT: String = "res://addons/terrain_3d/menu/channel_packer_dragdrop.gd" +enum { + INFO, + WARN, + ERROR, +} + +enum { + IMAGE_ALBEDO, + IMAGE_HEIGHT, + IMAGE_NORMAL, + IMAGE_ROUGHNESS +} + +var plugin: EditorPlugin +var window: Window +var save_file_dialog: EditorFileDialog +var open_file_dialog: EditorFileDialog +var invert_green_checkbox: CheckBox +var invert_smooth_checkbox: CheckBox +var invert_height_checkbox: CheckBox +var normalize_height_checkbox: CheckBox +var lumin_height_button: Button +var generate_mipmaps_checkbox: CheckBox +var high_quality_checkbox: CheckBox +var align_normals_checkbox: CheckBox +var resize_toggle_checkbox: CheckBox +var resize_option_box: SpinBox +var height_channel: Array[Button] +var height_channel_selected: int = 0 +var roughness_channel: Array[Button] +var roughness_channel_selected: int = 0 +var last_opened_directory: String +var last_saved_directory: String +var packing_albedo: bool = false +var queue_pack_normal_roughness: bool = false +var images: Array[Image] = [null, null, null, null] +var status_label: Label +var no_op: Callable = func(): pass +var last_file_selected_fn: Callable = no_op +var normal_vector: Vector3 + + +func pack_textures_popup() -> void: + if window != null: + window.show() + window.grab_focus() + window.move_to_center() + return + window = (load(WINDOW_SCENE) as PackedScene).instantiate() + window.close_requested.connect(_on_close_requested) + window.window_input.connect(func(event:InputEvent): + if event is InputEventKey: + if event.pressed and event.keycode == KEY_ESCAPE: + _on_close_requested() + ) + window.find_child("CloseButton").pressed.connect(_on_close_requested) + + status_label = window.find_child("StatusLabel") as Label + invert_green_checkbox = window.find_child("InvertGreenChannelCheckBox") as CheckBox + invert_smooth_checkbox = window.find_child("InvertSmoothCheckBox") as CheckBox + invert_height_checkbox = window.find_child("ConvertDepthToHeight") as CheckBox + normalize_height_checkbox = window.find_child("NormalizeHeight") as CheckBox + lumin_height_button = window.find_child("LuminanceAsHeightButton") as Button + generate_mipmaps_checkbox = window.find_child("GenerateMipmapsCheckBox") as CheckBox + high_quality_checkbox = window.find_child("HighQualityCheckBox") as CheckBox + align_normals_checkbox = window.find_child("AlignNormalsCheckBox") as CheckBox + resize_toggle_checkbox = window.find_child("ResizeToggle") as CheckBox + resize_option_box = window.find_child("ResizeOptionButton") as SpinBox + height_channel = [ + window.find_child("HeightChannelR") as Button, + window.find_child("HeightChannelG") as Button, + window.find_child("HeightChannelB") as Button, + window.find_child("HeightChannelA") as Button + ] + roughness_channel = [ + window.find_child("RoughnessChannelR") as Button, + window.find_child("RoughnessChannelG") as Button, + window.find_child("RoughnessChannelB") as Button, + window.find_child("RoughnessChannelA") as Button + ] + + height_channel[0].pressed.connect(func() -> void: height_channel_selected = 0) + height_channel[1].pressed.connect(func() -> void: height_channel_selected = 1) + height_channel[2].pressed.connect(func() -> void: height_channel_selected = 2) + height_channel[3].pressed.connect(func() -> void: height_channel_selected = 3) + + roughness_channel[0].pressed.connect(func() -> void: roughness_channel_selected = 0) + roughness_channel[1].pressed.connect(func() -> void: roughness_channel_selected = 1) + roughness_channel[2].pressed.connect(func() -> void: roughness_channel_selected = 2) + roughness_channel[3].pressed.connect(func() -> void: roughness_channel_selected = 3) + + plugin.add_child(window) + _init_file_dialogs() + + # the dialog disables the parent window "on top" so, restore it after 1 frame to alow the dialog to clear. + var set_on_top_fn: Callable = func(_file: String = "") -> void: + await RenderingServer.frame_post_draw + window.always_on_top = true + save_file_dialog.file_selected.connect(set_on_top_fn) + save_file_dialog.canceled.connect(set_on_top_fn) + open_file_dialog.file_selected.connect(set_on_top_fn) + open_file_dialog.canceled.connect(set_on_top_fn) + + _init_texture_picker(window.find_child("AlbedoVBox"), IMAGE_ALBEDO) + _init_texture_picker(window.find_child("HeightVBox"), IMAGE_HEIGHT) + _init_texture_picker(window.find_child("NormalVBox"), IMAGE_NORMAL) + _init_texture_picker(window.find_child("RoughnessVBox"), IMAGE_ROUGHNESS) + + (window.find_child("PackButton") as Button).pressed.connect(_on_pack_button_pressed) + + +func _on_close_requested() -> void: + last_file_selected_fn = no_op + images = [null, null, null, null] + window.queue_free() + window = null + + +func _init_file_dialogs() -> void: + save_file_dialog = EditorFileDialog.new() + save_file_dialog.set_filters(PackedStringArray(["*.png"])) + save_file_dialog.set_file_mode(EditorFileDialog.FILE_MODE_SAVE_FILE) + save_file_dialog.access = EditorFileDialog.ACCESS_FILESYSTEM + save_file_dialog.file_selected.connect(_on_save_file_selected) + save_file_dialog.ok_button_text = "Save" + save_file_dialog.size = Vector2i(550, 550) + #save_file_dialog.transient = false + #save_file_dialog.exclusive = false + #save_file_dialog.popup_window = true + + open_file_dialog = EditorFileDialog.new() + open_file_dialog.set_filters(PackedStringArray( + ["*.png", "*.bmp", "*.exr", "*.hdr", "*.jpg", "*.jpeg", "*.tga", "*.svg", "*.webp", "*.ktx", "*.dds"])) + open_file_dialog.set_file_mode(EditorFileDialog.FILE_MODE_OPEN_FILE) + open_file_dialog.access = EditorFileDialog.ACCESS_FILESYSTEM + open_file_dialog.ok_button_text = "Open" + open_file_dialog.size = Vector2i(550, 550) + #open_file_dialog.transient = false + #open_file_dialog.exclusive = false + #open_file_dialog.popup_window = true + + window.add_child(save_file_dialog) + window.add_child(open_file_dialog) + + +func _init_texture_picker(p_parent: Node, p_image_index: int) -> void: + var line_edit: LineEdit = p_parent.find_child("LineEdit") as LineEdit + var file_pick_button: Button = p_parent.find_child("PickButton") as Button + var clear_button: Button = p_parent.find_child("ClearButton") as Button + var texture_rect: TextureRect = p_parent.find_child("TextureRect") as TextureRect + var texture_button: Button = p_parent.find_child("TextureButton") as Button + texture_button.set_script(load(DRAG_DROP_SCRIPT) as GDScript) + + var set_channel_fn: Callable = func(used_channels: int) -> void: + var channel_count: int = 4 + # enum Image.UsedChannels + match used_channels: + Image.USED_CHANNELS_L, Image.USED_CHANNELS_R: channel_count = 1 + Image.USED_CHANNELS_LA, Image.USED_CHANNELS_RG: channel_count = 2 + Image.USED_CHANNELS_RGB: channel_count = 3 + Image.USED_CHANNELS_RGBA: channel_count = 4 + if p_image_index == IMAGE_HEIGHT: + for i in 4: + height_channel[i].visible = i < channel_count + height_channel[0].button_pressed = true + height_channel[0].pressed.emit() + elif p_image_index == IMAGE_ROUGHNESS: + for i in 4: + roughness_channel[i].visible = i < channel_count + roughness_channel[0].button_pressed = true + roughness_channel[0].pressed.emit() + + var load_image_fn: Callable = func(path: String): + var image: Image = Image.new() + var error: int = OK + # Special case for dds files + if path.get_extension() == "dds": + image = ResourceLoader.load(path).get_image() + if not image.is_empty(): + # if the dds file is loaded, we must clear any mipmaps and + # decompress if needed in order to do per pixel operations. + image.clear_mipmaps() + image.decompress() + else: + error = FAILED + else: + error = image.load(path) + if error != OK: + _show_message(ERROR, "Failed to load texture '" + path + "'") + texture_rect.texture = null + images[p_image_index] = null + else: + _show_message(INFO, "Loaded texture '" + path + "'") + texture_rect.texture = ImageTexture.create_from_image(image) + images[p_image_index] = image + _set_wh_labels(p_image_index, image.get_width(), image.get_height()) + if p_image_index == IMAGE_NORMAL: + _set_normal_vector(image) + if p_image_index == IMAGE_HEIGHT or p_image_index == IMAGE_ROUGHNESS: + set_channel_fn.call(image.detect_used_channels()) + + var os_drop_fn: Callable = func(files: PackedStringArray) -> void: + # OS drag drop holds mouse focus until released, + # Get mouse pos and check directly if inside texture_rect + var rect = texture_button.get_global_rect() + var mouse_position = texture_button.get_global_mouse_position() + if rect.has_point(mouse_position): + if files.size() != 1: + _show_message(ERROR, "Cannot load multiple files") + else: + line_edit.text = files[0] + load_image_fn.call(files[0]) + + var godot_drop_fn: Callable = func(path: String) -> void: + path = ProjectSettings.globalize_path(path) + line_edit.text = path + load_image_fn.call(path) + + var open_fn: Callable = func() -> void: + open_file_dialog.current_path = last_opened_directory + if last_file_selected_fn != no_op: + open_file_dialog.file_selected.disconnect(last_file_selected_fn) + last_file_selected_fn = func(path: String) -> void: + line_edit.text = path + load_image_fn.call(path) + open_file_dialog.file_selected.connect(last_file_selected_fn) + open_file_dialog.popup_centered_ratio() + + var line_edit_submit_fn: Callable = func(path: String) -> void: + line_edit.text = path + load_image_fn.call(path) + + var clear_fn: Callable = func() -> void: + line_edit.text = "" + texture_rect.texture = null + images[p_image_index] = null + _set_wh_labels(p_image_index, -1, -1) + + line_edit.text_submitted.connect(line_edit_submit_fn) + file_pick_button.pressed.connect(open_fn) + texture_button.pressed.connect(open_fn) + clear_button.pressed.connect(clear_fn) + texture_button.dropped.connect(godot_drop_fn) + window.files_dropped.connect(os_drop_fn) + + if p_image_index == IMAGE_HEIGHT: + var lumin_fn: Callable = func() -> void: + if !images[IMAGE_ALBEDO]: + _show_message(ERROR, "Albedo Image Required for Operation") + else: + line_edit.text = "Generated Height" + var height_texture: Image = Terrain3DUtil.luminance_to_height(images[IMAGE_ALBEDO]) + if height_texture.is_empty(): + _show_message(ERROR, "Height Texture Generation error") + # blur the image by resizing down and back.. + var w: int = height_texture.get_width() + var h: int = height_texture.get_height() + height_texture.resize(w / 4, h / 4) + height_texture.resize(w, h, Image.INTERPOLATE_CUBIC) + # "Load" the height texture + images[IMAGE_HEIGHT] = height_texture + texture_rect.texture = ImageTexture.create_from_image(images[IMAGE_HEIGHT]) + _set_wh_labels(IMAGE_HEIGHT, height_texture.get_width(), height_texture.get_height()) + set_channel_fn.call(Image.USED_CHANNELS_R) + _show_message(INFO, "Height Texture generated sucsessfully") + lumin_height_button.pressed.connect(lumin_fn) + plugin.ui.set_button_editor_icon(file_pick_button, "Folder") + plugin.ui.set_button_editor_icon(clear_button, "Remove") + + +func _set_wh_labels(p_image_index: int, width: int, height: int) -> void: + var w: String = "" + var h: String = "" + if width > 0 and height > 0: + w = "w: " + str(width) + h = "h: " + str(height) + match p_image_index: + 0: + window.find_child("AlbedoW").text = w + window.find_child("AlbedoH").text = h + 1: + window.find_child("HeightW").text = w + window.find_child("HeightH").text = h + 2: + window.find_child("NormalW").text = w + window.find_child("NormalH").text = h + 3: + window.find_child("RoughnessW").text = w + window.find_child("RoughnessH").text = h + + +func _show_message(p_level: int, p_text: String) -> void: + status_label.text = p_text + match p_level: + INFO: + print("Terrain3DChannelPacker: " + p_text) + status_label.add_theme_color_override("font_color", Color(0, 0.82, 0.14)) + WARN: + push_warning("Terrain3DChannelPacker: " + p_text) + status_label.add_theme_color_override("font_color", Color(0.9, 0.9, 0)) + ERROR,_: + push_error("Terrain3DChannelPacker: " + p_text) + status_label.add_theme_color_override("font_color", Color(0.9, 0, 0)) + + +func _create_import_file(png_path: String) -> void: + var dst_import_path: String = png_path + ".import" + var file: FileAccess = FileAccess.open(TEMPLATE_PATH, FileAccess.READ) + var template_content: String = file.get_as_text() + file.close() + template_content = template_content.replace( + "$SOURCE_FILE", png_path).replace( + "$HIGH_QUALITY", str(high_quality_checkbox.button_pressed)).replace( + "$GENERATE_MIPMAPS", str(generate_mipmaps_checkbox.button_pressed) + ) + var import_content: String = template_content + file = FileAccess.open(dst_import_path, FileAccess.WRITE) + file.store_string(import_content) + file.close() + + +func _on_pack_button_pressed() -> void: + packing_albedo = images[IMAGE_ALBEDO] != null and images[IMAGE_HEIGHT] != null + var packing_normal_roughness: bool = images[IMAGE_NORMAL] != null and images[IMAGE_ROUGHNESS] != null + + if not packing_albedo and not packing_normal_roughness: + _show_message(WARN, "Please select an albedo and height texture or a normal and roughness texture") + return + if packing_albedo: + save_file_dialog.current_path = last_saved_directory + "packed_albedo_height" + save_file_dialog.title = "Save Packed Albedo/Height Texture" + save_file_dialog.popup_centered_ratio() + if packing_normal_roughness: + queue_pack_normal_roughness = true + return + if packing_normal_roughness: + save_file_dialog.current_path = last_saved_directory + "packed_normal_roughness" + save_file_dialog.title = "Save Packed Normal/Roughness Texture" + save_file_dialog.popup_centered_ratio() + + +func _on_save_file_selected(p_dst_path) -> void: + last_saved_directory = p_dst_path.get_base_dir() + "/" + var error: int + if packing_albedo: + error = _pack_textures(images[IMAGE_ALBEDO], images[IMAGE_HEIGHT], p_dst_path, false, + invert_height_checkbox.button_pressed, false, normalize_height_checkbox.button_pressed, height_channel_selected) + else: + error = _pack_textures(images[IMAGE_NORMAL], images[IMAGE_ROUGHNESS], p_dst_path, + invert_green_checkbox.button_pressed, invert_smooth_checkbox.button_pressed, + align_normals_checkbox.button_pressed, false, roughness_channel_selected) + + if error == OK: + EditorInterface.get_resource_filesystem().scan() + if window.visible: + window.hide() + await EditorInterface.get_resource_filesystem().resources_reimported + # wait 1 extra frame, to ensure the UI is responsive. + await RenderingServer.frame_post_draw + window.show() + + if queue_pack_normal_roughness: + queue_pack_normal_roughness = false + packing_albedo = false + save_file_dialog.current_path = last_saved_directory + "packed_normal_roughness" + save_file_dialog.title = "Save Packed Normal/Roughness Texture" + + save_file_dialog.call_deferred("popup_centered_ratio") + save_file_dialog.call_deferred("grab_focus") + + +func _alignment_basis(normal: Vector3) -> Basis: + var up: Vector3 = Vector3(0, 0, 1) + var v: Vector3 = normal.cross(up) + var c: float = normal.dot(up) + var k: float = 1.0 / (1.0 + c) + + var vxy: float = v.x * v.y * k + var vxz: float = v.x * v.z * k + var vyz: float = v.y * v.z * k + + return Basis(Vector3(v.x * v.x * k + c, vxy - v.z, vxz + v.y), + Vector3(vxy + v.z, v.y * v.y * k + c, vyz - v.x), + Vector3(vxz - v.y, vyz + v.x, v.z * v.z * k + c) + ) + + +func _set_normal_vector(source: Image, quiet: bool = false) -> void: + # Calculate texture normal sum direction + var normal: Image = source + var sum: Color = Color(0.0, 0.0, 0.0, 0.0) + for x in normal.get_width(): + for y in normal.get_height(): + sum += normal.get_pixel(x, y) + var div: float = normal.get_height() * normal.get_width() + sum /= Color(div, div, div) + sum *= 2.0 + sum -= Color(1.0, 1.0, 1.0) + normal_vector = Vector3(sum.r, sum.g, sum.b).normalized() + if normal_vector.dot(Vector3(0.0, 0.0, 1.0)) < 0.999 && !quiet: + _show_message(WARN, "Normal Texture Not Orthoganol to UV plane.\nFor Compatability with Detiling and Rotation, Select Orthoganolize Normals") + + +func _align_normals(source: Image, iteration: int = 0) -> void: + # generate matrix to re-align the normalmap + var mat3: Basis = _alignment_basis(normal_vector) + # re-align the normal map pixels + for x in source.get_width(): + for y in source.get_height(): + var old_pixel: Color = source.get_pixel(x, y) + var vector_pixel: Vector3 = Vector3(old_pixel.r, old_pixel.g, old_pixel.b) + vector_pixel *= 2.0 + vector_pixel -= Vector3.ONE + vector_pixel = vector_pixel.normalized() + vector_pixel = vector_pixel * mat3 + vector_pixel += Vector3.ONE + vector_pixel *= 0.5 + var new_pixel: Color = Color(vector_pixel.x, vector_pixel.y, vector_pixel.z, old_pixel.a) + source.set_pixel(x, y, new_pixel) + _set_normal_vector(source, true) + if normal_vector.dot(Vector3(0.0, 0.0, 1.0)) < 0.999 && iteration < 3: + ++iteration + _align_normals(source, iteration) + + +func _pack_textures(p_rgb_image: Image, p_a_image: Image, p_dst_path: String, p_invert_green: bool, + p_invert_smooth: bool, p_align_normals: bool, p_normalize_height: bool, p_alpha_channel: int) -> Error: + if p_rgb_image and p_a_image: + if p_rgb_image.get_size() != p_a_image.get_size() and !resize_toggle_checkbox.button_pressed: + _show_message(ERROR, "Textures must be the same size.\nEnable resize to override image dimensions") + return FAILED + + if resize_toggle_checkbox.button_pressed: + var size: int = max(128, resize_option_box.value) + p_rgb_image.resize(size, size, Image.INTERPOLATE_CUBIC) + p_a_image.resize(size, size, Image.INTERPOLATE_CUBIC) + + if p_align_normals and normal_vector.dot(Vector3(0.0, 0.0, 1.0)) < 0.999: + _align_normals(p_rgb_image) + elif p_align_normals: + _show_message(INFO, "Alignment OK, skipping Normal Orthogonalization") + + var output_image: Image = Terrain3DUtil.pack_image(p_rgb_image, p_a_image, + p_invert_green, p_invert_smooth, p_normalize_height, p_alpha_channel) + + if not output_image: + _show_message(ERROR, "Failed to pack textures") + return FAILED + if output_image.detect_alpha() != Image.ALPHA_BLEND: + _show_message(WARN, "Warning, Alpha channel empty") + + output_image.save_png(p_dst_path) + _create_import_file(p_dst_path) + _show_message(INFO, "Packed to " + p_dst_path + ".") + return OK + else: + _show_message(ERROR, "Failed to load one or more textures") + return FAILED diff --git a/addons/terrain_3d/menu/channel_packer.gd.uid b/addons/terrain_3d/menu/channel_packer.gd.uid new file mode 100644 index 0000000..564c78d --- /dev/null +++ b/addons/terrain_3d/menu/channel_packer.gd.uid @@ -0,0 +1 @@ +uid://bwldx4itd58o7 diff --git a/addons/terrain_3d/menu/channel_packer.tscn b/addons/terrain_3d/menu/channel_packer.tscn new file mode 100644 index 0000000..fe0f80a --- /dev/null +++ b/addons/terrain_3d/menu/channel_packer.tscn @@ -0,0 +1,539 @@ +[gd_scene load_steps=7 format=3 uid="uid://nud6dwjcnj5v"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ysabf"] +bg_color = Color(0.211765, 0.239216, 0.290196, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lcvna"] +bg_color = Color(0.168627, 0.211765, 0.266667, 1) +border_width_left = 3 +border_width_top = 3 +border_width_right = 3 +border_width_bottom = 3 +border_color = Color(0.270588, 0.435294, 0.580392, 1) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cb0xf"] +bg_color = Color(0.137255, 0.137255, 0.137255, 1) +draw_center = false +border_width_left = 3 +border_width_top = 3 +border_width_right = 3 +border_width_bottom = 3 +border_color = Color(0.784314, 0.784314, 0.784314, 1) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_7qdas"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_wnxik"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_bs6ki"] + +[node name="Window" type="Window"] +title = "Terrain3D Channel Packer" +initial_position = 1 +size = Vector2i(583, 891) +wrap_controls = true +always_on_top = true + +[node name="PanelContainer" type="PanelContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_ysabf") + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 5 +theme_override_constants/margin_top = 5 +theme_override_constants/margin_right = 5 +theme_override_constants/margin_bottom = 5 + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="AlbedoHeightPanel" type="PanelContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_lcvna") + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel"] +layout_mode = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer"] +layout_mode = 2 + +[node name="AlbedoVBox" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="AlbedoLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox"] +layout_mode = 2 +text = "Albedo texture" + +[node name="AlbedoHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/AlbedoHBox"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="PickButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/AlbedoHBox"] +layout_mode = 2 + +[node name="ClearButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/AlbedoHBox"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox"] +layout_mode = 2 +size_flags_vertical = 4 +theme_override_constants/margin_top = 10 + +[node name="Panel" type="Panel" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/MarginContainer"] +custom_minimum_size = Vector2(110, 110) +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +theme_override_styles/panel = SubResource("StyleBoxFlat_cb0xf") + +[node name="TextureRect" type="TextureRect" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -50.0 +offset_top = -50.0 +offset_right = 50.0 +offset_bottom = 50.0 +grow_horizontal = 2 +grow_vertical = 2 +expand_mode = 1 + +[node name="TextureButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/normal = SubResource("StyleBoxEmpty_7qdas") + +[node name="AlbedoWHHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox"] +layout_mode = 2 +alignment = 1 + +[node name="AlbedoW" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/AlbedoWHHBox"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="AlbedoH" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/AlbedoWHHBox"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="HBoxContainer2" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox"] +layout_mode = 2 +alignment = 1 + +[node name="LuminanceAsHeightButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/AlbedoVBox/HBoxContainer2"] +layout_mode = 2 +text = " Generate Height from Luminance" +icon_alignment = 2 + +[node name="HeightVBox" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HeightLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox"] +layout_mode = 2 +text = "Height texture" + +[node name="HeightHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HeightHBox"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="PickButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HeightHBox"] +layout_mode = 2 + +[node name="ClearButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HeightHBox"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox"] +layout_mode = 2 +size_flags_vertical = 4 +theme_override_constants/margin_top = 10 + +[node name="Panel" type="Panel" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/MarginContainer"] +custom_minimum_size = Vector2(110, 110) +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +theme_override_styles/panel = SubResource("StyleBoxFlat_cb0xf") + +[node name="TextureRect" type="TextureRect" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -50.0 +offset_top = -50.0 +offset_right = 50.0 +offset_bottom = 50.0 +grow_horizontal = 2 +grow_vertical = 2 +expand_mode = 1 + +[node name="TextureButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/normal = SubResource("StyleBoxEmpty_7qdas") + +[node name="HeightWHHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox"] +layout_mode = 2 +alignment = 1 + +[node name="HeightW" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HeightWHHBox"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="HeightH" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HeightWHHBox"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="HBoxContainer2" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox"] +layout_mode = 2 +alignment = 1 + +[node name="ConvertDepthToHeight" type="CheckBox" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HBoxContainer2"] +layout_mode = 2 +text = " Convert Depth to Height" +icon_alignment = 2 + +[node name="HBoxContainer3" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox"] +layout_mode = 2 +alignment = 1 + +[node name="NormalizeHeight" type="CheckBox" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HBoxContainer3"] +layout_mode = 2 +text = "Normalize Height" +icon_alignment = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox"] +layout_mode = 2 +alignment = 1 + +[node name="HeightChannelLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HBoxContainer"] +layout_mode = 2 +text = " Source Channel: " +horizontal_alignment = 2 + +[node name="HeightChannelR" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HBoxContainer"] +layout_mode = 2 +toggle_mode = true +button_pressed = true +button_group = SubResource("ButtonGroup_wnxik") +text = "R" + +[node name="HeightChannelB" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HBoxContainer"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_wnxik") +text = "G" + +[node name="HeightChannelG" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HBoxContainer"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_wnxik") +text = "B" + +[node name="HeightChannelA" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/AlbedoHeightPanel/MarginContainer/HBoxContainer/HeightVBox/HBoxContainer"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_wnxik") +text = "A" + +[node name="NormalRoughnessPanel" type="PanelContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_lcvna") + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel"] +layout_mode = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer"] +layout_mode = 2 + +[node name="NormalVBox" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="NormalLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox"] +layout_mode = 2 +text = "Normal texture" + +[node name="NormalHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/NormalHBox"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="PickButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/NormalHBox"] +layout_mode = 2 + +[node name="ClearButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/NormalHBox"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox"] +layout_mode = 2 +size_flags_vertical = 4 +theme_override_constants/margin_top = 10 + +[node name="Panel" type="Panel" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/MarginContainer"] +custom_minimum_size = Vector2(110, 110) +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +theme_override_styles/panel = SubResource("StyleBoxFlat_cb0xf") + +[node name="TextureRect" type="TextureRect" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -50.0 +offset_top = -50.0 +offset_right = 50.0 +offset_bottom = 50.0 +grow_horizontal = 2 +grow_vertical = 2 +expand_mode = 1 + +[node name="TextureButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/normal = SubResource("StyleBoxEmpty_7qdas") + +[node name="NormalWHHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox"] +layout_mode = 2 +alignment = 1 + +[node name="NormalW" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/NormalWHHBox"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="NormalH" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/NormalWHHBox"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox"] +layout_mode = 2 +alignment = 1 + +[node name="InvertGreenChannelCheckBox" type="CheckBox" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/HBoxContainer"] +layout_mode = 2 +text = " Convert DirectX to OpenGL" + +[node name="HBoxContainer2" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox"] +layout_mode = 2 +alignment = 1 + +[node name="AlignNormalsCheckBox" type="CheckBox" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/NormalVBox/HBoxContainer2"] +layout_mode = 2 +text = " Orthoganolise Normals" + +[node name="RoughnessVBox" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="RoughnessLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox"] +layout_mode = 2 +text = "Roughness texture" + +[node name="RoughnessHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/RoughnessHBox"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="PickButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/RoughnessHBox"] +layout_mode = 2 + +[node name="ClearButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/RoughnessHBox"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox"] +layout_mode = 2 +size_flags_vertical = 4 +theme_override_constants/margin_top = 10 + +[node name="Panel" type="Panel" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/MarginContainer"] +custom_minimum_size = Vector2(110, 110) +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +theme_override_styles/panel = SubResource("StyleBoxFlat_cb0xf") + +[node name="TextureRect" type="TextureRect" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -50.0 +offset_top = -50.0 +offset_right = 50.0 +offset_bottom = 50.0 +grow_horizontal = 2 +grow_vertical = 2 +expand_mode = 1 + +[node name="TextureButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/normal = SubResource("StyleBoxEmpty_7qdas") + +[node name="RoughnessWHHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox"] +layout_mode = 2 +alignment = 1 + +[node name="RoughnessW" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/RoughnessWHHBox"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="RoughnessH" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/RoughnessWHHBox"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="HBoxContainer2" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox"] +layout_mode = 2 +alignment = 1 + +[node name="InvertSmoothCheckBox" type="CheckBox" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/HBoxContainer2"] +layout_mode = 2 +text = " Convert Smoothness to Roughness" + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox"] +layout_mode = 2 +alignment = 1 + +[node name="RoughnessChannelLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/HBoxContainer"] +layout_mode = 2 +text = " Source Channel: " +horizontal_alignment = 2 + +[node name="RoughnessChannelR" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/HBoxContainer"] +layout_mode = 2 +toggle_mode = true +button_pressed = true +button_group = SubResource("ButtonGroup_bs6ki") +text = "R" + +[node name="RoughnessChannelG" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/HBoxContainer"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_bs6ki") +text = "G" + +[node name="RoughnessChannelB" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/HBoxContainer"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_bs6ki") +text = "B" + +[node name="RoughnessChannelA" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/NormalRoughnessPanel/MarginContainer/HBoxContainer/RoughnessVBox/HBoxContainer"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_bs6ki") +text = "A" + +[node name="GeneralOptionsLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "General Options" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="GeneralOptionsHBox" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="ResizeToggle" type="CheckBox" parent="PanelContainer/MarginContainer/VBoxContainer/GeneralOptionsHBox"] +layout_mode = 2 +text = " Resize Packed Image" + +[node name="ResizeOptionButton" type="SpinBox" parent="PanelContainer/MarginContainer/VBoxContainer/GeneralOptionsHBox"] +visible = false +layout_mode = 2 +tooltip_text = "A value of 0 disables resizing." +min_value = 128.0 +max_value = 4096.0 +step = 128.0 +value = 1024.0 + +[node name="VSeparator" type="VSeparator" parent="PanelContainer/MarginContainer/VBoxContainer/GeneralOptionsHBox"] +layout_mode = 2 + +[node name="GenerateMipmapsCheckBox" type="CheckBox" parent="PanelContainer/MarginContainer/VBoxContainer/GeneralOptionsHBox"] +layout_mode = 2 +button_pressed = true +text = "Generate Mipmaps" + +[node name="HighQualityCheckBox" type="CheckBox" parent="PanelContainer/MarginContainer/VBoxContainer/GeneralOptionsHBox"] +layout_mode = 2 +text = "Import High Quality" + +[node name="PackButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Pack textures as..." + +[node name="StatusLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 60) +layout_mode = 2 +horizontal_alignment = 1 +autowrap_mode = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="CloseButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Close" + +[connection signal="toggled" from="PanelContainer/MarginContainer/VBoxContainer/GeneralOptionsHBox/ResizeToggle" to="PanelContainer/MarginContainer/VBoxContainer/GeneralOptionsHBox/ResizeOptionButton" method="set_visible"] diff --git a/addons/terrain_3d/menu/channel_packer_dragdrop.gd b/addons/terrain_3d/menu/channel_packer_dragdrop.gd new file mode 100644 index 0000000..154c8ad --- /dev/null +++ b/addons/terrain_3d/menu/channel_packer_dragdrop.gd @@ -0,0 +1,17 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Channel Packer Dragdropper for Terrain3D +@tool +extends Button + +signal dropped + +func _can_drop_data(p_position, p_data) -> bool: + if typeof(p_data) == TYPE_DICTIONARY: + if p_data.files.size() == 1: + match p_data.files[0].get_extension(): + "png", "bmp", "exr", "hdr", "jpg", "jpeg", "tga", "svg", "webp", "ktx", "dds": + return true + return false + +func _drop_data(p_position, p_data) -> void: + dropped.emit(p_data.files[0]) diff --git a/addons/terrain_3d/menu/channel_packer_dragdrop.gd.uid b/addons/terrain_3d/menu/channel_packer_dragdrop.gd.uid new file mode 100644 index 0000000..d9a59e3 --- /dev/null +++ b/addons/terrain_3d/menu/channel_packer_dragdrop.gd.uid @@ -0,0 +1 @@ +uid://br45krrqbw8bg diff --git a/addons/terrain_3d/menu/channel_packer_import_template.txt b/addons/terrain_3d/menu/channel_packer_import_template.txt new file mode 100644 index 0000000..55003e3 --- /dev/null +++ b/addons/terrain_3d/menu/channel_packer_import_template.txt @@ -0,0 +1,32 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="$SOURCE_FILE" + +[params] + +compress/mode=2 +compress/high_quality=$HIGH_QUALITY +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=$GENERATE_MIPMAPS +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/terrain_3d/menu/directory_setup.gd b/addons/terrain_3d/menu/directory_setup.gd new file mode 100644 index 0000000..b851747 --- /dev/null +++ b/addons/terrain_3d/menu/directory_setup.gd @@ -0,0 +1,86 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Directory Setup for Terrain3D +extends Node + +const DIRECTORY_SETUP: String = "res://addons/terrain_3d/menu/directory_setup.tscn" + +var plugin: EditorPlugin +var dialog: ConfirmationDialog +var select_dir_btn: Button +var selected_dir_le: LineEdit +var editor_file_dialog: EditorFileDialog + + +func _init() -> void: + editor_file_dialog = EditorFileDialog.new() + editor_file_dialog.set_filters(PackedStringArray(["*.res"])) + editor_file_dialog.set_file_mode(EditorFileDialog.FILE_MODE_SAVE_FILE) + editor_file_dialog.access = EditorFileDialog.ACCESS_RESOURCES + editor_file_dialog.ok_button_text = "Open" + editor_file_dialog.title = "Open a folder or file" + editor_file_dialog.dir_selected.connect(_on_dir_selected) + editor_file_dialog.size = Vector2i(850, 550) + editor_file_dialog.transient = false + editor_file_dialog.exclusive = false + editor_file_dialog.popup_window = true + add_child(editor_file_dialog) + + +func directory_setup_popup() -> void: + dialog = load(DIRECTORY_SETUP).instantiate() + dialog.hide() + + # Nodes + select_dir_btn = dialog.get_node("Margin/VBox/DirHBox/SelectDir") + selected_dir_le = dialog.get_node("Margin/VBox/DirHBox/LineEdit") + + if plugin.terrain.data_directory: + selected_dir_le.text = plugin.terrain.data_directory + + # Icons + plugin.ui.set_button_editor_icon(select_dir_btn, "Folder") + + #Signals + select_dir_btn.pressed.connect(_on_select_file_pressed.bind(EditorFileDialog.FILE_MODE_OPEN_DIR)) + dialog.confirmed.connect(_on_close_requested) + dialog.canceled.connect(_on_close_requested) + dialog.get_ok_button().pressed.connect(_on_ok_pressed) + + # Popup + EditorInterface.popup_dialog_centered(dialog) + + +func _on_close_requested() -> void: + dialog.queue_free() + dialog = null + + +func _on_select_file_pressed(file_mode: EditorFileDialog.FileMode) -> void: + editor_file_dialog.file_mode = file_mode + editor_file_dialog.popup_centered() + + +func _on_dir_selected(path: String) -> void: + selected_dir_le.text = path + + +func _on_ok_pressed() -> void: + if not plugin.terrain: + push_error("Not connected terrain. Click the Terrain3D node first") + return + if selected_dir_le.text.is_empty(): + push_error("No data directory specified") + return + if not DirAccess.dir_exists_absolute(selected_dir_le.text): + push_error("Directory doesn't exist: ", selected_dir_le.text) + return + # Check if directory empty of terrain files + var data_found: bool = false + var files: Array = DirAccess.get_files_at(selected_dir_le.text) + for file in files: + if file.begins_with("terrain3d") || file.ends_with(".res"): + data_found = true + break + + print("Setting terrain directory: ", selected_dir_le.text) + plugin.terrain.data_directory = selected_dir_le.text diff --git a/addons/terrain_3d/menu/directory_setup.gd.uid b/addons/terrain_3d/menu/directory_setup.gd.uid new file mode 100644 index 0000000..de0b12f --- /dev/null +++ b/addons/terrain_3d/menu/directory_setup.gd.uid @@ -0,0 +1 @@ +uid://0034ukv2mngn diff --git a/addons/terrain_3d/menu/directory_setup.tscn b/addons/terrain_3d/menu/directory_setup.tscn new file mode 100644 index 0000000..d5dabc5 --- /dev/null +++ b/addons/terrain_3d/menu/directory_setup.tscn @@ -0,0 +1,48 @@ +[gd_scene format=3 uid="uid://by3kr2nqbqr67"] + +[node name="DirectorySetup" type="ConfirmationDialog"] +title = "Terrain3D Data Directory Setup" +position = Vector2i(0, 36) +size = Vector2i(750, 330) +visible = true + +[node name="Margin" type="MarginContainer" parent="."] +offset_left = 8.0 +offset_top = 8.0 +offset_right = 742.0 +offset_bottom = 281.0 +theme_override_constants/margin_left = 20 +theme_override_constants/margin_top = 20 +theme_override_constants/margin_right = 20 +theme_override_constants/margin_bottom = 20 + +[node name="VBox" type="VBoxContainer" parent="Margin"] +layout_mode = 2 + +[node name="Instructions" type="Label" parent="Margin/VBox"] +custom_minimum_size = Vector2(400, 0) +layout_mode = 2 +text = "Terrain3D now stores data in a directory instead of a single file. Each region is stored in a separate file named `terrain3d[-_]##[-_]##.res`. For instance, the region at location (-1, 1) would be named `terrain3d-01_01.res`. Enable Terrain3D / Debug / Show Region Labels for a visual display." +autowrap_mode = 3 + +[node name="DirectoryLabel" type="Label" parent="Margin/VBox"] +custom_minimum_size = Vector2(400, 0) +layout_mode = 2 +text = " +Specify the directory to store your data. Any existing region files will be loaded." +autowrap_mode = 3 + +[node name="DirHBox" type="HBoxContainer" parent="Margin/VBox"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="Margin/VBox/DirHBox"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Data directory" + +[node name="SelectDir" type="Button" parent="Margin/VBox/DirHBox"] +layout_mode = 2 + +[node name="Spacer" type="Control" parent="Margin/VBox"] +custom_minimum_size = Vector2(0, 40) +layout_mode = 2 diff --git a/addons/terrain_3d/menu/terrain_menu.gd b/addons/terrain_3d/menu/terrain_menu.gd new file mode 100644 index 0000000..c53656f --- /dev/null +++ b/addons/terrain_3d/menu/terrain_menu.gd @@ -0,0 +1,83 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Menu for Terrain3D +extends HBoxContainer + + +const DirectoryWizard: Script = preload("res://addons/terrain_3d/menu/directory_setup.gd") +const Packer: Script = preload("res://addons/terrain_3d/menu/channel_packer.gd") +const Baker: Script = preload("res://addons/terrain_3d/menu/baker.gd") + +var plugin: EditorPlugin +var menu_button: MenuButton = MenuButton.new() +var directory_setup: DirectoryWizard = DirectoryWizard.new() +var packer: Packer = Packer.new() +var baker: Baker = Baker.new() + +# These are IDs and order must be consistent with add_item and set_disabled IDs +enum { + MENU_DIRECTORY_SETUP, + MENU_PACK_TEXTURES, + MENU_SEPARATOR, + MENU_BAKE_ARRAY_MESH, + MENU_BAKE_OCCLUDER, + MENU_SEPARATOR2, + MENU_SET_UP_NAVIGATION, + MENU_BAKE_NAV_MESH, +} + + +func _enter_tree() -> void: + directory_setup.plugin = plugin + packer.plugin = plugin + baker.plugin = plugin + add_child(directory_setup) + add_child(baker) + + menu_button.text = "Terrain3D" + menu_button.get_popup().add_item("Directory Setup...", MENU_DIRECTORY_SETUP) + menu_button.get_popup().add_item("Pack Textures...", MENU_PACK_TEXTURES) + menu_button.get_popup().add_separator("", MENU_SEPARATOR) + menu_button.get_popup().add_item("Bake ArrayMesh...", MENU_BAKE_ARRAY_MESH) + menu_button.get_popup().add_item("Bake Occluder3D...", MENU_BAKE_OCCLUDER) + menu_button.get_popup().add_separator("", MENU_SEPARATOR2) + menu_button.get_popup().add_item("Set up Navigation...", MENU_SET_UP_NAVIGATION) + menu_button.get_popup().add_item("Bake NavMesh...", MENU_BAKE_NAV_MESH) + + menu_button.get_popup().id_pressed.connect(_on_menu_pressed) + menu_button.about_to_popup.connect(_on_menu_about_to_popup) + add_child(menu_button) + + +func _on_menu_pressed(p_id: int) -> void: + match p_id: + MENU_DIRECTORY_SETUP: + directory_setup.directory_setup_popup() + MENU_PACK_TEXTURES: + packer.pack_textures_popup() + MENU_BAKE_ARRAY_MESH: + baker.bake_mesh_popup() + MENU_BAKE_OCCLUDER: + baker.bake_occluder_popup() + MENU_SET_UP_NAVIGATION: + baker.set_up_navigation_popup() + MENU_BAKE_NAV_MESH: + baker.bake_nav_mesh() + + +func _on_menu_about_to_popup() -> void: + menu_button.get_popup().set_item_disabled(MENU_DIRECTORY_SETUP, not plugin.terrain) + menu_button.get_popup().set_item_disabled(MENU_PACK_TEXTURES, not plugin.terrain) + menu_button.get_popup().set_item_disabled(MENU_BAKE_ARRAY_MESH, not plugin.terrain) + menu_button.get_popup().set_item_disabled(MENU_BAKE_OCCLUDER, not plugin.terrain) + + if plugin.terrain: + var nav_regions: Array[NavigationRegion3D] = baker.find_terrain_nav_regions(plugin.terrain) + menu_button.get_popup().set_item_disabled(MENU_BAKE_NAV_MESH, nav_regions.size() == 0) + menu_button.get_popup().set_item_disabled(MENU_SET_UP_NAVIGATION, nav_regions.size() != 0) + elif plugin.nav_region: + var terrains: Array[Terrain3D] = baker.find_nav_region_terrains(plugin.nav_region) + menu_button.get_popup().set_item_disabled(MENU_BAKE_NAV_MESH, terrains.size() == 0) + menu_button.get_popup().set_item_disabled(MENU_SET_UP_NAVIGATION, true) + else: + menu_button.get_popup().set_item_disabled(MENU_BAKE_NAV_MESH, true) + menu_button.get_popup().set_item_disabled(MENU_SET_UP_NAVIGATION, true) diff --git a/addons/terrain_3d/menu/terrain_menu.gd.uid b/addons/terrain_3d/menu/terrain_menu.gd.uid new file mode 100644 index 0000000..b1b1cea --- /dev/null +++ b/addons/terrain_3d/menu/terrain_menu.gd.uid @@ -0,0 +1 @@ +uid://3gxvahogxa10 diff --git a/addons/terrain_3d/plugin.cfg b/addons/terrain_3d/plugin.cfg new file mode 100644 index 0000000..6171d9c --- /dev/null +++ b/addons/terrain_3d/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Terrain3D" +description="A high performance, editable terrain system for Godot 4." +author="Cory Petkovsek & Roope Palmroos" +version="1.0.1" +script="src/editor_plugin.gd" diff --git a/addons/terrain_3d/src/asset_dock.gd b/addons/terrain_3d/src/asset_dock.gd new file mode 100644 index 0000000..58c67c1 --- /dev/null +++ b/addons/terrain_3d/src/asset_dock.gd @@ -0,0 +1,883 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Asset Dock for Terrain3D +@tool +extends PanelContainer + +signal confirmation_closed +signal confirmation_confirmed +signal confirmation_canceled + +const ES_DOCK_SLOT: String = "terrain3d/dock/slot" +const ES_DOCK_TILE_SIZE: String = "terrain3d/dock/tile_size" +const ES_DOCK_FLOATING: String = "terrain3d/dock/floating" +const ES_DOCK_PINNED: String = "terrain3d/dock/always_on_top" +const ES_DOCK_WINDOW_POSITION: String = "terrain3d/dock/window_position" +const ES_DOCK_WINDOW_SIZE: String = "terrain3d/dock/window_size" +const ES_DOCK_TAB: String = "terrain3d/dock/tab" + +var texture_list: ListContainer +var mesh_list: ListContainer +var _current_list: ListContainer +var _last_thumb_update_time: int = 0 +const MAX_UPDATE_TIME: int = 1000 + +var placement_opt: OptionButton +var floating_btn: Button +var pinned_btn: Button +var size_slider: HSlider +var box: BoxContainer +var buttons: BoxContainer +var textures_btn: Button +var meshes_btn: Button +var asset_container: ScrollContainer +var confirm_dialog: ConfirmationDialog +var _confirmed: bool = false + +# Used only for editor, so change to single visible/hiddden +enum { + HIDDEN = -1, + SIDEBAR = 0, + BOTTOM = 1, + WINDOWED = 2, +} +var state: int = HIDDEN + +enum { + POS_LEFT_UL = 0, + POS_LEFT_BL = 1, + POS_LEFT_UR = 2, + POS_LEFT_BR = 3, + POS_RIGHT_UL = 4, + POS_RIGHT_BL = 5, + POS_RIGHT_UR = 6, + POS_RIGHT_BR = 7, + POS_BOTTOM = 8, + POS_MAX = 9, +} +var slot: int = POS_RIGHT_BR +var _initialized: bool = false +var plugin: EditorPlugin +var window: Window +var _godot_last_state: Window.Mode = Window.MODE_FULLSCREEN + + +func initialize(p_plugin: EditorPlugin) -> void: + if p_plugin: + plugin = p_plugin + + _godot_last_state = plugin.godot_editor_window.mode + placement_opt = $Box/Buttons/PlacementOpt + pinned_btn = $Box/Buttons/Pinned + floating_btn = $Box/Buttons/Floating + floating_btn.owner = null + size_slider = $Box/Buttons/SizeSlider + size_slider.owner = null + box = $Box + buttons = $Box/Buttons + textures_btn = $Box/Buttons/TexturesBtn + meshes_btn = $Box/Buttons/MeshesBtn + asset_container = $Box/ScrollContainer + + texture_list = ListContainer.new() + texture_list.plugin = plugin + texture_list.type = Terrain3DAssets.TYPE_TEXTURE + asset_container.add_child(texture_list) + mesh_list = ListContainer.new() + mesh_list.plugin = plugin + mesh_list.type = Terrain3DAssets.TYPE_MESH + mesh_list.visible = false + asset_container.add_child(mesh_list) + _current_list = texture_list + + load_editor_settings() + + # Connect signals + resized.connect(update_layout) + textures_btn.pressed.connect(_on_textures_pressed) + meshes_btn.pressed.connect(_on_meshes_pressed) + placement_opt.item_selected.connect(set_slot) + floating_btn.pressed.connect(make_dock_float) + pinned_btn.toggled.connect(_on_pin_changed) + pinned_btn.visible = ( window != null ) + size_slider.value_changed.connect(_on_slider_changed) + plugin.ui.toolbar.tool_changed.connect(_on_tool_changed) + + meshes_btn.add_theme_font_size_override("font_size", 16 * EditorInterface.get_editor_scale()) + textures_btn.add_theme_font_size_override("font_size", 16 * EditorInterface.get_editor_scale()) + + _initialized = true + update_dock() + update_layout() + + +func _ready() -> void: + if not _initialized: + return + + # Setup styles + set("theme_override_styles/panel", get_theme_stylebox("panel", "Panel")) + # Avoid saving icon resources in tscn when editing w/ a tool script + if EditorInterface.get_edited_scene_root() != self: + pinned_btn.icon = get_theme_icon("Pin", "EditorIcons") + pinned_btn.text = "" + floating_btn.icon = get_theme_icon("MakeFloating", "EditorIcons") + floating_btn.text = "" + + update_thumbnails() + confirm_dialog = ConfirmationDialog.new() + add_child(confirm_dialog) + confirm_dialog.hide() + confirm_dialog.confirmed.connect(func(): _confirmed = true; \ + emit_signal("confirmation_closed"); \ + emit_signal("confirmation_confirmed") ) + confirm_dialog.canceled.connect(func(): _confirmed = false; \ + emit_signal("confirmation_closed"); \ + emit_signal("confirmation_canceled") ) + + +func get_current_list() -> ListContainer: + return _current_list + + +## Dock placement + +func set_slot(p_slot: int) -> void: + p_slot = clamp(p_slot, 0, POS_MAX-1) + + if slot != p_slot: + slot = p_slot + placement_opt.selected = slot + save_editor_settings() + plugin.select_terrain() + update_dock() + + +func remove_dock(p_force: bool = false) -> void: + if state == SIDEBAR: + plugin.remove_control_from_docks(self) + state = HIDDEN + + elif state == BOTTOM: + plugin.remove_control_from_bottom_panel(self) + state = HIDDEN + + # If windowed and destination is not window or final exit, otherwise leave + elif state == WINDOWED and p_force and window: + var parent: Node = get_parent() + if parent: + parent.remove_child(self) + plugin.godot_editor_window.mouse_entered.disconnect(_on_godot_window_entered) + plugin.godot_editor_window.focus_entered.disconnect(_on_godot_focus_entered) + plugin.godot_editor_window.focus_exited.disconnect(_on_godot_focus_exited) + window.hide() + window.queue_free() + window = null + floating_btn.button_pressed = false + floating_btn.visible = true + pinned_btn.visible = false + placement_opt.visible = true + state = HIDDEN + update_dock() # return window to side/bottom + + +func update_dock() -> void: + if not _initialized or window: + return + + update_assets() + + # Move dock to new destination + remove_dock() + # Sidebar + if slot < POS_BOTTOM: + state = SIDEBAR + plugin.add_control_to_dock(slot, self) + # Bottom + elif slot == POS_BOTTOM: + state = BOTTOM + plugin.add_control_to_bottom_panel(self, "Terrain3D") + plugin.make_bottom_panel_item_visible(self) + + +func update_layout() -> void: + if not _initialized: + return + + # Detect if we have a new window from Make floating, grab it so we can free it properly + if not window and get_parent() and get_parent().get_parent() is Window: + window = get_parent().get_parent() + make_dock_float() + return # Will call this function again upon display + + var size_parent: Control = size_slider.get_parent() + # Vertical layout in window / sidebar + if window or slot < POS_BOTTOM: + box.vertical = true + buttons.vertical = false + + if size.x >= 500 and size_parent != buttons: + size_slider.reparent(buttons) + buttons.move_child(size_slider, 3) + elif size.x < 500 and size_parent != box: + size_slider.reparent(box) + box.move_child(size_slider, 1) + floating_btn.reparent(buttons) + buttons.move_child(floating_btn, 4) + + # Wide layout on bottom bar + else: + size_slider.reparent(buttons) + buttons.move_child(size_slider, 3) + floating_btn.reparent(box) + box.vertical = false + buttons.vertical = true + + save_editor_settings() + + +func update_thumbnails() -> void: + if not is_instance_valid(plugin.terrain): + return + if _current_list.type == Terrain3DAssets.TYPE_MESH and \ + Time.get_ticks_msec() - _last_thumb_update_time > MAX_UPDATE_TIME: + plugin.terrain.assets.create_mesh_thumbnails() + _last_thumb_update_time = Time.get_ticks_msec() + for mesh_asset in mesh_list.entries: + mesh_asset.queue_redraw() + + +## Dock Button handlers + + +func _on_pin_changed(toggled: bool) -> void: + if window: + window.always_on_top = pinned_btn.button_pressed + save_editor_settings() + + +func _on_slider_changed(value: float) -> void: + if texture_list: + texture_list.set_entry_width(value) + if mesh_list: + mesh_list.set_entry_width(value) + save_editor_settings() + + +func _on_textures_pressed() -> void: + _current_list = texture_list + texture_list.update_asset_list() + texture_list.visible = true + mesh_list.visible = false + textures_btn.button_pressed = true + meshes_btn.button_pressed = false + texture_list.set_selected_id(texture_list.selected_id) + if plugin.is_terrain_valid(): + EditorInterface.edit_node(plugin.terrain) + save_editor_settings() + + +func _on_meshes_pressed() -> void: + _current_list = mesh_list + mesh_list.update_asset_list() + mesh_list.visible = true + texture_list.visible = false + meshes_btn.button_pressed = true + textures_btn.button_pressed = false + mesh_list.set_selected_id(mesh_list.selected_id) + if plugin.is_terrain_valid(): + EditorInterface.edit_node(plugin.terrain) + update_thumbnails() + save_editor_settings() + + +func _on_tool_changed(p_tool: Terrain3DEditor.Tool, p_operation: Terrain3DEditor.Operation) -> void: + if p_tool == Terrain3DEditor.INSTANCER: + _on_meshes_pressed() + elif p_tool in [ Terrain3DEditor.TEXTURE, Terrain3DEditor.COLOR, Terrain3DEditor.ROUGHNESS ]: + _on_textures_pressed() + + +## Update Dock Contents + + +func update_assets() -> void: + if not _initialized: + return + + # Verify signals to individual lists + if plugin.is_terrain_valid() and plugin.terrain.assets: + if not plugin.terrain.assets.textures_changed.is_connected(texture_list.update_asset_list): + plugin.terrain.assets.textures_changed.connect(texture_list.update_asset_list) + if not plugin.terrain.assets.meshes_changed.is_connected(mesh_list.update_asset_list): + plugin.terrain.assets.meshes_changed.connect(mesh_list.update_asset_list) + + _current_list.update_asset_list() + + +## Window Management + + +func make_dock_float() -> void: + # If not already created (eg from editor panel 'Make Floating' button) + if not window: + remove_dock() + create_window() + + state = WINDOWED + visible = true # Asset dock contents are hidden when popping out of the bottom! + pinned_btn.visible = true + floating_btn.visible = false + placement_opt.visible = false + window.title = "Terrain3D Asset Dock" + window.always_on_top = pinned_btn.button_pressed + window.close_requested.connect(remove_dock.bind(true)) + window.window_input.connect(_on_window_input) + window.focus_exited.connect(save_editor_settings) + window.mouse_exited.connect(save_editor_settings) + window.size_changed.connect(save_editor_settings) + plugin.godot_editor_window.mouse_entered.connect(_on_godot_window_entered) + plugin.godot_editor_window.focus_entered.connect(_on_godot_focus_entered) + plugin.godot_editor_window.focus_exited.connect(_on_godot_focus_exited) + plugin.godot_editor_window.grab_focus() + update_assets() + save_editor_settings() + + +func create_window() -> void: + window = Window.new() + window.wrap_controls = true + var mc := MarginContainer.new() + mc.set_anchors_preset(PRESET_FULL_RECT, false) + mc.add_child(self) + window.add_child(mc) + window.set_transient(false) + window.set_size(plugin.get_setting(ES_DOCK_WINDOW_SIZE, Vector2i(512, 512))) + window.set_position(plugin.get_setting(ES_DOCK_WINDOW_POSITION, Vector2i(704, 284))) + plugin.add_child(window) + window.show() + + +func clamp_window_position() -> void: + if window and window.visible: + var bounds: Vector2i + if EditorInterface.get_editor_settings().get_setting("interface/editor/single_window_mode"): + bounds = EditorInterface.get_base_control().size + else: + bounds = DisplayServer.screen_get_position(window.current_screen) + bounds += DisplayServer.screen_get_size(window.current_screen) + var margin: int = 40 + window.position.x = clamp(window.position.x, -window.size.x + 2*margin, bounds.x - margin) + window.position.y = clamp(window.position.y, 25, bounds.y - margin) + + +func _on_window_input(event: InputEvent) -> void: + # Capture CTRL+S when doc focused to save scene + if event is InputEventKey and event.keycode == KEY_S and event.pressed and event.is_command_or_control_pressed(): + save_editor_settings() + EditorInterface.save_scene() + + +func _on_godot_window_entered() -> void: + if is_instance_valid(window) and window.has_focus(): + plugin.godot_editor_window.grab_focus() + + +func _on_godot_focus_entered() -> void: + # If asset dock is windowed, and Godot was minimized, and now is not, restore asset dock window + if is_instance_valid(window): + if _godot_last_state == Window.MODE_MINIMIZED and plugin.godot_editor_window.mode != Window.MODE_MINIMIZED: + window.show() + _godot_last_state = plugin.godot_editor_window.mode + plugin.godot_editor_window.grab_focus() + + +func _on_godot_focus_exited() -> void: + if is_instance_valid(window) and plugin.godot_editor_window.mode == Window.MODE_MINIMIZED: + window.hide() + _godot_last_state = plugin.godot_editor_window.mode + + +## Manage Editor Settings + +func load_editor_settings() -> void: + floating_btn.button_pressed = plugin.get_setting(ES_DOCK_FLOATING, false) + pinned_btn.button_pressed = plugin.get_setting(ES_DOCK_PINNED, true) + size_slider.value = plugin.get_setting(ES_DOCK_TILE_SIZE, 83) + _on_slider_changed(size_slider.value) + set_slot(plugin.get_setting(ES_DOCK_SLOT, POS_BOTTOM)) + if floating_btn.button_pressed: + make_dock_float() + # TODO Don't save tab until thumbnail generation more reliable + #if plugin.get_setting(ES_DOCK_TAB, 0) == 1: + # _on_meshes_pressed() + + +func save_editor_settings() -> void: + if not _initialized: + return + clamp_window_position() + plugin.set_setting(ES_DOCK_SLOT, slot) + plugin.set_setting(ES_DOCK_TILE_SIZE, size_slider.value) + plugin.set_setting(ES_DOCK_FLOATING, floating_btn.button_pressed) + plugin.set_setting(ES_DOCK_PINNED, pinned_btn.button_pressed) + # TODO Don't save tab until thumbnail generation more reliable + # plugin.set_setting(ES_DOCK_TAB, 0 if _current_list == texture_list else 1) + if window: + plugin.set_setting(ES_DOCK_WINDOW_SIZE, window.size) + plugin.set_setting(ES_DOCK_WINDOW_POSITION, window.position) + + +############################################################## +## class ListContainer +############################################################## + + +class ListContainer extends Container: + var plugin: EditorPlugin + var type := Terrain3DAssets.TYPE_TEXTURE + var entries: Array[ListEntry] + var selected_id: int = 0 + var height: float = 0 + var width: float = 83 + var focus_style: StyleBox + + + func _ready() -> void: + set_v_size_flags(SIZE_EXPAND_FILL) + set_h_size_flags(SIZE_EXPAND_FILL) + + + func clear() -> void: + for e in entries: + e.get_parent().remove_child(e) + e.queue_free() + entries.clear() + + + func update_asset_list() -> void: + clear() + + # Grab terrain + var t: Terrain3D + if plugin.is_terrain_valid(): + t = plugin.terrain + elif is_instance_valid(plugin._last_terrain) and plugin.is_terrain_valid(plugin._last_terrain): + t = plugin._last_terrain + else: + return + + if not t.assets: + return + + if type == Terrain3DAssets.TYPE_TEXTURE: + var texture_count: int = t.assets.get_texture_count() + for i in texture_count: + var texture: Terrain3DTextureAsset = t.assets.get_texture(i) + add_item(texture) + if texture_count < Terrain3DAssets.MAX_TEXTURES: + add_item() + else: + var mesh_count: int = t.assets.get_mesh_count() + for i in mesh_count: + var mesh: Terrain3DMeshAsset = t.assets.get_mesh_asset(i) + add_item(mesh, t.assets) + if mesh_count < Terrain3DAssets.MAX_MESHES: + add_item() + if selected_id >= mesh_count or selected_id < 0: + set_selected_id(0) + + + func add_item(p_resource: Resource = null, p_assets: Terrain3DAssets = null) -> void: + var entry: ListEntry = ListEntry.new() + entry.focus_style = focus_style + var id: int = entries.size() + + entry.set_edited_resource(p_resource) + entry.hovered.connect(_on_resource_hovered.bind(id)) + entry.selected.connect(set_selected_id.bind(id)) + entry.inspected.connect(_on_resource_inspected) + entry.changed.connect(_on_resource_changed.bind(id)) + entry.type = type + entry.asset_list = p_assets + add_child(entry) + entries.push_back(entry) + + if p_resource: + entry.set_selected(id == selected_id) + if not p_resource.id_changed.is_connected(set_selected_after_swap): + p_resource.id_changed.connect(set_selected_after_swap) + + + func _on_resource_hovered(p_id: int): + if type == Terrain3DAssets.TYPE_MESH: + if plugin.terrain: + plugin.terrain.assets.create_mesh_thumbnails(p_id) + + + func set_selected_after_swap(p_type: Terrain3DAssets.AssetType, p_old_id: int, p_new_id: int) -> void: + set_selected_id(clamp(p_new_id, 0, entries.size() - 2)) + + + func set_selected_id(p_id: int) -> void: + selected_id = p_id + + for i in entries.size(): + var entry: ListEntry = entries[i] + entry.set_selected(i == selected_id) + + plugin.select_terrain() + + # Select Paint tool if clicking a texture + if type == Terrain3DAssets.TYPE_TEXTURE and \ + not plugin.editor.get_tool() in [ Terrain3DEditor.TEXTURE, Terrain3DEditor.COLOR, Terrain3DEditor.ROUGHNESS ]: + var paint_btn: Button = plugin.ui.toolbar.get_node_or_null("PaintTexture") + if paint_btn: + paint_btn.set_pressed(true) + plugin.ui._on_tool_changed(Terrain3DEditor.TEXTURE, Terrain3DEditor.REPLACE) + + elif type == Terrain3DAssets.TYPE_MESH and plugin.editor.get_tool() != Terrain3DEditor.INSTANCER: + var instancer_btn: Button = plugin.ui.toolbar.get_node_or_null("InstanceMeshes") + if instancer_btn: + instancer_btn.set_pressed(true) + plugin.ui._on_tool_changed(Terrain3DEditor.INSTANCER, Terrain3DEditor.ADD) + + # Update editor with selected brush + plugin.ui._on_setting_changed() + + + func _on_resource_inspected(p_resource: Resource) -> void: + await get_tree().create_timer(.01).timeout + EditorInterface.edit_resource(p_resource) + + + func _on_resource_changed(p_resource: Resource, p_id: int) -> void: + if not p_resource: + var asset_dock: Control = get_parent().get_parent().get_parent() + if type == Terrain3DAssets.TYPE_TEXTURE: + asset_dock.confirm_dialog.dialog_text = "Are you sure you want to clear this texture?" + else: + asset_dock.confirm_dialog.dialog_text = "Are you sure you want to clear this mesh and delete all instances?" + asset_dock.confirm_dialog.popup_centered() + await asset_dock.confirmation_closed + if not asset_dock._confirmed: + update_asset_list() + return + + if not plugin.is_terrain_valid(): + plugin.select_terrain() + await get_tree().create_timer(.01).timeout + + if plugin.is_terrain_valid(): + if type == Terrain3DAssets.TYPE_TEXTURE: + plugin.terrain.get_assets().set_texture(p_id, p_resource) + else: + plugin.terrain.get_assets().set_mesh_asset(p_id, p_resource) + await get_tree().create_timer(.01).timeout + plugin.terrain.assets.create_mesh_thumbnails(p_id) + + # If removing an entry, clear inspector + if not p_resource: + EditorInterface.inspect_object(null) + + # If null resource, remove last + if not p_resource: + var last_offset: int = 2 + if p_id == entries.size()-2: + last_offset = 3 + set_selected_id(clamp(selected_id, 0, entries.size() - last_offset)) + + + func get_selected_id() -> int: + return selected_id + + + func set_entry_width(value: float) -> void: + width = clamp(value, 66, 230) + redraw() + + + func get_entry_width() -> float: + return width + + + func redraw() -> void: + height = 0 + var id: int = 0 + var separation: float = 4 + var columns: int = 3 + columns = clamp(size.x / width, 1, 100) + + for c in get_children(): + if is_instance_valid(c): + c.size = Vector2(width, width) - Vector2(separation, separation) + c.position = Vector2(id % columns, id / columns) * width + \ + Vector2(separation / columns, separation / columns) + height = max(height, c.position.y + width) + id += 1 + + + # Needed to enable ScrollContainer scroll bar + func _get_minimum_size() -> Vector2: + return Vector2(0, height) + + + func _notification(p_what) -> void: + if p_what == NOTIFICATION_SORT_CHILDREN: + redraw() + + +############################################################## +## class ListEntry +############################################################## + + +class ListEntry extends VBoxContainer: + signal hovered() + signal selected() + signal changed(resource: Resource) + signal inspected(resource: Resource) + + var resource: Resource + var type := Terrain3DAssets.TYPE_TEXTURE + var _thumbnail: Texture2D + var drop_data: bool = false + var is_hovered: bool = false + var is_selected: bool = false + var asset_list: Terrain3DAssets + + @onready var button_row := HBoxContainer.new() + @onready var button_clear := TextureButton.new() + @onready var button_edit := TextureButton.new() + @onready var spacer := Control.new() + @onready var button_enabled := TextureButton.new() + @onready var clear_icon: Texture2D = get_theme_icon("Close", "EditorIcons") + @onready var edit_icon: Texture2D = get_theme_icon("Edit", "EditorIcons") + @onready var enabled_icon: Texture2D = get_theme_icon("GuiVisibilityVisible", "EditorIcons") + @onready var disabled_icon: Texture2D = get_theme_icon("GuiVisibilityHidden", "EditorIcons") + + var name_label: Label + @onready var add_icon: Texture2D = get_theme_icon("Add", "EditorIcons") + @onready var background: StyleBox = get_theme_stylebox("pressed", "Button") + @onready var focus_style: StyleBox = get_theme_stylebox("focus", "Button").duplicate() + + + func _ready() -> void: + setup_buttons() + setup_label() + focus_style.set_border_width_all(2) + focus_style.set_border_color(Color(1, 1, 1, .67)) + + + func setup_buttons() -> void: + var icon_size: Vector2 = Vector2(12, 12) + var margin_container := MarginContainer.new() + margin_container.mouse_filter = Control.MOUSE_FILTER_PASS + margin_container.add_theme_constant_override("margin_top", 5) + margin_container.add_theme_constant_override("margin_left", 5) + margin_container.add_theme_constant_override("margin_right", 5) + add_child(margin_container) + + button_row.size_flags_horizontal = Control.SIZE_EXPAND_FILL + button_row.alignment = BoxContainer.ALIGNMENT_CENTER + button_row.mouse_filter = Control.MOUSE_FILTER_PASS + margin_container.add_child(button_row) + + if type == Terrain3DAssets.TYPE_MESH: + button_enabled.set_texture_normal(enabled_icon) + button_enabled.set_texture_pressed(disabled_icon) + button_enabled.set_custom_minimum_size(icon_size) + button_enabled.set_h_size_flags(Control.SIZE_SHRINK_END) + button_enabled.set_visible(resource != null) + button_enabled.toggle_mode = true + button_enabled.mouse_filter = Control.MOUSE_FILTER_PASS + button_enabled.pressed.connect(enable) + button_row.add_child(button_enabled) + + button_edit.set_texture_normal(edit_icon) + button_edit.set_custom_minimum_size(icon_size) + button_edit.set_h_size_flags(Control.SIZE_SHRINK_END) + button_edit.set_visible(resource != null) + button_edit.mouse_filter = Control.MOUSE_FILTER_PASS + button_edit.pressed.connect(edit) + button_row.add_child(button_edit) + + spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL + spacer.mouse_filter = Control.MOUSE_FILTER_PASS + button_row.add_child(spacer) + + button_clear.set_texture_normal(clear_icon) + button_clear.set_custom_minimum_size(icon_size) + button_clear.set_h_size_flags(Control.SIZE_SHRINK_END) + button_clear.set_visible(resource != null) + button_clear.mouse_filter = Control.MOUSE_FILTER_PASS + button_clear.pressed.connect(clear) + button_row.add_child(button_clear) + + + func setup_label() -> void: + name_label = Label.new() + add_child(name_label, true) + name_label.visible = false + name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + name_label.vertical_alignment = VERTICAL_ALIGNMENT_BOTTOM + name_label.size_flags_vertical = Control.SIZE_EXPAND_FILL + name_label.add_theme_color_override("font_color", Color.WHITE) + name_label.add_theme_color_override("font_shadow_color", Color.BLACK) + name_label.add_theme_constant_override("shadow_offset_x", 1.) + name_label.add_theme_constant_override("shadow_offset_y", 1.) + name_label.add_theme_font_size_override("font_size", 15) + name_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + name_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + if type == Terrain3DAssets.TYPE_TEXTURE: + name_label.text = "Add Texture" + else: + name_label.text = "Add Mesh" + + + func _notification(p_what) -> void: + match p_what: + NOTIFICATION_DRAW: + # Hide spacer if icons are crowding small textures + spacer.visible = size.x > 70 or type == Terrain3DAssets.TYPE_TEXTURE + + var rect: Rect2 = Rect2(Vector2.ZERO, get_size()) + if !resource: + draw_style_box(background, rect) + draw_texture(add_icon, (get_size() / 2) - (add_icon.get_size() / 2)) + else: + if type == Terrain3DAssets.TYPE_TEXTURE: + name_label.text = (resource as Terrain3DTextureAsset).get_name() + self_modulate = resource.get_albedo_color() + _thumbnail = resource.get_albedo_texture() + if _thumbnail: + draw_texture_rect(_thumbnail, rect, false) + texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST_WITH_MIPMAPS + else: + name_label.text = (resource as Terrain3DMeshAsset).get_name() + var id: int = (resource as Terrain3DMeshAsset).get_id() + _thumbnail = resource.get_thumbnail() + if _thumbnail: + draw_texture_rect(_thumbnail, rect, false) + texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS + else: + draw_rect(rect, Color(.15, .15, .15, 1.)) + button_enabled.set_pressed_no_signal(!resource.is_enabled()) + name_label.add_theme_font_size_override("font_size", 4 + rect.size.x/10) + if drop_data: + draw_style_box(focus_style, rect) + if is_hovered: + draw_rect(rect, Color(1, 1, 1, 0.2)) + if is_selected: + draw_style_box(focus_style, rect) + NOTIFICATION_MOUSE_ENTER: + is_hovered = true + name_label.visible = true + emit_signal("hovered") + queue_redraw() + NOTIFICATION_MOUSE_EXIT: + is_hovered = false + name_label.visible = false + drop_data = false + queue_redraw() + + + func _gui_input(p_event: InputEvent) -> void: + if p_event is InputEventMouseButton: + if p_event.is_pressed(): + match p_event.get_button_index(): + MOUSE_BUTTON_LEFT: + # If `Add new` is clicked + if !resource: + if type == Terrain3DAssets.TYPE_TEXTURE: + set_edited_resource(Terrain3DTextureAsset.new(), false) + else: + set_edited_resource(Terrain3DMeshAsset.new(), false) + edit() + else: + emit_signal("selected") + MOUSE_BUTTON_RIGHT: + if resource: + edit() + MOUSE_BUTTON_MIDDLE: + if resource: + clear() + + + func _can_drop_data(p_at_position: Vector2, p_data: Variant) -> bool: + drop_data = false + if typeof(p_data) == TYPE_DICTIONARY: + if p_data.files.size() == 1: + queue_redraw() + drop_data = true + return drop_data + + + func _drop_data(p_at_position: Vector2, p_data: Variant) -> void: + if typeof(p_data) == TYPE_DICTIONARY: + var res: Resource = load(p_data.files[0]) + if res is Texture2D and type == Terrain3DAssets.TYPE_TEXTURE: + var ta := Terrain3DTextureAsset.new() + if resource is Terrain3DTextureAsset: + ta.id = resource.id + ta.set_albedo_texture(res) + set_edited_resource(ta, false) + resource = ta + elif res is Terrain3DTextureAsset and type == Terrain3DAssets.TYPE_TEXTURE: + if resource is Terrain3DTextureAsset: + res.id = resource.id + set_edited_resource(res, false) + elif res is PackedScene and type == Terrain3DAssets.TYPE_MESH: + var ma := Terrain3DMeshAsset.new() + if resource is Terrain3DMeshAsset: + ma.id = resource.id + set_edited_resource(ma, false) + ma.set_scene_file(res) + resource = ma + elif res is Terrain3DMeshAsset and type == Terrain3DAssets.TYPE_MESH: + if resource is Terrain3DMeshAsset: + res.id = resource.id + set_edited_resource(res, false) + emit_signal("selected") + emit_signal("inspected", resource) + + + + func set_edited_resource(p_res: Resource, p_no_signal: bool = true) -> void: + resource = p_res + if resource: + resource.setting_changed.connect(_on_resource_changed) + resource.file_changed.connect(_on_resource_changed) + if resource is Terrain3DMeshAsset: + resource.instancer_setting_changed.connect(_on_resource_changed) + + if button_clear: + button_clear.set_visible(resource != null) + + queue_redraw() + if !p_no_signal: + emit_signal("changed", resource) + + + func _on_resource_changed() -> void: + queue_redraw() + emit_signal("changed", resource) + + + func set_selected(value: bool) -> void: + is_selected = value + queue_redraw() + + + func clear() -> void: + if resource: + set_edited_resource(null, false) + + + func edit() -> void: + emit_signal("selected") + emit_signal("inspected", resource) + + + func enable() -> void: + if resource is Terrain3DMeshAsset: + resource.set_enabled(!resource.is_enabled()) diff --git a/addons/terrain_3d/src/asset_dock.gd.uid b/addons/terrain_3d/src/asset_dock.gd.uid new file mode 100644 index 0000000..8c39f29 --- /dev/null +++ b/addons/terrain_3d/src/asset_dock.gd.uid @@ -0,0 +1 @@ +uid://bgoifepft1hjw diff --git a/addons/terrain_3d/src/asset_dock.tscn b/addons/terrain_3d/src/asset_dock.tscn new file mode 100644 index 0000000..f88c8c0 --- /dev/null +++ b/addons/terrain_3d/src/asset_dock.tscn @@ -0,0 +1,92 @@ +[gd_scene load_steps=2 format=3 uid="uid://dkb6hii5e48m2"] + +[ext_resource type="Script" path="res://addons/terrain_3d/src/asset_dock.gd" id="1_e23pg"] + +[node name="Terrain3D" type="PanelContainer"] +custom_minimum_size = Vector2(256, 95) +offset_right = 766.0 +offset_bottom = 100.0 +script = ExtResource("1_e23pg") + +[node name="Box" type="BoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +vertical = true + +[node name="Buttons" type="BoxContainer" parent="Box"] +layout_mode = 2 + +[node name="TexturesBtn" type="Button" parent="Box/Buttons"] +custom_minimum_size = Vector2(80, 30) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +theme_override_font_sizes/font_size = 16 +toggle_mode = true +button_pressed = true +text = "Textures" + +[node name="MeshesBtn" type="Button" parent="Box/Buttons"] +custom_minimum_size = Vector2(80, 30) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +theme_override_font_sizes/font_size = 16 +toggle_mode = true +text = "Meshes" + +[node name="PlacementOpt" type="OptionButton" parent="Box/Buttons"] +custom_minimum_size = Vector2(80, 30) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +selected = 7 +item_count = 9 +popup/item_0/text = "Left_UL" +popup/item_1/text = "Left_BL" +popup/item_1/id = 1 +popup/item_2/text = "Left_UR" +popup/item_2/id = 2 +popup/item_3/text = "Left_BR" +popup/item_3/id = 3 +popup/item_4/text = "Right_UL" +popup/item_4/id = 4 +popup/item_5/text = "Right_BL " +popup/item_5/id = 5 +popup/item_6/text = "Right_UR" +popup/item_6/id = 6 +popup/item_7/text = "Right_BR" +popup/item_7/id = 7 +popup/item_8/text = "Bottom" +popup/item_8/id = 8 + +[node name="SizeSlider" type="HSlider" parent="Box/Buttons"] +custom_minimum_size = Vector2(80, 10) +layout_mode = 2 +size_flags_horizontal = 3 +min_value = 66.0 +max_value = 230.0 +value = 83.0 + +[node name="Floating" type="Button" parent="Box/Buttons"] +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +tooltip_text = "Pop this dock out to a floating window." +toggle_mode = true +text = "F" +flat = true + +[node name="Pinned" type="Button" parent="Box/Buttons"] +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +tooltip_text = "Make this window \"Always on top\"." +toggle_mode = true +text = "P" +flat = true + +[node name="ScrollContainer" type="ScrollContainer" parent="Box"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 diff --git a/addons/terrain_3d/src/double_slider.gd b/addons/terrain_3d/src/double_slider.gd new file mode 100644 index 0000000..8119456 --- /dev/null +++ b/addons/terrain_3d/src/double_slider.gd @@ -0,0 +1,164 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# DoubleSlider for Terrain3D +# Should work for other UIs +@tool +class_name DoubleSlider +extends Control + +signal value_changed(Vector2) +var label: Label +var suffix: String +var grabbed_handle: int = 0 # -1 left, 0 none, 1 right +var min_value: float = 0.0 +var max_value: float = 100.0 +var step: float = 1.0 +var range := Vector2(0, 100) +var display_scale: float = 1. +var position_x: float = 0. +var minimum_x: float = 60. + + +func _ready() -> void: + # Setup Display Scale + # 0 auto, 1 75%, 2 100%, 3 125%, 4 150%, 5 175%, 6 200%, 7 custom + var es: EditorSettings = EditorInterface.get_editor_settings() + var ds: int = es.get_setting("interface/editor/display_scale") + if ds == 0: + ds = 2 + elif ds == 7: + display_scale = es.get_setting("interface/editor/custom_display_scale") + else: + display_scale = float(ds + 2) * .25 + + update_label() + + +func set_min(p_value: float) -> void: + min_value = p_value + if range.x <= min_value: + range.x = min_value + set_value(range) + update_label() + + +func get_min() -> float: + return min_value + + +func set_max(p_value: float) -> void: + max_value = p_value + if range.y == 0 or range.y >= max_value: + range.y = max_value + set_value(range) + update_label() + + +func get_max() -> float: + return max_value + + +func set_step(p_step: float) -> void: + step = p_step + + +func get_step() -> float: + return step + + +func set_value(p_range: Vector2) -> void: + range.x = clamp(p_range.x, min_value, max_value) + range.y = clamp(p_range.y, min_value, max_value) + if range.y < range.x: + var tmp: float = range.x + range.x = range.y + range.y = tmp + + update_label() + emit_signal("value_changed", Vector2(range.x, range.y)) + queue_redraw() + + +func get_value() -> Vector2: + return range + + +func update_label() -> void: + if label: + label.set_text(str(range.x) + suffix + "/" + str(range.y) + suffix) + if position_x == 0: + position_x = label.position.x + else: + label.position.x = position_x + 5 * display_scale + label.custom_minimum_size.x = minimum_x + 5 * display_scale + + +func _get_handle() -> int: + return 1 + + +func _gui_input(p_event: InputEvent) -> void: + if p_event is InputEventMouseButton: + var button: int = p_event.get_button_index() + if button in [ MOUSE_BUTTON_LEFT, MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN ]: + if p_event.is_pressed(): + var mid_point = (range.x + range.y) / 2.0 + var xpos: float = p_event.get_position().x * 2.0 + if xpos >= mid_point: + grabbed_handle = 1 + else: + grabbed_handle = -1 + match button: + MOUSE_BUTTON_LEFT: + set_slider(p_event.get_position().x) + MOUSE_BUTTON_WHEEL_DOWN: + set_slider(-1., true) + MOUSE_BUTTON_WHEEL_UP: + set_slider(1., true) + else: + grabbed_handle = 0 + + if p_event is InputEventMouseMotion: + if grabbed_handle != 0: + set_slider(p_event.get_position().x) + + +func set_slider(p_xpos: float, p_relative: bool = false) -> void: + if grabbed_handle == 0: + return + var xpos_step: float = clamp(snappedf((p_xpos / size.x) * max_value, step), min_value, max_value) + if(grabbed_handle < 0): + if p_relative: + range.x += p_xpos + else: + range.x = xpos_step + else: + if p_relative: + range.y += p_xpos + else: + range.y = xpos_step + set_value(range) + + +func _notification(p_what: int) -> void: + if p_what == NOTIFICATION_DRAW: + # Draw background bar + var bg: StyleBox = get_theme_stylebox("slider", "HSlider") + var bg_height: float = bg.get_minimum_size().y + var mid_y: float = (size.y - bg_height) / 2.0 + draw_style_box(bg, Rect2(Vector2(0, mid_y), Vector2(size.x, bg_height))) + + # Draw foreground bar + var handle: Texture2D = get_theme_icon("grabber", "HSlider") + var area: StyleBox = get_theme_stylebox("grabber_area", "HSlider") + var startx: float = (range.x / max_value) * size.x + var endx: float = (range.y / max_value) * size.x + draw_style_box(area, Rect2(Vector2(startx, mid_y), Vector2(endx - startx, bg_height))) + + # Draw handles, slightly in so they don't get on the outside edges + var handle_pos: Vector2 + handle_pos.x = clamp(startx - handle.get_size().x/2, -10, size.x) + handle_pos.y = clamp(endx - handle.get_size().x/2, 0, size.x - 10) + draw_texture(handle, Vector2(handle_pos.x, -mid_y - 10 * (display_scale - 1.))) + draw_texture(handle, Vector2(handle_pos.y, -mid_y - 10 * (display_scale - 1.))) + + update_label() diff --git a/addons/terrain_3d/src/double_slider.gd.uid b/addons/terrain_3d/src/double_slider.gd.uid new file mode 100644 index 0000000..1e73752 --- /dev/null +++ b/addons/terrain_3d/src/double_slider.gd.uid @@ -0,0 +1 @@ +uid://stro0p1oawfb diff --git a/addons/terrain_3d/src/editor_plugin.gd b/addons/terrain_3d/src/editor_plugin.gd new file mode 100644 index 0000000..e3e732e --- /dev/null +++ b/addons/terrain_3d/src/editor_plugin.gd @@ -0,0 +1,458 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Editor Plugin for Terrain3D +@tool +extends EditorPlugin + + +# Includes +const UI: Script = preload("res://addons/terrain_3d/src/ui.gd") +const RegionGizmo: Script = preload("res://addons/terrain_3d/src/region_gizmo.gd") +const ASSET_DOCK: String = "res://addons/terrain_3d/src/asset_dock.tscn" + +var modifier_ctrl: bool +var modifier_alt: bool +var modifier_shift: bool +var _last_modifiers: int = 0 +var _input_mode: int = 0 # -1: camera move, 0: none, 1: operating +var rmb_release_time: int = 0 +var _use_meta: bool = false + +var terrain: Terrain3D +var _last_terrain: Terrain3D +var nav_region: NavigationRegion3D + +var editor: Terrain3DEditor +var editor_settings: EditorSettings +var ui: Node # Terrain3DUI see Godot #75388 +var asset_dock: PanelContainer +var region_gizmo: RegionGizmo +var current_region_position: Vector2 +var mouse_global_position: Vector3 = Vector3.ZERO +var godot_editor_window: Window # The Godot Editor window + + +func _init() -> void: + if OS.get_name() == "macOS": + _use_meta = true + + # Get the Godot Editor window. Structure is root:Window/EditorNode/Base Control + godot_editor_window = EditorInterface.get_base_control().get_parent().get_parent() + godot_editor_window.focus_entered.connect(_on_godot_focus_entered) + + +func _enter_tree() -> void: + editor = Terrain3DEditor.new() + setup_editor_settings() + ui = UI.new() + ui.plugin = self + add_child(ui) + + region_gizmo = RegionGizmo.new() + + scene_changed.connect(_on_scene_changed) + + asset_dock = load(ASSET_DOCK).instantiate() + asset_dock.initialize(self) + + +func _exit_tree() -> void: + asset_dock.remove_dock(true) + asset_dock.queue_free() + ui.queue_free() + editor.free() + + scene_changed.disconnect(_on_scene_changed) + godot_editor_window.focus_entered.disconnect(_on_godot_focus_entered) + + +func _on_godot_focus_entered() -> void: + _read_input() + ui.update_decal() + + +## EditorPlugin selection function call chain isn't consistent. Here's the map of calls: +## Assume we handle Terrain3D and NavigationRegion3D +# Click Terrain3D: _handles(Terrain3D), _make_visible(true), _edit(Terrain3D) +# Deselect: _make_visible(false), _edit(null) +# Click other node: _handles(OtherNode) +# Click NavRegion3D: _handles(NavReg3D), _make_visible(true), _edit(NavReg3D) +# Click NavRegion3D, Terrain3D: _handles(Terrain3D), _edit(Terrain3D) +# Click Terrain3D, NavRegion3D: _handles(NavReg3D), _edit(NavReg3D) +func _handles(p_object: Object) -> bool: + if p_object is Terrain3D: + return true + elif p_object is NavigationRegion3D and is_instance_valid(_last_terrain): + return true + + # Terrain3DObjects requires access to EditorUndoRedoManager. The only way to make sure it + # always has it, is to pass it in here. _edit is NOT called if the node is cut and pasted. + elif p_object is Terrain3DObjects: + p_object.editor_setup(self) + elif p_object is Node3D and p_object.get_parent() is Terrain3DObjects: + p_object.get_parent().editor_setup(self) + + return false + + +func _make_visible(p_visible: bool, p_redraw: bool = false) -> void: + if p_visible and is_selected(): + ui.set_visible(true) + asset_dock.update_dock() + else: + ui.set_visible(false) + + +func _edit(p_object: Object) -> void: + if !p_object: + _clear() + + if p_object is Terrain3D: + if p_object == terrain: + return + terrain = p_object + _last_terrain = terrain + terrain.set_plugin(self) + terrain.set_editor(editor) + editor.set_terrain(terrain) + region_gizmo.set_node_3d(terrain) + terrain.add_gizmo(region_gizmo) + ui.set_visible(true) + terrain.set_meta("_edit_lock_", true) + + # Get alerted when a new asset list is loaded + if not terrain.assets_changed.is_connected(asset_dock.update_assets): + terrain.assets_changed.connect(asset_dock.update_assets) + asset_dock.update_assets() + # Get alerted when the region map changes + if not terrain.data.region_map_changed.is_connected(update_region_grid): + terrain.data.region_map_changed.connect(update_region_grid) + update_region_grid() + else: + _clear() + + if is_terrain_valid(_last_terrain): + if p_object is NavigationRegion3D: + ui.set_visible(true, true) + nav_region = p_object + else: + nav_region = null + + +func _clear() -> void: + if is_terrain_valid(): + if terrain.data.region_map_changed.is_connected(update_region_grid): + terrain.data.region_map_changed.disconnect(update_region_grid) + + terrain.clear_gizmos() + terrain = null + editor.set_terrain(null) + + ui.clear_picking() + + region_gizmo.clear() + + +func _forward_3d_gui_input(p_viewport_camera: Camera3D, p_event: InputEvent) -> AfterGUIInput: + if not is_terrain_valid(): + return AFTER_GUI_INPUT_PASS + + var continue_input: AfterGUIInput = _read_input(p_event) + if continue_input != AFTER_GUI_INPUT_CUSTOM: + return continue_input + ui.update_decal() + + ## Setup active camera & viewport + # Always update this for all inputs, as the mouse position can move without + # necessarily being a InputEventMouseMotion object. get_intersection() also + # returns the last frame position, and should be updated more frequently. + + # Snap terrain to current camera + terrain.set_camera(p_viewport_camera) + + # Detect if viewport is set to half_resolution + # Structure is: Node3DEditorViewportContainer/Node3DEditorViewport(4)/SubViewportContainer/SubViewport/Camera3D + var editor_vpc: SubViewportContainer = p_viewport_camera.get_parent().get_parent() + var full_resolution: bool = false if editor_vpc.stretch_shrink == 2 else true + + ## Get mouse location on terrain + # Project 2D mouse position to 3D position and direction + var vp_mouse_pos: Vector2 = editor_vpc.get_local_mouse_position() + var mouse_pos: Vector2 = vp_mouse_pos if full_resolution else vp_mouse_pos / 2 + var camera_pos: Vector3 = p_viewport_camera.project_ray_origin(mouse_pos) + var camera_dir: Vector3 = p_viewport_camera.project_ray_normal(mouse_pos) + + # If region tool, grab mouse position without considering height + if editor.get_tool() == Terrain3DEditor.REGION: + var t = -Vector3(0, 1, 0).dot(camera_pos) / Vector3(0, 1, 0).dot(camera_dir) + mouse_global_position = (camera_pos + t * camera_dir) + else: + #Else look for intersection with terrain + var intersection_point: Vector3 = terrain.get_intersection(camera_pos, camera_dir, true) + if intersection_point.z > 3.4e38 or is_nan(intersection_point.y): # max double or nan + return AFTER_GUI_INPUT_PASS + mouse_global_position = intersection_point + + ## Handle mouse movement + if p_event is InputEventMouseMotion: + + if _input_mode != -1: # Not cam rotation + ## Update region highlight + var region_position: Vector2 = ( Vector2(mouse_global_position.x, mouse_global_position.z) \ + / (terrain.get_region_size() * terrain.get_vertex_spacing()) ).floor() + if current_region_position != region_position: + current_region_position = region_position + update_region_grid() + + if _input_mode > 0 and editor.is_operating(): + # Inject pressure - Relies on C++ set_brush_data() using same dictionary instance + ui.brush_data["mouse_pressure"] = p_event.pressure + + editor.operate(mouse_global_position, p_viewport_camera.rotation.y) + return AFTER_GUI_INPUT_STOP + + return AFTER_GUI_INPUT_PASS + + if p_event is InputEventMouseButton and _input_mode > 0: + if p_event.is_pressed(): + # If picking + if ui.is_picking(): + ui.pick(mouse_global_position) + if not ui.operation_builder or not ui.operation_builder.is_ready(): + return AFTER_GUI_INPUT_STOP + + if modifier_ctrl and editor.get_tool() == Terrain3DEditor.HEIGHT: + var height: float = terrain.data.get_height(mouse_global_position) + ui.brush_data["height"] = height + ui.tool_settings.set_setting("height", height) + + # If adjusting regions + if editor.get_tool() == Terrain3DEditor.REGION: + # Skip regions that already exist or don't + var has_region: bool = terrain.data.has_regionp(mouse_global_position) + var op: int = editor.get_operation() + if ( has_region and op == Terrain3DEditor.ADD) or \ + ( not has_region and op == Terrain3DEditor.SUBTRACT ): + return AFTER_GUI_INPUT_STOP + + # If an automatic operation is ready to go (e.g. gradient) + if ui.operation_builder and ui.operation_builder.is_ready(): + ui.operation_builder.apply_operation(editor, mouse_global_position, p_viewport_camera.rotation.y) + return AFTER_GUI_INPUT_STOP + + # Mouse clicked, start editing + editor.start_operation(mouse_global_position) + editor.operate(mouse_global_position, p_viewport_camera.rotation.y) + return AFTER_GUI_INPUT_STOP + + # _input_apply released, save undo data + elif editor.is_operating(): + editor.stop_operation() + return AFTER_GUI_INPUT_STOP + + return AFTER_GUI_INPUT_PASS + + +func _read_input(p_event: InputEvent = null) -> AfterGUIInput: + ## Determine if user is moving camera or applying + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) or \ + p_event is InputEventMouseButton and p_event.is_released() and \ + p_event.get_button_index() == MOUSE_BUTTON_LEFT: + _input_mode = 1 + else: + _input_mode = 0 + + match get_setting("editors/3d/navigation/navigation_scheme", 0): + 2, 1: # Modo, Maya + if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) or \ + ( Input.is_key_pressed(KEY_ALT) and Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) ): + _input_mode = -1 + if p_event is InputEventMouseButton and p_event.is_released() and \ + ( p_event.get_button_index() == MOUSE_BUTTON_RIGHT or \ + ( Input.is_key_pressed(KEY_ALT) and p_event.get_button_index() == MOUSE_BUTTON_LEFT )): + rmb_release_time = Time.get_ticks_msec() + 0, _: # Godot + if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) or \ + Input.is_mouse_button_pressed(MOUSE_BUTTON_MIDDLE): + _input_mode = -1 + if p_event is InputEventMouseButton and p_event.is_released() and \ + ( p_event.get_button_index() == MOUSE_BUTTON_RIGHT or \ + p_event.get_button_index() == MOUSE_BUTTON_MIDDLE ): + rmb_release_time = Time.get_ticks_msec() + if _input_mode < 0: + # Camera is moving, skip input + return AFTER_GUI_INPUT_PASS + + ## Determine modifiers pressed + modifier_shift = Input.is_key_pressed(KEY_SHIFT) + + # Editor responds to modifier_ctrl so we must register touchscreen Invert + if _use_meta: + modifier_ctrl = Input.is_key_pressed(KEY_META) || ui.inverted_input + else: + modifier_ctrl = Input.is_key_pressed(KEY_CTRL) || ui.inverted_input + + # Keybind enum: Alt,Space,Meta,Capslock + var alt_key: int + match get_setting("terrain3d/config/alt_key_bind", 0): + 3: alt_key = KEY_CAPSLOCK + 2: alt_key = KEY_META + 1: alt_key = KEY_SPACE + 0, _: alt_key = KEY_ALT + modifier_alt = Input.is_key_pressed(alt_key) + var current_mods: int = int(modifier_shift) | int(modifier_ctrl) << 1 | int(modifier_alt) << 2 + + ## Process Hotkeys + if p_event is InputEventKey and \ + current_mods == 0 and \ + p_event.is_pressed() and \ + not p_event.is_echo() and \ + consume_hotkey(p_event.keycode): + # Hotkey found, consume event, and stop input processing + EditorInterface.get_editor_viewport_3d().set_input_as_handled() + return AFTER_GUI_INPUT_STOP + + # Brush data is cleared on set_tool, or clicking textures in the asset dock + # Update modifiers if changed or missing + if _last_modifiers != current_mods or not ui.brush_data.has("modifier_shift"): + _last_modifiers = current_mods + ui.brush_data["modifier_shift"] = modifier_shift + ui.brush_data["modifier_ctrl"] = modifier_ctrl + ui.brush_data["modifier_alt"] = modifier_alt + ui.set_active_operation() + + ## Continue processing input + return AFTER_GUI_INPUT_CUSTOM + + +# Returns true if hotkey matches and operation triggered +func consume_hotkey(keycode: int) -> bool: + match keycode: + KEY_1: + terrain.material.set_show_region_grid(!terrain.material.get_show_region_grid()) + KEY_2: + terrain.material.set_show_instancer_grid(!terrain.material.get_show_instancer_grid()) + KEY_3: + terrain.material.set_show_vertex_grid(!terrain.material.get_show_vertex_grid()) + KEY_4: + terrain.material.set_show_contours(!terrain.material.get_show_contours()) + KEY_E: + ui.toolbar.get_button("AddRegion").set_pressed(true) + KEY_R: + ui.toolbar.get_button("Raise").set_pressed(true) + KEY_H: + ui.toolbar.get_button("Height").set_pressed(true) + KEY_S: + ui.toolbar.get_button("Slope").set_pressed(true) + KEY_C: + ui.toolbar.get_button("PaintColor").set_pressed(true) + KEY_N: + ui.toolbar.get_button("PaintNavigableArea").set_pressed(true) + KEY_I: + ui.toolbar.get_button("InstanceMeshes").set_pressed(true) + KEY_X: + ui.toolbar.get_button("AddHoles").set_pressed(true) + KEY_W: + ui.toolbar.get_button("PaintWetness").set_pressed(true) + KEY_B: + ui.toolbar.get_button("PaintTexture").set_pressed(true) + KEY_V: + ui.toolbar.get_button("SprayTexture").set_pressed(true) + KEY_A: + ui.toolbar.get_button("PaintAutoshader").set_pressed(true) + _: + return false + return true + + +func update_region_grid() -> void: + if not region_gizmo: + return + region_gizmo.set_hidden(not ui.visible) + + if is_terrain_valid(): + region_gizmo.show_rect = editor.get_tool() == Terrain3DEditor.REGION + region_gizmo.use_secondary_color = editor.get_operation() == Terrain3DEditor.SUBTRACT + region_gizmo.region_position = current_region_position + region_gizmo.region_size = terrain.get_region_size() * terrain.get_vertex_spacing() + region_gizmo.grid = terrain.get_data().get_region_locations() + + terrain.update_gizmos() + return + + region_gizmo.show_rect = false + region_gizmo.region_size = 1024 + region_gizmo.grid = [Vector2i.ZERO] + + +func _on_scene_changed(scene_root: Node) -> void: + if not scene_root: + return + + for node in scene_root.find_children("", "Terrain3DObjects"): + node.editor_setup(self) + + asset_dock.update_assets() + await get_tree().create_timer(2).timeout + asset_dock.update_thumbnails() + + +func is_terrain_valid(p_terrain: Terrain3D = null) -> bool: + var t: Terrain3D + if p_terrain: + t = p_terrain + else: + t = terrain + if is_instance_valid(t) and t.is_inside_tree() and t.data: + return true + return false + + +func is_selected() -> bool: + var selected: Array[Node] = EditorInterface.get_selection().get_selected_nodes() + for node in selected: + if ( is_instance_valid(_last_terrain) and node.get_instance_id() == _last_terrain.get_instance_id() ) or \ + node is Terrain3D: + return true + return false + + +func select_terrain() -> void: + if is_instance_valid(_last_terrain) and is_terrain_valid(_last_terrain) and not is_selected(): + var es: EditorSelection = EditorInterface.get_selection() + es.clear() + es.add_node(_last_terrain) + + +## Editor Settings + + +func setup_editor_settings() -> void: + editor_settings = EditorInterface.get_editor_settings() + if not editor_settings.has_setting("terrain3d/config/alt_key_bind"): + editor_settings.set("terrain3d/config/alt_key_bind", 0) + var property_info = { + "name": "terrain3d/config/alt_key_bind", + "type": TYPE_INT, + "hint": PROPERTY_HINT_ENUM, + "hint_string": "Alt,Space,Meta,Capslock" + } + editor_settings.add_property_info(property_info) + + +func set_setting(p_str: String, p_value: Variant) -> void: + editor_settings.set_setting(p_str, p_value) + + +func get_setting(p_str: String, p_default: Variant) -> Variant: + if editor_settings.has_setting(p_str): + return editor_settings.get_setting(p_str) + else: + return p_default + + +func has_setting(p_str: String) -> bool: + return editor_settings.has_setting(p_str) + + +func erase_setting(p_str: String) -> void: + editor_settings.erase(p_str) diff --git a/addons/terrain_3d/src/editor_plugin.gd.uid b/addons/terrain_3d/src/editor_plugin.gd.uid new file mode 100644 index 0000000..fb3e1ea --- /dev/null +++ b/addons/terrain_3d/src/editor_plugin.gd.uid @@ -0,0 +1 @@ +uid://bsgxo1qywjdf3 diff --git a/addons/terrain_3d/src/gradient_operation_builder.gd b/addons/terrain_3d/src/gradient_operation_builder.gd new file mode 100644 index 0000000..8bbafd4 --- /dev/null +++ b/addons/terrain_3d/src/gradient_operation_builder.gd @@ -0,0 +1,56 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Gradient Operation Builder for Terrain3D +extends "res://addons/terrain_3d/src/operation_builder.gd" + + +const MultiPicker: Script = preload("res://addons/terrain_3d/src/multi_picker.gd") + + +func _get_point_picker() -> MultiPicker: + return tool_settings.settings["gradient_points"] + + +func _get_brush_size() -> float: + return tool_settings.get_setting("size") + + +func _is_drawable() -> bool: + return tool_settings.get_setting("drawable") + + +func is_picking() -> bool: + return not _get_point_picker().all_points_selected() + + +func pick(p_global_position: Vector3, p_terrain: Terrain3D) -> void: + if not _get_point_picker().all_points_selected(): + _get_point_picker().add_point(p_global_position) + + +func is_ready() -> bool: + return _get_point_picker().all_points_selected() and not _is_drawable() + + +func apply_operation(p_editor: Terrain3DEditor, p_global_position: Vector3, p_camera_direction: float) -> void: + var points: PackedVector3Array = _get_point_picker().get_points() + assert(points.size() == 2) + assert(not _is_drawable()) + + var brush_size: float = _get_brush_size() + assert(brush_size > 0.0) + + var start: Vector3 = points[0] + var end: Vector3 = points[1] + + p_editor.start_operation(start) + + var dir: Vector3 = (end - start).normalized() + + var pos: Vector3 = start + while dir.dot(end - pos) > 0.0: + p_editor.operate(pos, p_camera_direction) + pos += dir * brush_size * 0.2 + + p_editor.stop_operation() + + _get_point_picker().clear() diff --git a/addons/terrain_3d/src/gradient_operation_builder.gd.uid b/addons/terrain_3d/src/gradient_operation_builder.gd.uid new file mode 100644 index 0000000..e747d25 --- /dev/null +++ b/addons/terrain_3d/src/gradient_operation_builder.gd.uid @@ -0,0 +1 @@ +uid://def7sych6dp8b diff --git a/addons/terrain_3d/src/multi_picker.gd b/addons/terrain_3d/src/multi_picker.gd new file mode 100644 index 0000000..717ca7b --- /dev/null +++ b/addons/terrain_3d/src/multi_picker.gd @@ -0,0 +1,88 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Multipicker for Terrain3D +extends HBoxContainer + + +signal pressed +signal value_changed + + +const ICON_PICKER_CHECKED: String = "res://addons/terrain_3d/icons/picker_checked.svg" +const MAX_POINTS: int = 2 + + +var icon_picker: Texture2D +var icon_picker_checked: Texture2D +var points: PackedVector3Array +var picking_index: int = -1 + + +func _enter_tree() -> void: + icon_picker = get_theme_icon("ColorPick", "EditorIcons") + icon_picker_checked = load(ICON_PICKER_CHECKED) + + points.resize(MAX_POINTS) + + for i in range(MAX_POINTS): + var button := Button.new() + button.icon = icon_picker + button.tooltip_text = "Pick point on the Terrain" + button.set_meta(&"point_index", i) + button.pressed.connect(_on_button_pressed.bind(i)) + add_child(button) + + _update_buttons() + + +func _on_button_pressed(button_index: int) -> void: + points[button_index] = Vector3.ZERO + picking_index = button_index + _update_buttons() + pressed.emit() + + +func _update_buttons() -> void: + for child in get_children(): + if child is Button: + _update_button(child) + + +func _update_button(button: Button) -> void: + var index: int = button.get_meta(&"point_index") + + if points[index] != Vector3.ZERO: + button.icon = icon_picker_checked + else: + button.icon = icon_picker + + +func clear() -> void: + points.fill(Vector3.ZERO) + _update_buttons() + value_changed.emit() + + +func all_points_selected() -> bool: + return points.count(Vector3.ZERO) == 0 + + +func add_point(p_value: Vector3) -> void: + if points.has(p_value): + return + + # If manually selecting a point individually + if picking_index != -1: + points[picking_index] = p_value + picking_index = -1 + else: + # Else picking a sequence of points (non-drawable) + for i in range(MAX_POINTS): + if points[i] == Vector3.ZERO: + points[i] = p_value + break + _update_buttons() + value_changed.emit() + + +func get_points() -> PackedVector3Array: + return points diff --git a/addons/terrain_3d/src/multi_picker.gd.uid b/addons/terrain_3d/src/multi_picker.gd.uid new file mode 100644 index 0000000..6db5cb7 --- /dev/null +++ b/addons/terrain_3d/src/multi_picker.gd.uid @@ -0,0 +1 @@ +uid://dvdtoa32h6xdn diff --git a/addons/terrain_3d/src/operation_builder.gd b/addons/terrain_3d/src/operation_builder.gd new file mode 100644 index 0000000..2a558be --- /dev/null +++ b/addons/terrain_3d/src/operation_builder.gd @@ -0,0 +1,25 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Operation Builder for Terrain3D +extends RefCounted + + +const ToolSettings: Script = preload("res://addons/terrain_3d/src/tool_settings.gd") + + +var tool_settings: ToolSettings + + +func is_picking() -> bool: + return false + + +func pick(p_global_position: Vector3, p_terrain: Terrain3D) -> void: + pass + + +func is_ready() -> bool: + return false + + +func apply_operation(editor: Terrain3DEditor, p_global_position: Vector3, p_camera_direction: float) -> void: + pass diff --git a/addons/terrain_3d/src/operation_builder.gd.uid b/addons/terrain_3d/src/operation_builder.gd.uid new file mode 100644 index 0000000..f14e1fe --- /dev/null +++ b/addons/terrain_3d/src/operation_builder.gd.uid @@ -0,0 +1 @@ +uid://bu5cm0eh052rm diff --git a/addons/terrain_3d/src/region_gizmo.gd b/addons/terrain_3d/src/region_gizmo.gd new file mode 100644 index 0000000..c74c8f5 --- /dev/null +++ b/addons/terrain_3d/src/region_gizmo.gd @@ -0,0 +1,68 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Editor Region Gizmos for Terrain3D +extends EditorNode3DGizmo + +var material: StandardMaterial3D +var selection_material: StandardMaterial3D +var region_position: Vector2 +var region_size: float +var grid: Array[Vector2i] +var use_secondary_color: bool = false +var show_rect: bool = true + +var main_color: Color = Color.GREEN_YELLOW +var secondary_color: Color = Color.RED +var grid_color: Color = Color.WHITE +var border_color: Color = Color.BLUE + + +func _init() -> void: + material = StandardMaterial3D.new() + material.set_flag(BaseMaterial3D.FLAG_DISABLE_DEPTH_TEST, true) + material.set_flag(BaseMaterial3D.FLAG_ALBEDO_FROM_VERTEX_COLOR, true) + material.set_shading_mode(BaseMaterial3D.SHADING_MODE_UNSHADED) + material.set_albedo(Color.WHITE) + + selection_material = material.duplicate() + selection_material.set_render_priority(0) + + +func _redraw() -> void: + clear() + + var rect_position = region_position * region_size + + if show_rect: + var modulate: Color = main_color if !use_secondary_color else secondary_color + if abs(region_position.x) > Terrain3DData.REGION_MAP_SIZE*.5 or abs(region_position.y) > Terrain3DData.REGION_MAP_SIZE*.5: + modulate = Color.GRAY + draw_rect(Vector2(region_size,region_size)*.5 + rect_position, region_size, selection_material, modulate) + + for pos in grid: + var grid_tile_position = Vector2(pos) * region_size + if show_rect and grid_tile_position == rect_position: + # Skip this one, otherwise focused region borders are not always visible due to draw order + continue + + draw_rect(Vector2(region_size,region_size)*.5 + grid_tile_position, region_size, material, grid_color) + + draw_rect(Vector2.ZERO, region_size * Terrain3DData.REGION_MAP_SIZE, material, border_color) + + +func draw_rect(p_pos: Vector2, p_size: float, p_material: StandardMaterial3D, p_modulate: Color) -> void: + var lines: PackedVector3Array = [ + Vector3(-1, 0, -1), + Vector3(-1, 0, 1), + Vector3(1, 0, 1), + Vector3(1, 0, -1), + Vector3(-1, 0, 1), + Vector3(1, 0, 1), + Vector3(1, 0, -1), + Vector3(-1, 0, -1), + ] + + for i in lines.size(): + lines[i] = ((lines[i] / 2.0) * p_size) + Vector3(p_pos.x, 0, p_pos.y) + + add_lines(lines, p_material, false, p_modulate) + diff --git a/addons/terrain_3d/src/region_gizmo.gd.uid b/addons/terrain_3d/src/region_gizmo.gd.uid new file mode 100644 index 0000000..346a404 --- /dev/null +++ b/addons/terrain_3d/src/region_gizmo.gd.uid @@ -0,0 +1 @@ +uid://bh6qwe1ok4cx3 diff --git a/addons/terrain_3d/src/tool_settings.gd b/addons/terrain_3d/src/tool_settings.gd new file mode 100644 index 0000000..ea2d246 --- /dev/null +++ b/addons/terrain_3d/src/tool_settings.gd @@ -0,0 +1,693 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Tool settings bar for Terrain3D +extends PanelContainer + +signal picking(type: Terrain3DEditor.Tool, callback: Callable) +signal setting_changed(setting: Variant) + +enum Layout { + HORIZONTAL, + VERTICAL, + GRID, +} + +enum SettingType { + CHECKBOX, + COLOR_SELECT, + DOUBLE_SLIDER, + OPTION, + PICKER, + MULTI_PICKER, + SLIDER, + LABEL, + TYPE_MAX, +} + +const MultiPicker: Script = preload("res://addons/terrain_3d/src/multi_picker.gd") +const DEFAULT_BRUSH: String = "circle0.exr" +const BRUSH_PATH: String = "res://addons/terrain_3d/brushes" +const ES_TOOL_SETTINGS: String = "terrain3d/tool_settings/" + +# Add settings flags +const NONE: int = 0x0 +const ALLOW_LARGER: int = 0x1 +const ALLOW_SMALLER: int = 0x2 +const ALLOW_OUT_OF_BOUNDS: int = 0x3 # LARGER|SMALLER +const NO_LABEL: int = 0x4 +const ADD_SEPARATOR: int = 0x8 # Add a vertical line before this entry +const ADD_SPACER: int = 0x10 # Add a space before this entry +const NO_SAVE: int = 0x20 # Don't save this in EditorSettings + +var plugin: EditorPlugin # Actually Terrain3DEditorPlugin, but Godot still has CRC errors +var brush_preview_material: ShaderMaterial +var select_brush_button: Button +var selected_brush_imgs: Array +var main_list: HFlowContainer +var advanced_list: VBoxContainer +var height_list: VBoxContainer +var scale_list: VBoxContainer +var rotation_list: VBoxContainer +var color_list: VBoxContainer +var settings: Dictionary = {} + + +func _ready() -> void: + # Remove old editor settings + for setting in ["lift_floor", "flatten_peaks", "lift_flatten", "automatic_regions"]: + plugin.erase_setting(ES_TOOL_SETTINGS + setting) + + # Setup buttons + main_list = HFlowContainer.new() + add_child(main_list, true) + + add_brushes(main_list) + + add_setting({ "name":"instructions", "label":"Click the terrain to add a region. CTRL+Click to remove. Or select another tool on the left.", + "type":SettingType.LABEL, "list":main_list, "flags":NO_LABEL|NO_SAVE }) + + add_setting({ "name":"size", "type":SettingType.SLIDER, "list":main_list, "default":20, "unit":"m", + "range":Vector3(0.1, 200, 1), "flags":ALLOW_LARGER|ADD_SPACER }) + + add_setting({ "name":"strength", "type":SettingType.SLIDER, "list":main_list, "default":33, + "unit":"%", "range":Vector3(1, 100, 1), "flags":ALLOW_LARGER }) + + add_setting({ "name":"height", "type":SettingType.SLIDER, "list":main_list, "default":20, + "unit":"m", "range":Vector3(-500, 500, 0.1), "flags":ALLOW_OUT_OF_BOUNDS }) + add_setting({ "name":"height_picker", "type":SettingType.PICKER, "list":main_list, + "default":Terrain3DEditor.HEIGHT, "flags":NO_LABEL }) + + add_setting({ "name":"color", "type":SettingType.COLOR_SELECT, "list":main_list, + "default":Color.WHITE, "flags":ADD_SEPARATOR }) + add_setting({ "name":"color_picker", "type":SettingType.PICKER, "list":main_list, + "default":Terrain3DEditor.COLOR, "flags":NO_LABEL }) + + add_setting({ "name":"roughness", "type":SettingType.SLIDER, "list":main_list, "default":-65, + "unit":"%", "range":Vector3(-100, 100, 1), "flags":ADD_SEPARATOR }) + add_setting({ "name":"roughness_picker", "type":SettingType.PICKER, "list":main_list, + "default":Terrain3DEditor.ROUGHNESS, "flags":NO_LABEL }) + + add_setting({ "name":"enable_texture", "label":"Texture", "type":SettingType.CHECKBOX, + "list":main_list, "default":true, "flags":ADD_SEPARATOR }) + + add_setting({ "name":"texture_filter", "label":"Texture Filter", "type":SettingType.CHECKBOX, + "list":main_list, "default":false, "flags":ADD_SEPARATOR }) + + add_setting({ "name":"margin", "type":SettingType.SLIDER, "list":main_list, "default":0, + "unit":"", "range":Vector3(-50, 50, 1), "flags":ALLOW_OUT_OF_BOUNDS }) + + # Slope painting filter + add_setting({ "name":"slope", "type":SettingType.DOUBLE_SLIDER, "list":main_list, "default":Vector2(0, 90), + "unit":"°", "range":Vector3(0, 90, 1), "flags":ADD_SEPARATOR }) + + add_setting({ "name":"enable_angle", "label":"Angle", "type":SettingType.CHECKBOX, + "list":main_list, "default":true, "flags":ADD_SEPARATOR }) + add_setting({ "name":"angle", "type":SettingType.SLIDER, "list":main_list, "default":0, + "unit":"%", "range":Vector3(0, 337.5, 22.5), "flags":NO_LABEL }) + add_setting({ "name":"angle_picker", "type":SettingType.PICKER, "list":main_list, + "default":Terrain3DEditor.ANGLE, "flags":NO_LABEL }) + add_setting({ "name":"dynamic_angle", "label":"Dynamic", "type":SettingType.CHECKBOX, + "list":main_list, "default":false, "flags":ADD_SPACER }) + + add_setting({ "name":"enable_scale", "label":"Scale", "type":SettingType.CHECKBOX, + "list":main_list, "default":true, "flags":ADD_SEPARATOR }) + add_setting({ "name":"scale", "label":"±", "type":SettingType.SLIDER, "list":main_list, "default":0, + "unit":"%", "range":Vector3(-60, 80, 20), "flags":NO_LABEL }) + add_setting({ "name":"scale_picker", "type":SettingType.PICKER, "list":main_list, + "default":Terrain3DEditor.SCALE, "flags":NO_LABEL }) + + ## Slope sculpting brush + add_setting({ "name":"gradient_points", "type":SettingType.MULTI_PICKER, "label":"Points", + "list":main_list, "default":Terrain3DEditor.SCULPT, "flags":ADD_SEPARATOR }) + add_setting({ "name":"drawable", "type":SettingType.CHECKBOX, "list":main_list, "default":false, + "flags":ADD_SEPARATOR }) + settings["drawable"].toggled.connect(_on_drawable_toggled) + + ## Instancer + height_list = create_submenu(main_list, "Height", Layout.VERTICAL) + add_setting({ "name":"height_offset", "type":SettingType.SLIDER, "list":height_list, "default":0, + "unit":"m", "range":Vector3(-10, 10, 0.05), "flags":ALLOW_OUT_OF_BOUNDS }) + add_setting({ "name":"random_height", "label":"Random Height ±", "type":SettingType.SLIDER, + "list":height_list, "default":0, "unit":"m", "range":Vector3(0, 10, 0.05), + "flags":ALLOW_OUT_OF_BOUNDS }) + + scale_list = create_submenu(main_list, "Scale", Layout.VERTICAL) + add_setting({ "name":"fixed_scale", "type":SettingType.SLIDER, "list":scale_list, "default":100, + "unit":"%", "range":Vector3(1, 1000, 1), "flags":ALLOW_OUT_OF_BOUNDS }) + add_setting({ "name":"random_scale", "label":"Random Scale ±", "type":SettingType.SLIDER, "list":scale_list, + "default":20, "unit":"%", "range":Vector3(0, 99, 1), "flags":ALLOW_OUT_OF_BOUNDS }) + + rotation_list = create_submenu(main_list, "Rotation", Layout.VERTICAL) + add_setting({ "name":"fixed_spin", "label":"Fixed Spin (Around Y)", "type":SettingType.SLIDER, "list":rotation_list, + "default":0, "unit":"°", "range":Vector3(0, 360, 1) }) + add_setting({ "name":"random_spin", "type":SettingType.SLIDER, "list":rotation_list, "default":360, + "unit":"°", "range":Vector3(0, 360, 1) }) + add_setting({ "name":"fixed_tilt", "label":"Fixed Tilt", "type":SettingType.SLIDER, "list":rotation_list, + "default":0, "unit":"°", "range":Vector3(-85, 85, 1), "flags":ALLOW_OUT_OF_BOUNDS }) + add_setting({ "name":"random_tilt", "label":"Random Tilt ±", "type":SettingType.SLIDER, "list":rotation_list, + "default":10, "unit":"°", "range":Vector3(0, 85, 1), "flags":ALLOW_OUT_OF_BOUNDS }) + add_setting({ "name":"align_to_normal", "type":SettingType.CHECKBOX, "list":rotation_list, "default":false }) + + color_list = create_submenu(main_list, "Color", Layout.VERTICAL) + add_setting({ "name":"vertex_color", "type":SettingType.COLOR_SELECT, "list":color_list, + "default":Color.WHITE }) + add_setting({ "name":"random_hue", "label":"Random Hue Shift ±", "type":SettingType.SLIDER, + "list":color_list, "default":0, "unit":"°", "range":Vector3(0, 360, 1) }) + add_setting({ "name":"random_darken", "type":SettingType.SLIDER, "list":color_list, "default":50, + "unit":"%", "range":Vector3(0, 100, 1) }) + #add_setting({ "name":"blend_mode", "type":SettingType.OPTION, "list":color_list, "default":0, + #"range":Vector3(0, 3, 1) }) + + if DisplayServer.is_touchscreen_available(): + add_setting({ "name":"invert", "label":"Invert", "type":SettingType.CHECKBOX, "list":main_list, "default":false, "flags":ADD_SEPARATOR }) + + var spacer: Control = Control.new() + spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL + main_list.add_child(spacer, true) + + ## Advanced Settings Menu + advanced_list = create_submenu(main_list, "", Layout.VERTICAL, false) + add_setting({ "name":"auto_regions", "label":"Add regions while sculpting", "type":SettingType.CHECKBOX, + "list":advanced_list, "default":true }) + add_setting({ "name":"align_to_view", "type":SettingType.CHECKBOX, "list":advanced_list, + "default":true }) + add_setting({ "name":"show_cursor_while_painting", "type":SettingType.CHECKBOX, "list":advanced_list, + "default":true }) + advanced_list.add_child(HSeparator.new(), true) + add_setting({ "name":"gamma", "type":SettingType.SLIDER, "list":advanced_list, "default":1.0, + "unit":"γ", "range":Vector3(0.1, 2.0, 0.01) }) + add_setting({ "name":"jitter", "type":SettingType.SLIDER, "list":advanced_list, "default":50, + "unit":"%", "range":Vector3(0, 100, 1) }) + add_setting({ "name":"crosshair_threshold", "type":SettingType.SLIDER, "list":advanced_list, "default":16., + "unit":"m", "range":Vector3(0, 200, 1) }) + + +func create_submenu(p_parent: Control, p_button_name: String, p_layout: Layout, p_hover_pop: bool = true) -> Container: + var menu_button: Button = Button.new() + if p_button_name.is_empty(): + menu_button.icon = get_theme_icon("GuiTabMenuHl", "EditorIcons") + else: + menu_button.set_text(p_button_name) + menu_button.set_toggle_mode(true) + menu_button.set_v_size_flags(SIZE_SHRINK_CENTER) + menu_button.toggled.connect(_on_show_submenu.bind(menu_button)) + + var submenu: PopupPanel = PopupPanel.new() + submenu.popup_hide.connect(menu_button.set_pressed.bind(false)) + var panel_style: StyleBox = get_theme_stylebox("panel", "PopupMenu").duplicate() + panel_style.set_content_margin_all(10) + submenu.set("theme_override_styles/panel", panel_style) + submenu.add_to_group("terrain3d_submenus") + + # Pop up menu on hover, hide on exit + if p_hover_pop: + menu_button.mouse_entered.connect(_on_show_submenu.bind(true, menu_button)) + + submenu.mouse_entered.connect(func(): submenu.set_meta("mouse_entered", true)) + + submenu.mouse_exited.connect(func(): + # On mouse_exit, hide popup unless LineEdit focused + var focused_element: Control = submenu.gui_get_focus_owner() + if not focused_element is LineEdit: + _on_show_submenu(false, menu_button) + submenu.set_meta("mouse_entered", false) + return + + focused_element.focus_exited.connect(func(): + # Close submenu once lineedit loses focus + if not submenu.get_meta("mouse_entered"): + _on_show_submenu(false, menu_button) + submenu.set_meta("mouse_entered", false) + ) + ) + + var sublist: Container + match(p_layout): + Layout.GRID: + sublist = GridContainer.new() + Layout.VERTICAL: + sublist = VBoxContainer.new() + Layout.HORIZONTAL, _: + sublist = HBoxContainer.new() + + p_parent.add_child(menu_button, true) + menu_button.add_child(submenu, true) + submenu.add_child(sublist, true) + + return sublist + + +func _on_show_submenu(p_toggled: bool, p_button: Button) -> void: + # Don't show if mouse already down (from painting) + if p_toggled and Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + return + + # Hide menu if mouse is not in button or panel + var button_rect: Rect2 = Rect2(p_button.get_screen_transform().origin, p_button.get_global_rect().size) + var in_button: bool = button_rect.has_point(DisplayServer.mouse_get_position()) + var popup: PopupPanel = p_button.get_child(0) + var popup_rect: Rect2 = Rect2(popup.position, popup.size) + var in_popup: bool = popup_rect.has_point(DisplayServer.mouse_get_position()) + if not p_toggled and ( in_button or in_popup ): + return + + # Hide all submenus before possibly enabling the current one + get_tree().call_group("terrain3d_submenus", "set_visible", false) + popup.set_visible(p_toggled) + var popup_pos: Vector2 = p_button.get_screen_transform().origin + popup_pos.y -= popup.size.y + if popup.get_child_count()>0 and popup.get_child(0) == advanced_list: + popup_pos.x -= popup.size.x - p_button.size.x + popup.set_position(popup_pos) + + +func add_brushes(p_parent: Control) -> void: + var brush_list: GridContainer = create_submenu(p_parent, "Brush", Layout.GRID) + brush_list.name = "BrushList" + + var brush_button_group: ButtonGroup = ButtonGroup.new() + brush_button_group.pressed.connect(_on_setting_changed) + var default_brush_btn: Button + + var dir: DirAccess = DirAccess.open(BRUSH_PATH) + if dir: + dir.list_dir_begin() + var file_name = dir.get_next() + while file_name != "": + if !dir.current_is_dir() and file_name.ends_with(".exr"): + var img: Image = Image.load_from_file(BRUSH_PATH + "/" + file_name) + var thumbimg: Image = img.duplicate() + img.convert(Image.FORMAT_RF) + + if thumbimg.get_width() != 100 and thumbimg.get_height() != 100: + thumbimg.resize(100, 100, Image.INTERPOLATE_CUBIC) + thumbimg = Terrain3DUtil.black_to_alpha(thumbimg) + thumbimg.convert(Image.FORMAT_LA8) + var thumbtex: ImageTexture = ImageTexture.create_from_image(thumbimg) + + var brush_btn: Button = Button.new() + brush_btn.set_custom_minimum_size(Vector2.ONE * 100) + brush_btn.set_button_icon(thumbtex) + brush_btn.set_meta("image", img) + brush_btn.set_expand_icon(true) + brush_btn.set_material(_get_brush_preview_material()) + brush_btn.set_toggle_mode(true) + brush_btn.set_button_group(brush_button_group) + brush_btn.mouse_entered.connect(_on_brush_hover.bind(true, brush_btn)) + brush_btn.mouse_exited.connect(_on_brush_hover.bind(false, brush_btn)) + brush_list.add_child(brush_btn, true) + if file_name == DEFAULT_BRUSH: + default_brush_btn = brush_btn + + var lbl: Label = Label.new() + brush_btn.name = file_name.get_basename().to_pascal_case() + brush_btn.add_child(lbl, true) + lbl.text = brush_btn.name + lbl.visible = false + lbl.position.y = 70 + lbl.add_theme_color_override("font_shadow_color", Color.BLACK) + lbl.add_theme_constant_override("shadow_offset_x", 1) + lbl.add_theme_constant_override("shadow_offset_y", 1) + lbl.add_theme_font_size_override("font_size", 16) + + file_name = dir.get_next() + + brush_list.columns = sqrt(brush_list.get_child_count()) + 2 + + if not default_brush_btn: + default_brush_btn = brush_button_group.get_buttons()[0] + default_brush_btn.set_pressed(true) + _generate_brush_texture(default_brush_btn) + + settings["brush"] = brush_button_group + + select_brush_button = brush_list.get_parent().get_parent() + # Optionally erase the main brush button text and replace it with the texture + select_brush_button.set_text("") + select_brush_button.set_button_icon(default_brush_btn.get_button_icon()) + select_brush_button.set_custom_minimum_size(Vector2.ONE * 36) + select_brush_button.set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER) + select_brush_button.set_expand_icon(true) + + +func _on_brush_hover(p_hovering: bool, p_button: Button) -> void: + if p_button.get_child_count() > 0: + var child = p_button.get_child(0) + if child is Label: + if p_hovering: + child.visible = true + else: + child.visible = false + + +func _on_pick(p_type: Terrain3DEditor.Tool) -> void: + emit_signal("picking", p_type, _on_picked) + + +func _on_picked(p_type: Terrain3DEditor.Tool, p_color: Color, p_global_position: Vector3) -> void: + match p_type: + Terrain3DEditor.HEIGHT: + settings["height"].value = p_color.r if not is_nan(p_color.r) else 0. + Terrain3DEditor.COLOR: + settings["color"].color = p_color if not is_nan(p_color.r) else Color.WHITE + Terrain3DEditor.ROUGHNESS: + # This converts 0,1 to -100,100 + # It also quantizes explicitly so picked values matches painted values + settings["roughness"].value = round(200. * float(int(p_color.a * 255.) / 255. - .5)) if not is_nan(p_color.r) else 0. + Terrain3DEditor.ANGLE: + settings["angle"].value = p_color.r + Terrain3DEditor.SCALE: + settings["scale"].value = p_color.r + _on_setting_changed() + + +func _on_point_pick(p_type: Terrain3DEditor.Tool, p_name: String) -> void: + assert(p_type == Terrain3DEditor.SCULPT) + emit_signal("picking", p_type, _on_point_picked.bind(p_name)) + + +func _on_point_picked(p_type: Terrain3DEditor.Tool, p_color: Color, p_global_position: Vector3, p_name: String) -> void: + assert(p_type == Terrain3DEditor.SCULPT) + var point: Vector3 = p_global_position + point.y = p_color.r + settings[p_name].add_point(point) + _on_setting_changed() + + +func add_setting(p_args: Dictionary) -> void: + var p_name: StringName = p_args.get("name", "") + var p_label: String = p_args.get("label", "") # Optional replacement for name + var p_type: SettingType = p_args.get("type", SettingType.TYPE_MAX) + var p_list: Control = p_args.get("list") + var p_default: Variant = p_args.get("default") + var p_suffix: String = p_args.get("unit", "") + var p_range: Vector3 = p_args.get("range", Vector3(0, 0, 1)) + var p_minimum: float = p_range.x + var p_maximum: float = p_range.y + var p_step: float = p_range.z + var p_flags: int = p_args.get("flags", NONE) + + if p_name.is_empty() or p_type == SettingType.TYPE_MAX: + return + + var container: HBoxContainer = HBoxContainer.new() + container.set_v_size_flags(SIZE_EXPAND_FILL) + var control: Control # Houses the setting to be saved + var pending_children: Array[Control] + + match p_type: + SettingType.LABEL: + var label := Label.new() + label.set_text(p_label) + pending_children.push_back(label) + control = label + + SettingType.CHECKBOX: + var checkbox := CheckBox.new() + if !(p_flags & NO_SAVE): + checkbox.set_pressed_no_signal(plugin.get_setting(ES_TOOL_SETTINGS + p_name, p_default)) + checkbox.toggled.connect( ( + func(value, path): + plugin.set_setting(path, value) + ).bind(ES_TOOL_SETTINGS + p_name) ) + else: + checkbox.set_pressed_no_signal(p_default) + checkbox.pressed.connect(_on_setting_changed) + pending_children.push_back(checkbox) + control = checkbox + + SettingType.COLOR_SELECT: + var picker := ColorPickerButton.new() + picker.set_custom_minimum_size(Vector2(100, 25)) + picker.edit_alpha = false + picker.get_picker().set_color_mode(ColorPicker.MODE_HSV) + if !(p_flags & NO_SAVE): + picker.set_pick_color(plugin.get_setting(ES_TOOL_SETTINGS + p_name, p_default)) + picker.color_changed.connect( ( + func(value, path): + plugin.set_setting(path, value) + ).bind(ES_TOOL_SETTINGS + p_name) ) + else: + picker.set_pick_color(p_default) + picker.color_changed.connect(_on_setting_changed) + pending_children.push_back(picker) + control = picker + + SettingType.PICKER: + var button := Button.new() + button.set_v_size_flags(SIZE_SHRINK_CENTER) + button.icon = get_theme_icon("ColorPick", "EditorIcons") + button.tooltip_text = "Pick value from the Terrain" + button.pressed.connect(_on_pick.bind(p_default)) + pending_children.push_back(button) + control = button + + SettingType.MULTI_PICKER: + var multi_picker: HBoxContainer = MultiPicker.new() + multi_picker.pressed.connect(_on_point_pick.bind(p_default, p_name)) + multi_picker.value_changed.connect(_on_setting_changed) + pending_children.push_back(multi_picker) + control = multi_picker + + SettingType.OPTION: + var option := OptionButton.new() + for i in int(p_maximum): + option.add_item("a", i) + option.selected = p_minimum + option.item_selected.connect(_on_setting_changed) + pending_children.push_back(option) + control = option + + SettingType.SLIDER, SettingType.DOUBLE_SLIDER: + var slider: Control + if p_type == SettingType.SLIDER: + # Create an editable value box + var spin_slider := EditorSpinSlider.new() + spin_slider.set_flat(false) + spin_slider.set_hide_slider(true) + spin_slider.value_changed.connect(_on_setting_changed) + spin_slider.set_max(p_maximum) + spin_slider.set_min(p_minimum) + spin_slider.set_step(p_step) + spin_slider.set_suffix(p_suffix) + spin_slider.set_v_size_flags(SIZE_SHRINK_CENTER) + spin_slider.set_custom_minimum_size(Vector2(65, 0)) + + # Create horizontal slider linked to the above box + slider = HSlider.new() + slider.share(spin_slider) + if p_flags & ALLOW_LARGER: + slider.set_allow_greater(true) + if p_flags & ALLOW_SMALLER: + slider.set_allow_lesser(true) + + pending_children.push_back(slider) + pending_children.push_back(spin_slider) + control = spin_slider + + else: # DOUBLE_SLIDER + var label := Label.new() + label.set_custom_minimum_size(Vector2(60, 0)) + label.set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER) + slider = DoubleSlider.new() + slider.label = label + slider.suffix = p_suffix + slider.value_changed.connect(_on_setting_changed) + pending_children.push_back(slider) + pending_children.push_back(label) + control = slider + + slider.set_min(p_minimum) + slider.set_max(p_maximum) + slider.set_step(p_step) + slider.set_value(p_default) + slider.set_v_size_flags(SIZE_SHRINK_CENTER) + slider.set_custom_minimum_size(Vector2(50, 10)) + + if !(p_flags & NO_SAVE): + slider.set_value(plugin.get_setting(ES_TOOL_SETTINGS + p_name, p_default)) + slider.value_changed.connect( ( + func(value, path): + plugin.set_setting(path, value) + ).bind(ES_TOOL_SETTINGS + p_name) ) + else: + slider.set_value(p_default) + + control.name = p_name.to_pascal_case() + settings[p_name] = control + + # Setup button labels + if not (p_flags & NO_LABEL): + # Labels are actually buttons styled to look like labels + var label := Button.new() + label.set("theme_override_styles/normal", get_theme_stylebox("normal", "Label")) + label.set("theme_override_styles/hover", get_theme_stylebox("normal", "Label")) + label.set("theme_override_styles/pressed", get_theme_stylebox("normal", "Label")) + label.set("theme_override_styles/focus", get_theme_stylebox("normal", "Label")) + label.pressed.connect(_on_label_pressed.bind(p_name, p_default)) + if p_label.is_empty(): + label.set_text(p_name.capitalize() + ": ") + else: + label.set_text(p_label.capitalize() + ": ") + pending_children.push_front(label) + + # Add separators to front + if p_flags & ADD_SEPARATOR: + pending_children.push_front(VSeparator.new()) + if p_flags & ADD_SPACER: + var spacer := Control.new() + spacer.set_custom_minimum_size(Vector2(5, 0)) + pending_children.push_front(spacer) + + # Add all children to container and list + for child in pending_children: + container.add_child(child, true) + p_list.add_child(container, true) + + +# If label button is pressed, reset value to default or toggle checkbox +func _on_label_pressed(p_name: String, p_default: Variant) -> void: + var control: Control = settings.get(p_name) + if not control: + return + if control is CheckBox: + set_setting(p_name, !control.button_pressed) + elif p_default != null: + set_setting(p_name, p_default) + + +func get_settings() -> Dictionary: + var dict: Dictionary + for key in settings.keys(): + dict[key] = get_setting(key) + return dict + + +func get_setting(p_setting: String) -> Variant: + var object: Object = settings.get(p_setting) + var value: Variant + if object is Range: + value = object.get_value() + # Adjust widths of all sliders on update of values + var digits: float = count_digits(value) + var width: float = clamp( (1 + count_digits(value)) * 19., 50, 80) * clamp(EditorInterface.get_editor_scale(), .9, 2) + object.set_custom_minimum_size(Vector2(width, 0)) + elif object is DoubleSlider: + value = object.get_value() + elif object is ButtonGroup: # "brush" + value = selected_brush_imgs + elif object is CheckBox: + value = object.is_pressed() + elif object is ColorPickerButton: + value = object.color + elif object is MultiPicker: + value = object.get_points() + if value == null: + value = 0 + return value + + +func set_setting(p_setting: String, p_value: Variant) -> void: + var object: Object = settings.get(p_setting) + if object is DoubleSlider: # Expects p_value is Vector2 + object.set_value(p_value) + elif object is Range: + object.set_value(p_value) + elif object is ButtonGroup: # Expects p_value is Array [ "button name", boolean ] + if p_value is Array and p_value.size() == 2: + for button in object.get_buttons(): + if button.name == p_value[0]: + button.button_pressed = p_value[1] + elif object is CheckBox: + object.button_pressed = p_value + elif object is ColorPickerButton: + object.color = p_value + plugin.set_setting(ES_TOOL_SETTINGS + p_setting, p_value) # Signal doesn't fire on CPB + elif object is MultiPicker: # Expects p_value is PackedVector3Array + object.points = p_value + _on_setting_changed(object) + + +func show_settings(p_settings: PackedStringArray) -> void: + for setting in settings.keys(): + var object: Object = settings[setting] + if object is Control: + if setting in p_settings: + object.get_parent().show() + else: + object.get_parent().hide() + if select_brush_button: + if not "brush" in p_settings: + select_brush_button.hide() + else: + select_brush_button.show() + + +func _on_setting_changed(p_setting: Variant = null) -> void: + # If a brush was selected + if p_setting is Button and p_setting.get_parent().name == "BrushList": + _generate_brush_texture(p_setting) + # Optionally Set selected brush texture in main brush button + if select_brush_button: + select_brush_button.set_button_icon(p_setting.get_button_icon()) + # Hide popup + p_setting.get_parent().get_parent().set_visible(false) + # Hide label + if p_setting.get_child_count() > 0: + p_setting.get_child(0).visible = false + emit_signal("setting_changed", p_setting) + + +func _generate_brush_texture(p_btn: Button) -> void: + if p_btn is Button: + var img: Image = p_btn.get_meta("image") + if img.get_width() < 1024 and img.get_height() < 1024: + img = img.duplicate() + img.resize(1024, 1024, Image.INTERPOLATE_CUBIC) + var tex: ImageTexture = ImageTexture.create_from_image(img) + selected_brush_imgs = [ img, tex ] + + +func _on_drawable_toggled(p_button_pressed: bool) -> void: + if not p_button_pressed: + settings["gradient_points"].clear() + + +func _get_brush_preview_material() -> ShaderMaterial: + if !brush_preview_material: + brush_preview_material = ShaderMaterial.new() + var shader: Shader = Shader.new() + var code: String = "shader_type canvas_item;\n" + code += "varying vec4 v_vertex_color;\n" + code += "void vertex() {\n" + code += " v_vertex_color = COLOR;\n" + code += "}\n" + code += "void fragment(){\n" + code += " vec4 tex = texture(TEXTURE, UV);\n" + code += " COLOR.a *= pow(tex.r, 0.666);\n" + code += " COLOR.rgb = v_vertex_color.rgb;\n" + code += "}\n" + shader.set_code(code) + brush_preview_material.set_shader(shader) + return brush_preview_material + + +# Counts digits of a number including negative sign, decimal points, and up to 3 decimals +func count_digits(p_value: float) -> int: + var count: int = 1 + for i in range(5, 0, -1): + if abs(p_value) >= pow(10, i): + count = i+1 + break + if p_value - floor(p_value) >= .1: + count += 1 # For the decimal + if p_value*10 - floor(p_value*10.) >= .1: + count += 1 + if p_value*100 - floor(p_value*100.) >= .1: + count += 1 + if p_value*1000 - floor(p_value*1000.) >= .1: + count += 1 + # Negative sign + if p_value < 0: + count += 1 + return count + diff --git a/addons/terrain_3d/src/tool_settings.gd.uid b/addons/terrain_3d/src/tool_settings.gd.uid new file mode 100644 index 0000000..b6c65fb --- /dev/null +++ b/addons/terrain_3d/src/tool_settings.gd.uid @@ -0,0 +1 @@ +uid://ciskaaennrffu diff --git a/addons/terrain_3d/src/toolbar.gd b/addons/terrain_3d/src/toolbar.gd new file mode 100644 index 0000000..fc68b86 --- /dev/null +++ b/addons/terrain_3d/src/toolbar.gd @@ -0,0 +1,154 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Toolbar for Terrain3D +extends VFlowContainer + +signal tool_changed(p_tool: Terrain3DEditor.Tool, p_operation: Terrain3DEditor.Operation) + +const ICON_REGION_ADD: String = "res://addons/terrain_3d/icons/region_add.svg" +const ICON_REGION_REMOVE: String = "res://addons/terrain_3d/icons/region_remove.svg" +const ICON_HEIGHT_ADD: String = "res://addons/terrain_3d/icons/height_add.svg" +const ICON_HEIGHT_SUB: String = "res://addons/terrain_3d/icons/height_sub.svg" +const ICON_HEIGHT_FLAT: String = "res://addons/terrain_3d/icons/height_flat.svg" +const ICON_HEIGHT_SLOPE: String = "res://addons/terrain_3d/icons/height_slope.svg" +const ICON_HEIGHT_SMOOTH: String = "res://addons/terrain_3d/icons/height_smooth.svg" +const ICON_PAINT_TEXTURE: String = "res://addons/terrain_3d/icons/texture_paint.svg" +const ICON_SPRAY_TEXTURE: String = "res://addons/terrain_3d/icons/texture_spray.svg" +const ICON_COLOR: String = "res://addons/terrain_3d/icons/color_paint.svg" +const ICON_WETNESS: String = "res://addons/terrain_3d/icons/wetness.svg" +const ICON_AUTOSHADER: String = "res://addons/terrain_3d/icons/autoshader.svg" +const ICON_HOLES: String = "res://addons/terrain_3d/icons/holes.svg" +const ICON_NAVIGATION: String = "res://addons/terrain_3d/icons/navigation.svg" +const ICON_INSTANCER: String = "res://addons/terrain_3d/icons/multimesh.svg" + +var add_tool_group: ButtonGroup = ButtonGroup.new() +var sub_tool_group: ButtonGroup = ButtonGroup.new() +var buttons: Dictionary + + +func _init() -> void: + set_custom_minimum_size(Vector2(20, 0)) + + +func _ready() -> void: + add_tool_group.pressed.connect(_on_tool_selected) + sub_tool_group.pressed.connect(_on_tool_selected) + + add_tool_button({ "tool":Terrain3DEditor.REGION, + "add_text":"Add Region (E)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_REGION_ADD, + "sub_text":"Remove Region", "sub_op":Terrain3DEditor.SUBTRACT, "sub_icon":ICON_REGION_REMOVE }) + + add_child(HSeparator.new()) + + add_tool_button({ "tool":Terrain3DEditor.SCULPT, + "add_text":"Raise (R)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_HEIGHT_ADD, + "sub_text":"Lower (R)", "sub_op":Terrain3DEditor.SUBTRACT, "sub_icon":ICON_HEIGHT_SUB }) + + add_tool_button({ "tool":Terrain3DEditor.SCULPT, + "add_text":"Smooth (Shift)", "add_op":Terrain3DEditor.AVERAGE, "add_icon":ICON_HEIGHT_SMOOTH }) + + add_tool_button({ "tool":Terrain3DEditor.HEIGHT, + "add_text":"Height (H)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_HEIGHT_FLAT, + "sub_text":"Height (H)", "sub_op":Terrain3DEditor.SUBTRACT, "sub_icon":ICON_HEIGHT_FLAT }) + + add_tool_button({ "tool":Terrain3DEditor.SCULPT, + "add_text":"Slope (S)", "add_op":Terrain3DEditor.GRADIENT, "add_icon":ICON_HEIGHT_SLOPE }) + + add_child(HSeparator.new()) + + add_tool_button({ "tool":Terrain3DEditor.TEXTURE, + "add_text":"Paint Texture (B)", "add_op":Terrain3DEditor.REPLACE, "add_icon":ICON_PAINT_TEXTURE }) + + add_tool_button({ "tool":Terrain3DEditor.TEXTURE, + "add_text":"Spray Texture (V)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_SPRAY_TEXTURE }) + + add_tool_button({ "tool":Terrain3DEditor.AUTOSHADER, + "add_text":"Paint Autoshader (A)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_AUTOSHADER, + "sub_text":"Disable Autoshader (A)", "sub_op":Terrain3DEditor.SUBTRACT }) + + add_child(HSeparator.new()) + + add_tool_button({ "tool":Terrain3DEditor.COLOR, + "add_text":"Paint Color (C)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_COLOR, + "sub_text":"Remove Color (C)", "sub_op":Terrain3DEditor.SUBTRACT }) + + add_tool_button({ "tool":Terrain3DEditor.ROUGHNESS, + "add_text":"Paint Wetness (W)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_WETNESS, + "sub_text":"Remove Wetness (W)", "sub_op":Terrain3DEditor.SUBTRACT }) + + add_child(HSeparator.new()) + + add_tool_button({ "tool":Terrain3DEditor.HOLES, + "add_text":"Add Holes (X)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_HOLES, + "sub_text":"Remove Holes (X)", "sub_op":Terrain3DEditor.SUBTRACT }) + + add_tool_button({ "tool":Terrain3DEditor.NAVIGATION, + "add_text":"Paint Navigable Area (N)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_NAVIGATION, + "sub_text":"Remove Navigable Area (N)", "sub_op":Terrain3DEditor.SUBTRACT }) + + add_tool_button({ "tool":Terrain3DEditor.INSTANCER, + "add_text":"Instance Meshes (I)", "add_op":Terrain3DEditor.ADD, "add_icon":ICON_INSTANCER, + "sub_text":"Remove Meshes (I)", "sub_op":Terrain3DEditor.SUBTRACT }) + + # Select first button + var buttons: Array[BaseButton] = add_tool_group.get_buttons() + buttons[0].set_pressed(true) + show_add_buttons(true) + + +func add_tool_button(p_params: Dictionary) -> void: + # Additive button + var button := Button.new() + var name_str: String = p_params.get("add_text", "blank").get_slice('(', 0).to_pascal_case() + button.set_name(name_str) + button.set_meta("Tool", p_params.get("tool", 0)) + button.set_meta("Operation", p_params.get("add_op", 0)) + button.set_meta("ID", add_tool_group.get_buttons().size() + 1) + button.set_tooltip_text(p_params.get("add_text", "blank")) + button.set_button_icon(load(p_params.get("add_icon"))) + button.set_flat(true) + button.set_toggle_mode(true) + button.set_h_size_flags(SIZE_SHRINK_END) + button.set_button_group(p_params.get("group", add_tool_group)) + add_child(button, true) + buttons[button.get_name()] = button + + # Subtractive button + var button2: Button + if p_params.has("sub_text"): + button2 = Button.new() + name_str = p_params.get("sub_text", "blank").get_slice('(', 0).to_pascal_case() + button2.set_name(name_str) + button2.set_meta("Tool", p_params.get("tool", 0)) + button2.set_meta("Operation", p_params.get("sub_op", 0)) + button2.set_meta("ID", button.get_meta("ID")) + button2.set_tooltip_text(p_params.get("sub_text", "blank")) + button2.set_button_icon(load(p_params.get("sub_icon", p_params.get("add_icon")))) + button2.set_flat(true) + button2.set_toggle_mode(true) + button2.set_h_size_flags(SIZE_SHRINK_END) + else: + button2 = button.duplicate() + button2.set_button_group(p_params.get("group", sub_tool_group)) + add_child(button2, true) + buttons[button2.get_name()] = button + + +func get_button(p_name: String) -> Button: + return buttons.get(p_name, null) + + +func show_add_buttons(p_enable: bool) -> void: + for button in add_tool_group.get_buttons(): + button.visible = p_enable + for button in sub_tool_group.get_buttons(): + button.visible = !p_enable + + +func _on_tool_selected(p_button: BaseButton) -> void: + # Select same tool on negative bar + var group: ButtonGroup = p_button.get_button_group() + var change_group: ButtonGroup = add_tool_group if group == sub_tool_group else sub_tool_group + var id: int = p_button.get_meta("ID", -2) + for button in change_group.get_buttons(): + button.set_pressed_no_signal(button.get_meta("ID", -1) == id) + emit_signal("tool_changed", p_button.get_meta("Tool", Terrain3DEditor.TOOL_MAX), p_button.get_meta("Operation", Terrain3DEditor.OP_MAX)) diff --git a/addons/terrain_3d/src/toolbar.gd.uid b/addons/terrain_3d/src/toolbar.gd.uid new file mode 100644 index 0000000..6ba79d5 --- /dev/null +++ b/addons/terrain_3d/src/toolbar.gd.uid @@ -0,0 +1 @@ +uid://b1j37u6utjbom diff --git a/addons/terrain_3d/src/ui.gd b/addons/terrain_3d/src/ui.gd new file mode 100644 index 0000000..7c4d740 --- /dev/null +++ b/addons/terrain_3d/src/ui.gd @@ -0,0 +1,576 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# UI for Terrain3D +extends Node + + +# Includes +const TerrainMenu: Script = preload("res://addons/terrain_3d/menu/terrain_menu.gd") +const Toolbar: Script = preload("res://addons/terrain_3d/src/toolbar.gd") +const ToolSettings: Script = preload("res://addons/terrain_3d/src/tool_settings.gd") +const OperationBuilder: Script = preload("res://addons/terrain_3d/src/operation_builder.gd") +const GradientOperationBuilder: Script = preload("res://addons/terrain_3d/src/gradient_operation_builder.gd") +const COLOR_RAISE := Color.WHITE +const COLOR_LOWER := Color.BLACK +const COLOR_SMOOTH := Color(0.5, 0, .2) +const COLOR_LIFT := Color.ORANGE +const COLOR_FLATTEN := Color.BLUE_VIOLET +const COLOR_HEIGHT := Color(0., 0.32, .4) +const COLOR_SLOPE := Color.YELLOW +const COLOR_PAINT := Color.DARK_GREEN +const COLOR_SPRAY := Color.PALE_GREEN +const COLOR_ROUGHNESS := Color.ROYAL_BLUE +const COLOR_AUTOSHADER := Color.DODGER_BLUE +const COLOR_HOLES := Color.BLACK +const COLOR_NAVIGATION := Color(.28, .0, .25) +const COLOR_INSTANCER := Color.CRIMSON +const COLOR_PICK_COLOR := Color.WHITE +const COLOR_PICK_HEIGHT := Color.DARK_RED +const COLOR_PICK_ROUGH := Color.ROYAL_BLUE + +const OP_NONE: int = 0x0 +const OP_POSITIVE_ONLY: int = 0x01 +const OP_NEGATIVE_ONLY: int = 0x02 + +const RING1: String = "res://addons/terrain_3d/brushes/ring1.exr" +var ring_texture : ImageTexture +@onready var region_texture := ImageTexture.new() : + set(value): + var image: Image = Image.create_empty(1, 1, false, Image.FORMAT_R8) + image.fill(Color.WHITE) + value.create_from_image(image) + region_texture = value +var plugin: EditorPlugin # Actually Terrain3DEditorPlugin, but Godot still has CRC errors +var toolbar: Toolbar +var tool_settings: ToolSettings +var terrain_menu: TerrainMenu +var setting_has_changed: bool = false +var visible: bool = false +var picking: int = Terrain3DEditor.TOOL_MAX +var picking_callback: Callable +var brush_data: Dictionary +var operation_builder: OperationBuilder +var active_tool: Terrain3DEditor.Tool +var _selected_tool: Terrain3DEditor.Tool +var active_operation: Terrain3DEditor.Operation +var _selected_operation: Terrain3DEditor.Operation +var inverted_input: bool = false + +# Editor decals, indices; 0 = main brush, 1 = slope point A, 2 = slope point B +var mat_rid: RID +var editor_decal_position: Array[Vector2] = [Vector2(), Vector2(), Vector2()] +var editor_decal_rotation: Array[float] = [float(), float(), float()] +var editor_decal_size: Array[float] = [float(), float(), float()] +var editor_decal_color: Array[Color] = [Color(), Color(), Color()] +var editor_decal_visible: Array[bool] = [bool(), bool(), bool()] +var editor_brush_texture_rid: RID = RID() +var editor_decal_timer: Timer +var editor_decal_fade: float : + set(value): + editor_decal_fade = value + if editor_decal_color.size() > 0: + editor_decal_color[0].a = value + if is_shader_valid(): + RenderingServer.material_set_param(mat_rid, "_editor_decal_color", editor_decal_color) + if value < 0.001: + var r_map: PackedInt32Array = plugin.terrain.data.get_region_map() + RenderingServer.material_set_param(mat_rid, "_region_map", r_map) +var editor_ring_texture_rid: RID + + +func _enter_tree() -> void: + toolbar = Toolbar.new() + toolbar.hide() + toolbar.tool_changed.connect(_on_tool_changed) + + tool_settings = ToolSettings.new() + tool_settings.setting_changed.connect(_on_setting_changed) + tool_settings.picking.connect(_on_picking) + tool_settings.plugin = plugin + tool_settings.hide() + + terrain_menu = TerrainMenu.new() + terrain_menu.plugin = plugin + terrain_menu.hide() + + plugin.add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_SIDE_LEFT, toolbar) + plugin.add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_BOTTOM, tool_settings) + plugin.add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, terrain_menu) + + _on_tool_changed(Terrain3DEditor.REGION, Terrain3DEditor.ADD) + + editor_decal_timer = Timer.new() + editor_decal_timer.wait_time = .5 + editor_decal_timer.one_shot = true + editor_decal_timer.timeout.connect(func(): + get_tree().create_tween().tween_property(self, "editor_decal_fade", 0.0, 0.15)) + add_child(editor_decal_timer) + + +func _ready() -> void: + var img: Image = Image.load_from_file(RING1) + img.convert(Image.FORMAT_R8) + ring_texture = ImageTexture.create_from_image(img) + editor_ring_texture_rid = ring_texture.get_rid() + + +func _exit_tree() -> void: + plugin.remove_control_from_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_SIDE_LEFT, toolbar) + plugin.remove_control_from_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_BOTTOM, tool_settings) + toolbar.queue_free() + tool_settings.queue_free() + terrain_menu.queue_free() + editor_decal_timer.queue_free() + + +func set_visible(p_visible: bool, p_menu_only: bool = false) -> void: + terrain_menu.set_visible(p_visible) + + if p_menu_only: + toolbar.set_visible(false) + tool_settings.set_visible(false) + else: + visible = p_visible + toolbar.set_visible(p_visible) + tool_settings.set_visible(p_visible) + update_decal() + + if plugin.editor: + if p_visible: + await get_tree().create_timer(.01).timeout # Won't work, otherwise + _on_tool_changed(_selected_tool, _selected_operation) + else: + plugin.editor.set_tool(Terrain3DEditor.TOOL_MAX) + plugin.editor.set_operation(Terrain3DEditor.OP_MAX) + + +func set_menu_visibility(p_list: Control, p_visible: bool) -> void: + if p_list: + p_list.get_parent().get_parent().visible = p_visible + + +func _on_tool_changed(p_tool: Terrain3DEditor.Tool, p_operation: Terrain3DEditor.Operation) -> void: + _selected_tool = p_tool + _selected_operation = p_operation + clear_picking() + set_menu_visibility(tool_settings.advanced_list, true) + set_menu_visibility(tool_settings.scale_list, false) + set_menu_visibility(tool_settings.rotation_list, false) + set_menu_visibility(tool_settings.height_list, false) + set_menu_visibility(tool_settings.color_list, false) + + # Select which settings to show. Options in tool_settings.gd:_ready + var to_show: PackedStringArray = [] + + match _selected_tool: + Terrain3DEditor.REGION: + to_show.push_back("instructions") + to_show.push_back("invert") + set_menu_visibility(tool_settings.advanced_list, false) + + Terrain3DEditor.SCULPT: + to_show.push_back("brush") + to_show.push_back("size") + to_show.push_back("strength") + if _selected_operation in [Terrain3DEditor.ADD, Terrain3DEditor.SUBTRACT]: + to_show.push_back("invert") + elif _selected_operation == Terrain3DEditor.GRADIENT: + to_show.push_back("gradient_points") + to_show.push_back("drawable") + + Terrain3DEditor.HEIGHT: + to_show.push_back("brush") + to_show.push_back("size") + to_show.push_back("strength") + to_show.push_back("height") + to_show.push_back("height_picker") + to_show.push_back("invert") + + Terrain3DEditor.TEXTURE: + to_show.push_back("brush") + to_show.push_back("size") + to_show.push_back("enable_texture") + if _selected_operation == Terrain3DEditor.ADD: + to_show.push_back("strength") + to_show.push_back("invert") + to_show.push_back("slope") + to_show.push_back("enable_angle") + to_show.push_back("angle") + to_show.push_back("angle_picker") + to_show.push_back("dynamic_angle") + to_show.push_back("enable_scale") + to_show.push_back("scale") + to_show.push_back("scale_picker") + + Terrain3DEditor.COLOR: + to_show.push_back("brush") + to_show.push_back("size") + to_show.push_back("strength") + to_show.push_back("color") + to_show.push_back("color_picker") + to_show.push_back("slope") + to_show.push_back("texture_filter") + to_show.push_back("margin") + to_show.push_back("invert") + + Terrain3DEditor.ROUGHNESS: + to_show.push_back("brush") + to_show.push_back("size") + to_show.push_back("strength") + to_show.push_back("roughness") + to_show.push_back("roughness_picker") + to_show.push_back("slope") + to_show.push_back("texture_filter") + to_show.push_back("margin") + to_show.push_back("invert") + + Terrain3DEditor.AUTOSHADER, Terrain3DEditor.HOLES, Terrain3DEditor.NAVIGATION: + to_show.push_back("brush") + to_show.push_back("size") + to_show.push_back("invert") + + Terrain3DEditor.INSTANCER: + to_show.push_back("size") + to_show.push_back("strength") + to_show.push_back("slope") + set_menu_visibility(tool_settings.height_list, true) + to_show.push_back("height_offset") + to_show.push_back("random_height") + set_menu_visibility(tool_settings.scale_list, true) + to_show.push_back("fixed_scale") + to_show.push_back("random_scale") + set_menu_visibility(tool_settings.rotation_list, true) + to_show.push_back("fixed_spin") + to_show.push_back("random_spin") + to_show.push_back("fixed_tilt") + to_show.push_back("random_tilt") + to_show.push_back("align_to_normal") + set_menu_visibility(tool_settings.color_list, true) + to_show.push_back("vertex_color") + to_show.push_back("random_darken") + to_show.push_back("random_hue") + to_show.push_back("invert") + + _: + pass + + # Advanced menu settings + to_show.push_back("auto_regions") + to_show.push_back("align_to_view") + to_show.push_back("show_cursor_while_painting") + to_show.push_back("gamma") + to_show.push_back("jitter") + to_show.push_back("crosshair_threshold") + tool_settings.show_settings(to_show) + + operation_builder = null + if _selected_operation == Terrain3DEditor.GRADIENT: + operation_builder = GradientOperationBuilder.new() + operation_builder.tool_settings = tool_settings + + _on_setting_changed() + plugin.update_region_grid() + + +func _on_setting_changed(p_setting: Variant = null) -> void: + if not plugin.asset_dock: # Skip function if not _ready() + return + brush_data = tool_settings.get_settings() + brush_data["asset_id"] = plugin.asset_dock.get_current_list().get_selected_id() + if plugin.editor: + plugin.editor.set_brush_data(brush_data) + inverted_input = brush_data.get("invert", false) + if p_setting is CheckBox and p_setting.name == &"Invert": + plugin._read_input() # Revalidate keyboard input for modifier_ctrl + set_active_operation() + update_decal() + + +# Change tool/operation based on modifiers. Called from: +# * editor_plugin.gd:_read_input() - when a modifier key is pressed +# * _on_tool_changed() via: +# * _on_setting_changed() eg. Touchscreen Invert +func set_active_operation() -> void: + var inverted: bool = plugin.modifier_ctrl || inverted_input + + # Toggle toolbar buttons + toolbar.show_add_buttons(not inverted) + + # If Shift, Smoothness + if plugin.modifier_shift and not inverted: + active_tool = Terrain3DEditor.SCULPT + active_operation = Terrain3DEditor.AVERAGE + + # Else if Ctrl/Invert checked, opposite + elif _selected_operation == Terrain3DEditor.ADD and inverted: + active_tool = _selected_tool + active_operation = Terrain3DEditor.SUBTRACT + elif _selected_operation == Terrain3DEditor.SUBTRACT and not inverted: + active_tool = _selected_tool + active_operation = Terrain3DEditor.ADD + + # Else use default and set + else: + active_tool = _selected_tool + active_operation = _selected_operation + + if plugin.editor: + plugin.editor.set_tool(active_tool) + plugin.editor.set_operation(active_operation) + + +func update_decal() -> void: + if not plugin.terrain or brush_data.size() <= 3: + return + mat_rid = plugin.terrain.material.get_material_rid() + editor_decal_timer.start() + + # If not a state that should show the decal, hide everything and return + if not visible or \ + plugin._input_mode < 0 or \ + # After moving camera, wait for mouse cursor to update before revealing + # See https://github.com/godotengine/godot/issues/70098 + Time.get_ticks_msec() - plugin.rmb_release_time <= 100 or \ + (plugin._input_mode > 0 and not brush_data["show_cursor_while_painting"]): + hide_decal() + return + + reset_decal_arrays() + editor_decal_position[0] = Vector2(plugin.mouse_global_position.x, plugin.mouse_global_position.z) + editor_decal_visible[0] = true + # Set region size, and modify region map for none background mode. + var r_map: PackedInt32Array = plugin.terrain.data.get_region_map() + if plugin.editor.get_tool() == Terrain3DEditor.REGION: + var r_size: float = float(plugin.terrain.get_region_size()) * plugin.terrain.get_vertex_spacing() + var map_size: int = plugin.terrain.data.REGION_MAP_SIZE + var half_r_size: float = r_size * 0.5 + var pos: Vector2 = (Vector2(plugin.mouse_global_position.x, plugin.mouse_global_position.z) + + Vector2(half_r_size, half_r_size)).snappedf(r_size) - Vector2(half_r_size, half_r_size) + editor_brush_texture_rid = region_texture.get_rid() + editor_decal_position[0] = pos + editor_decal_size[0] = r_size + editor_decal_rotation[0] = 0.0 + + var loc: Vector2i = plugin.terrain.data.get_region_location(plugin.mouse_global_position) + loc += Vector2i(map_size / 2, map_size / 2) + if !(loc.x < 0 or loc.x > map_size - 1 or loc.y < 0 or loc.y > map_size - 1): + var index: int = clampi(loc.y * map_size + loc.x, 0, map_size * map_size - 1) + if plugin.terrain.material.get_world_background() == Terrain3DMaterial.WorldBackground.NONE: + if r_map[index] == 0 and active_operation == Terrain3DEditor.ADD: + r_map[index] = -index - 1 + else: + r_map[index] = r_map[index] + + match active_operation: + Terrain3DEditor.ADD: + if r_map[index] <= 0: + editor_decal_color[0] = Color.WHITE + editor_decal_color[0].a = 0.25 + else: + hide_decal() + + Terrain3DEditor.SUBTRACT: + if r_map[index] > 0: + editor_decal_color[0] = Color.WHITE * .15 + editor_decal_color[0].a = 0.75 + else: + hide_decal() + else: + hide_decal() + # Set texture and color + elif picking != Terrain3DEditor.TOOL_MAX: + editor_brush_texture_rid = ring_texture.get_rid() + editor_decal_size[0] = 10. * plugin.terrain.get_vertex_spacing() + match picking: + Terrain3DEditor.HEIGHT: + editor_decal_color[0] = COLOR_PICK_HEIGHT + Terrain3DEditor.COLOR: + editor_decal_color[0] = COLOR_PICK_COLOR + Terrain3DEditor.ROUGHNESS: + editor_decal_color[0] = COLOR_PICK_ROUGH + editor_decal_color[0].a = 1.0 + else: + editor_brush_texture_rid = brush_data["brush"][1].get_rid() + editor_decal_size[0] = maxf(brush_data["size"], .5) + if brush_data["align_to_view"]: + var cam: Camera3D = plugin.terrain.get_camera(); + if (cam): + editor_decal_rotation[0] = cam.rotation.y + else: + editor_decal_rotation[0] = 0. + match plugin.editor.get_tool(): + Terrain3DEditor.SCULPT: + match active_operation: + Terrain3DEditor.ADD: + if plugin.modifier_alt: + editor_decal_color[0] = COLOR_LIFT + editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + else: + editor_decal_color[0] = COLOR_RAISE + editor_decal_color[0].a = clamp(brush_data["strength"], .25, .5) + Terrain3DEditor.SUBTRACT: + if plugin.modifier_alt: + editor_decal_color[0] = COLOR_FLATTEN + editor_decal_color[0].a = clamp(brush_data["strength"], .25, .5) + .1 + else: + editor_decal_color[0] = COLOR_LOWER + editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .25 + Terrain3DEditor.AVERAGE: + editor_decal_color[0] = COLOR_SMOOTH + editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .25 + Terrain3DEditor.GRADIENT: + editor_decal_color[0] = COLOR_SLOPE + editor_decal_color[0].a = clamp(brush_data["strength"], .2, .4) + Terrain3DEditor.HEIGHT: + editor_decal_color[0] = COLOR_HEIGHT + editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .25 + Terrain3DEditor.TEXTURE: + match active_operation: + Terrain3DEditor.REPLACE: + editor_decal_color[0] = COLOR_PAINT + editor_decal_color[0].a = .6 + Terrain3DEditor.SUBTRACT: + editor_decal_color[0] = COLOR_PAINT + editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .1 + Terrain3DEditor.ADD: + editor_decal_color[0] = COLOR_SPRAY + editor_decal_color[0].a = clamp(brush_data["strength"], .15, .4) + Terrain3DEditor.COLOR: + editor_decal_color[0] = brush_data["color"].srgb_to_linear() + editor_decal_color[0].a *= clamp(brush_data["strength"], .2, .5) + Terrain3DEditor.ROUGHNESS: + editor_decal_color[0] = COLOR_ROUGHNESS + editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .1 + Terrain3DEditor.AUTOSHADER: + editor_decal_color[0] = COLOR_AUTOSHADER + editor_decal_color[0].a = .6 + Terrain3DEditor.HOLES: + editor_decal_color[0] = COLOR_HOLES + editor_decal_color[0].a = .75 + Terrain3DEditor.NAVIGATION: + editor_decal_color[0] = COLOR_NAVIGATION + editor_decal_color[0].a = .80 + Terrain3DEditor.INSTANCER: + editor_brush_texture_rid = ring_texture.get_rid() + editor_decal_color[0] = COLOR_INSTANCER + editor_decal_color[0].a = .75 + + editor_decal_visible[1] = false + editor_decal_visible[2] = false + + if active_operation == Terrain3DEditor.GRADIENT: + var point1: Vector3 = brush_data["gradient_points"][0] + if point1 != Vector3.ZERO: + editor_decal_color[1] = COLOR_SLOPE + editor_decal_size[1] = 10. * plugin.terrain.get_vertex_spacing() + editor_decal_visible[1] = true + editor_decal_position[1] = Vector2(point1.x, point1.z) + var point2: Vector3 = brush_data["gradient_points"][1] + if point2 != Vector3.ZERO: + editor_decal_color[2] = COLOR_SLOPE + editor_decal_size[2] = 10. * plugin.terrain.get_vertex_spacing() + editor_decal_visible[2] = true + editor_decal_position[2] = Vector2(point2.x, point2.z) + + if RenderingServer.get_current_rendering_method().contains("gl_compatibility"): + for i in editor_decal_color.size(): + editor_decal_color[i].a = maxf(0.1, editor_decal_color[i].a - .25) + + editor_decal_fade = editor_decal_color[0].a + # Update Shader params + if is_shader_valid(): + RenderingServer.material_set_param(mat_rid, "_editor_brush_texture", editor_brush_texture_rid) + RenderingServer.material_set_param(mat_rid, "_editor_ring_texture", editor_ring_texture_rid) + RenderingServer.material_set_param(mat_rid, "_editor_decal_position", editor_decal_position) + RenderingServer.material_set_param(mat_rid, "_editor_decal_rotation", editor_decal_rotation) + RenderingServer.material_set_param(mat_rid, "_editor_decal_size", editor_decal_size) + RenderingServer.material_set_param(mat_rid, "_editor_decal_color", editor_decal_color) + RenderingServer.material_set_param(mat_rid, "_editor_decal_visible", editor_decal_visible) + RenderingServer.material_set_param(mat_rid, "_editor_crosshair_threshold", brush_data["crosshair_threshold"] + 0.1) + RenderingServer.material_set_param(mat_rid, "_region_map", r_map) + + +func is_shader_valid() -> bool: + # As long as the compiled shader contains at least 1 uniform, we can use it to check + # if the shader compilation has failed, as this will then return an empty dictionary. + if not plugin.terrain: + return false + var params = RenderingServer.get_shader_parameter_list(plugin.terrain.material.get_shader_rid()) + if params.is_empty(): + return false + else: + return true + + +func hide_decal() -> void: + editor_decal_visible = [false, false, false] + if is_shader_valid(): + var r_map: PackedInt32Array = plugin.terrain.data.get_region_map() + RenderingServer.material_set_param(mat_rid, "_editor_decal_visible", editor_decal_visible) + RenderingServer.material_set_param(mat_rid, "_region_map", r_map) + + +# These array sizes are reset to 0 when closing scenes for some unknown reason, so check and reset +func reset_decal_arrays() -> void: + if editor_decal_color.size() < 3: + editor_decal_position = [Vector2(), Vector2(), Vector2()] + editor_decal_rotation = [float(), float(), float()] + editor_decal_size = [float(), float(), float()] + editor_decal_color = [Color(), Color(), Color()] + editor_decal_visible = [false, false, false] + editor_brush_texture_rid = RID() + + +func set_decal_rotation(p_rot: float) -> void: + editor_decal_rotation[0] = p_rot + if is_shader_valid(): + RenderingServer.material_set_param(mat_rid, "_editor_decal_rotation", editor_decal_rotation) + + +func _on_picking(p_type: Terrain3DEditor.Tool, p_callback: Callable) -> void: + picking = p_type + picking_callback = p_callback + update_decal() + + +func clear_picking() -> void: + picking = Terrain3DEditor.TOOL_MAX + + +func is_picking() -> bool: + if picking != Terrain3DEditor.TOOL_MAX: + return true + + if operation_builder and operation_builder.is_picking(): + return true + + return false + + +func pick(p_global_position: Vector3) -> void: + if picking != Terrain3DEditor.TOOL_MAX: + var color: Color + match picking: + Terrain3DEditor.HEIGHT, Terrain3DEditor.SCULPT: + color = Color(plugin.terrain.data.get_height(p_global_position), 0., 0., 1.) + Terrain3DEditor.ROUGHNESS: + color = plugin.terrain.data.get_pixel(Terrain3DRegion.TYPE_COLOR, p_global_position) + Terrain3DEditor.COLOR: + color = plugin.terrain.data.get_color(p_global_position) + Terrain3DEditor.ANGLE: + color = Color(plugin.terrain.data.get_control_angle(p_global_position), 0., 0., 1.) + Terrain3DEditor.SCALE: + color = Color(plugin.terrain.data.get_control_scale(p_global_position), 0., 0., 1.) + _: + push_error("Unsupported picking type: ", picking) + return + if picking_callback.is_valid(): + picking_callback.call(picking, color, p_global_position) + picking_callback = Callable() + picking = Terrain3DEditor.TOOL_MAX + + elif operation_builder and operation_builder.is_picking(): + operation_builder.pick(p_global_position, plugin.terrain) + + +func set_button_editor_icon(p_button: Button, p_icon_name: String) -> void: + p_button.icon = EditorInterface.get_base_control().get_theme_icon(p_icon_name, "EditorIcons") diff --git a/addons/terrain_3d/src/ui.gd.uid b/addons/terrain_3d/src/ui.gd.uid new file mode 100644 index 0000000..bc20eee --- /dev/null +++ b/addons/terrain_3d/src/ui.gd.uid @@ -0,0 +1 @@ +uid://bpad72s36mwkx diff --git a/addons/terrain_3d/terrain.gdextension b/addons/terrain_3d/terrain.gdextension new file mode 100644 index 0000000..000d085 --- /dev/null +++ b/addons/terrain_3d/terrain.gdextension @@ -0,0 +1,32 @@ +[configuration] + +entry_symbol = "terrain_3d_init" +compatibility_minimum = 4.4 + +[icons] + +Terrain3D = "res://addons/terrain_3d/icons/terrain3d.svg" + +[libraries] + +windows.debug.x86_64 = "res://addons/terrain_3d/bin/libterrain.windows.debug.x86_64.dll" +windows.release.x86_64 = "res://addons/terrain_3d/bin/libterrain.windows.release.x86_64.dll" + +linux.debug.x86_64 = "res://addons/terrain_3d/bin/libterrain.linux.debug.x86_64.so" +linux.release.x86_64 = "res://addons/terrain_3d/bin/libterrain.linux.release.x86_64.so" +linux.debug.arm64 = "res://addons/terrain_3d/bin/libterrain.linux.debug.arm64.so" +linux.release.arm64 = "res://addons/terrain_3d/bin/libterrain.linux.release.arm64.so" +linux.debug.rv64 = "res://addons/terrain_3d/bin/libterrain.linux.debug.rv64.so" +linux.release.rv64 = "res://addons/terrain_3d/bin/libterrain.linux.release.rv64.so" + +macos.debug = "res://addons/terrain_3d/bin/libterrain.macos.debug.framework" +macos.release = "res://addons/terrain_3d/bin/libterrain.macos.release.framework" + +android.debug.arm64 = "res://addons/terrain_3d/bin/libterrain.android.debug.arm64.so" +android.release.arm64 = "res://addons/terrain_3d/bin/libterrain.android.release.arm64.so" + +ios.debug = "res://addons/terrain_3d/bin/libterrain.ios.debug.universal.dylib" +ios.release = "res://addons/terrain_3d/bin/libterrain.ios.release.universal.dylib" + +web.debug = "res://addons/terrain_3d/bin/libterrain.web.debug.wasm32.wasm" +web.release = "res://addons/terrain_3d/bin/libterrain.web.release.wasm32.wasm" diff --git a/addons/terrain_3d/terrain.gdextension.uid b/addons/terrain_3d/terrain.gdextension.uid new file mode 100644 index 0000000..ef58a55 --- /dev/null +++ b/addons/terrain_3d/terrain.gdextension.uid @@ -0,0 +1 @@ +uid://bdn2ygldx56a8 diff --git a/addons/terrain_3d/tools/importer.gd b/addons/terrain_3d/tools/importer.gd new file mode 100644 index 0000000..661099b --- /dev/null +++ b/addons/terrain_3d/tools/importer.gd @@ -0,0 +1,108 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Importer for Terrain3D +@tool +extends Terrain3D + + +@export var clear_all: bool = false : set = reset_settings +@export var clear_terrain: bool = false : set = reset_terrain +@export var update_height_range: bool = false : set = update_heights + + +func reset_settings(p_value) -> void: + if p_value: + height_file_name = "" + control_file_name = "" + color_file_name = "" + destination_directory = "" + import_position = Vector2i.ZERO + height_offset = 0.0 + import_scale = 1.0 + r16_range = Vector2(0, 1) + r16_size = Vector2i(1024, 1024) + material = null + assets = null + reset_terrain(true) + + +func reset_terrain(p_value) -> void: + data_directory = "" + for region:Terrain3DRegion in data.get_regions_active(): + data.remove_region(region, false) + data.update_maps(Terrain3DRegion.TYPE_MAX, true, false) + + +## Recalculates min and max heights for all regions. +func update_heights(p_value) -> void: + if p_value and data: + data.calc_height_range(true) + + +@export_group("Import File") +@export_global_file var height_file_name: String = "" +@export_global_file var control_file_name: String = "" +@export_global_file var color_file_name: String = "" +@export var import_position: Vector2i = Vector2i(0, 0) : set = set_import_position +@export var import_scale: float = 1.0 +@export var height_offset: float = 0.0 +@export var r16_range: Vector2 = Vector2(0, 1) +@export var r16_size: Vector2i = Vector2i(1024, 1024) : set = set_r16_size +@export var run_import: bool = false : set = start_import + +@export_dir var destination_directory: String = "" +@export var save_to_disk: bool = false : set = save_data + + +func set_import_position(p_value: Vector2i) -> void: + import_position.x = clamp(p_value.x, -8192, 8192) + import_position.y = clamp(p_value.y, -8192, 8192) + + +func set_r16_size(p_value: Vector2i) -> void: + r16_size.x = clamp(p_value.x, 0, 16384) + r16_size.y = clamp(p_value.y, 0, 16384) + + +func start_import(p_value: bool) -> void: + if p_value: + print("Terrain3DImporter: Importing files:\n\t%s\n\t%s\n\t%s" % [ height_file_name, control_file_name, color_file_name]) + + var imported_images: Array[Image] + imported_images.resize(Terrain3DRegion.TYPE_MAX) + var min_max := Vector2(0, 1) + var img: Image + if height_file_name: + img = Terrain3DUtil.load_image(height_file_name, ResourceLoader.CACHE_MODE_IGNORE, r16_range, r16_size) + min_max = Terrain3DUtil.get_min_max(img) + imported_images[Terrain3DRegion.TYPE_HEIGHT] = img + if control_file_name: + img = Terrain3DUtil.load_image(control_file_name, ResourceLoader.CACHE_MODE_IGNORE) + imported_images[Terrain3DRegion.TYPE_CONTROL] = img + if color_file_name: + img = Terrain3DUtil.load_image(color_file_name, ResourceLoader.CACHE_MODE_IGNORE) + imported_images[Terrain3DRegion.TYPE_COLOR] = img + if assets.get_texture_count() == 0: + material.show_checkered = false + material.show_colormap = true + var pos := Vector3(import_position.x, 0, import_position.y) + data.import_images(imported_images, pos, height_offset, import_scale) + print("Terrain3DImporter: Import finished") + + +func save_data(p_value: bool) -> void: + if destination_directory.is_empty(): + push_error("Set destination directory first") + return + data.save_directory(destination_directory) + + +@export_group("Export File") +enum { TYPE_HEIGHT, TYPE_CONTROL, TYPE_COLOR } +@export_enum("Height:0", "Control:1", "Color:2") var map_type: int = TYPE_HEIGHT +@export var file_name_out: String = "" +@export var run_export: bool = false : set = start_export + +func start_export(p_value: bool) -> void: + var err: int = data.export_image(file_name_out, map_type) + print("Terrain3DImporter: Export error status: ", err, " ", error_string(err)) + diff --git a/addons/terrain_3d/tools/importer.gd.uid b/addons/terrain_3d/tools/importer.gd.uid new file mode 100644 index 0000000..7a59538 --- /dev/null +++ b/addons/terrain_3d/tools/importer.gd.uid @@ -0,0 +1 @@ +uid://cib2rig7vup10 diff --git a/addons/terrain_3d/tools/importer.tscn b/addons/terrain_3d/tools/importer.tscn new file mode 100644 index 0000000..4bc43c3 --- /dev/null +++ b/addons/terrain_3d/tools/importer.tscn @@ -0,0 +1,63 @@ +[gd_scene load_steps=9 format=3 uid="uid://blaieaqp413k7"] + +[ext_resource type="Script" path="res://addons/terrain_3d/tools/importer.gd" id="1_60b8f"] + +[sub_resource type="Gradient" id="Gradient_88f3t"] +offsets = PackedFloat32Array(0.2, 1) +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_muvel"] +noise_type = 2 +frequency = 0.03 +cellular_jitter = 3.0 +cellular_return_type = 0 +domain_warp_enabled = true +domain_warp_type = 1 +domain_warp_amplitude = 50.0 +domain_warp_fractal_type = 2 +domain_warp_fractal_lacunarity = 1.5 +domain_warp_fractal_gain = 1.0 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_ve0yk"] +seamless = true +color_ramp = SubResource("Gradient_88f3t") +noise = SubResource("FastNoiseLite_muvel") + +[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_p55u0"] +_shader_parameters = { +"blend_sharpness": 0.87, +"height_blending": true, +"macro_variation1": Color(1, 1, 1, 1), +"macro_variation2": Color(1, 1, 1, 1), +"noise1_angle": 0.0, +"noise1_offset": Vector2(0.5, 0.5), +"noise1_scale": 0.04, +"noise2_scale": 0.076, +"noise3_scale": 0.225, +"noise_texture": SubResource("NoiseTexture2D_ve0yk"), +"vertex_normals_distance": 128.0 +} +show_checkered = true + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_8rvqy"] +cull_mode = 2 +vertex_color_use_as_albedo = true +backlight_enabled = true +backlight = Color(0.5, 0.5, 0.5, 1) + +[sub_resource type="Terrain3DMeshAsset" id="Terrain3DMeshAsset_7je72"] +height_offset = 0.5 +density = 10.0 +material_override = SubResource("StandardMaterial3D_8rvqy") +generated_type = 1 + +[sub_resource type="Terrain3DAssets" id="Terrain3DAssets_op32e"] +mesh_list = Array[Terrain3DMeshAsset]([SubResource("Terrain3DMeshAsset_7je72")]) + +[node name="Importer" type="Terrain3D"] +material = SubResource("Terrain3DMaterial_p55u0") +assets = SubResource("Terrain3DAssets_op32e") +mesh_lods = 8 +top_level = true +script = ExtResource("1_60b8f") +metadata/_edit_lock_ = true diff --git a/addons/terrain_3d/tools/region_mover.gd b/addons/terrain_3d/tools/region_mover.gd new file mode 100644 index 0000000..78dcbd8 --- /dev/null +++ b/addons/terrain_3d/tools/region_mover.gd @@ -0,0 +1,52 @@ +# This script can be used to move your regions by an offset. +# Eventually this tool will find its way into a built in UI +# +# Attach it to your Terrain3D node +# Save and reload your scene +# Select your Terrain3D node +# Enter a valid `offset` where all regions will be within -16, +15 +# Run it +# It should unload the regions, rename files, and reload them +# Clear the script and resave your scene + + +@tool +extends Terrain3D + + +@export var offset: Vector2i +@export var run: bool = false : set = start_rename + + +func start_rename(val: bool = false) -> void: + if val == false or offset == Vector2i.ZERO: + return + + var dir_name: String = data_directory + data_directory = "" + var dir := DirAccess.open(dir_name) + if not dir: + print("An error occurred when trying to access the path: ", data_directory) + return + + var affected_files: PackedStringArray + var files: PackedStringArray = dir.get_files() + for file_name in files: + if file_name.match("terrain3d*.res") and not dir.current_is_dir(): + var region_loc: Vector2i = Terrain3DUtil.filename_to_location(file_name) + var new_loc: Vector2i = region_loc + offset + if new_loc.x < -16 or new_loc.x > 15 or new_loc.y < -16 or new_loc.y > 15: + push_error("New location %.0v out of bounds for region %.0v. Aborting" % [ new_loc, region_loc ]) + return + var new_name: String = "tmp_" + Terrain3DUtil.location_to_filename(new_loc) + dir.rename(file_name, new_name) + affected_files.push_back(new_name) + print("File: %s renamed to: %s" % [ file_name, new_name ]) + + for file_name in affected_files: + var new_name: String = file_name.trim_prefix("tmp_") + dir.rename(file_name, new_name) + print("File: %s renamed to: %s" % [ file_name, new_name ]) + + data_directory = dir_name + EditorInterface.get_resource_filesystem().scan() diff --git a/addons/terrain_3d/tools/region_mover.gd.uid b/addons/terrain_3d/tools/region_mover.gd.uid new file mode 100644 index 0000000..0c9b4e5 --- /dev/null +++ b/addons/terrain_3d/tools/region_mover.gd.uid @@ -0,0 +1 @@ +uid://bngnvtbm6ifkk diff --git a/addons/terrain_3d/utils/terrain_3d_objects.gd b/addons/terrain_3d/utils/terrain_3d_objects.gd new file mode 100644 index 0000000..3a19f6d --- /dev/null +++ b/addons/terrain_3d/utils/terrain_3d_objects.gd @@ -0,0 +1,191 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Objects parent for Terrain3D +# Children nodes get transform updates on sculpting +@tool +extends Node3D +class_name Terrain3DObjects + +const TransformChangedNotifier: Script = preload("res://addons/terrain_3d/utils/transform_changed_notifier.gd") + +const CHILD_HELPER_NAME: StringName = &"TransformChangedSignaller" +const CHILD_HELPER_PATH: NodePath = ^"TransformChangedSignaller" + +var _undo_redo = null +var _terrain_id: int +var _offsets: Dictionary # Object ID -> Vector3(X, Y offset relative to terrain height, Z) +var _ignore_transform_change: bool = false + + +func _enter_tree() -> void: + if not Engine.is_editor_hint(): + return + + for child in get_children(): + _on_child_entered_tree(child) + + child_entered_tree.connect(_on_child_entered_tree) + child_exiting_tree.connect(_on_child_exiting_tree) + + +func _exit_tree() -> void: + if not Engine.is_editor_hint(): + return + + child_entered_tree.disconnect(_on_child_entered_tree) + child_exiting_tree.disconnect(_on_child_exiting_tree) + + for child in get_children(): + _on_child_exiting_tree(child) + + +func editor_setup(p_plugin) -> void: + _undo_redo = p_plugin.get_undo_redo() + + +func get_terrain() -> Terrain3D: + var terrain := instance_from_id(_terrain_id) as Terrain3D + if not terrain or terrain.is_queued_for_deletion() or not terrain.is_inside_tree(): + var terrains: Array[Node] = Engine.get_singleton(&"EditorInterface").get_edited_scene_root().find_children("", "Terrain3D") + if terrains.size() > 0: + terrain = terrains[0] + _terrain_id = terrain.get_instance_id() if terrain else 0 + + if terrain and terrain.data and not terrain.data.maps_edited.is_connected(_on_maps_edited): + terrain.data.maps_edited.connect(_on_maps_edited) + + return terrain + + +func _get_terrain_height(p_global_position: Vector3) -> float: + var terrain: Terrain3D = get_terrain() + if not terrain or not terrain.data: + return 0.0 + var height: float = terrain.data.get_height(p_global_position) + if is_nan(height): + return 0.0 + return height + + +func _on_child_entered_tree(p_node: Node) -> void: + if not (p_node is Node3D): + return + + assert(p_node.get_parent() == self) + + var helper: TransformChangedNotifier = p_node.get_node_or_null(CHILD_HELPER_PATH) + if not helper: + helper = TransformChangedNotifier.new() + helper.name = CHILD_HELPER_NAME + p_node.add_child(helper, true, INTERNAL_MODE_BACK) + assert(p_node.has_node(CHILD_HELPER_PATH)) + + # When reparenting a Node3D, Godot changes its transform _after_ reparenting it. So here, + # we must use call_deferred, to avoid receiving transform_changed as a result of reparenting. + _setup_child_signal.call_deferred(p_node, helper) + + +func _setup_child_signal(p_node: Node, helper: TransformChangedNotifier) -> void: + if not p_node.is_inside_tree(): + return + if helper.transform_changed.is_connected(_on_child_transform_changed): + return + + helper.transform_changed.connect(_on_child_transform_changed.bind(p_node)) + _update_child_offset(p_node) + + +func _on_child_exiting_tree(p_node: Node) -> void: + if not (p_node is Node3D) or not p_node.has_node(CHILD_HELPER_PATH): + return + + var helper: TransformChangedNotifier = p_node.get_node_or_null(CHILD_HELPER_PATH) + if helper: + if helper.transform_changed.is_connected(_on_child_transform_changed): + helper.transform_changed.disconnect(_on_child_transform_changed) + p_node.remove_child(helper) + helper.queue_free() + + _offsets.erase(p_node.get_instance_id()) + + +func _is_node_selected(p_node: Node) -> bool: + var editor_sel = Engine.get_singleton(&"EditorInterface").get_selection() + return editor_sel.get_transformable_selected_nodes().has(p_node) + + +func _on_child_transform_changed(p_node: Node3D) -> void: + if _ignore_transform_change: + return + + var lmb_down := Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) + if lmb_down and (_is_node_selected(p_node) or _is_node_selected(self)): + # The user may be moving the node using gizmos. + # We should wait until they're done before updating otherwise gizmos + this node conflict. + return + + if not _offsets.has(p_node.get_instance_id()): + return + + var old_offset: Vector3 = _offsets[p_node.get_instance_id()] + var old_h: float = _get_terrain_height(old_offset) + var old_position: Vector3 = old_offset + Vector3(0, old_h, 0) + var new_position: Vector3 = p_node.global_position + if old_position.is_equal_approx(new_position): + return + var new_h: float = _get_terrain_height(new_position) + var new_offset: Vector3 = new_position - Vector3(0, new_h, 0) + + var translate_without_reposition: bool = Input.is_key_pressed(KEY_SHIFT) + var y_changed: bool = not is_equal_approx(old_position.y, p_node.global_position.y) + if not y_changed and not translate_without_reposition: + new_offset.y = old_offset.y + new_position = new_offset + Vector3(0, new_h, 0) + + # Make sure that when the user undo's the translation, the offset change gets undone too! + _undo_redo.create_action("Translate", UndoRedo.MERGE_ALL) + _undo_redo.add_do_method(self, &"_set_offset_and_position", p_node.get_instance_id(), new_offset, new_position) + _undo_redo.add_undo_method(self, &"_set_offset_and_position", p_node.get_instance_id(), old_offset, old_position) + _undo_redo.commit_action() + + +func _set_offset_and_position(p_id: int, p_offset: Vector3, p_position: Vector3) -> void: + var node := instance_from_id(p_id) as Node + if not is_instance_valid(node): + return + + _ignore_transform_change = true + node.global_position = p_position + _offsets[p_id] = p_offset + _ignore_transform_change = false + + +# Overwrite current offset stored for node with its current Y position relative to the terrain +func _update_child_offset(p_node: Node3D) -> void: + var position: Vector3 = global_transform * p_node.position + var h: float = _get_terrain_height(position) + var offset: Vector3 = position - Vector3(0, h, 0) + _offsets[p_node.get_instance_id()] = offset + + +# Overwrite node's current position with terrain height + stored offset for this node +func _update_child_position(p_node: Node3D) -> void: + if not _offsets.has(p_node.get_instance_id()): + return + + var position: Vector3 = global_transform * p_node.position + var h: float = _get_terrain_height(position) + var offset: Vector3 = _offsets[p_node.get_instance_id()] + var new_position: Vector3 = global_transform.inverse() * (offset + Vector3(0, h, 0)) + if not p_node.position.is_equal_approx(new_position): + p_node.position = new_position + + +func _on_maps_edited(p_edited_aabb: AABB) -> void: + var edited_area: AABB = p_edited_aabb.grow(1) + edited_area.position.y = -INF + edited_area.end.y = INF + + for child in get_children(): + var node := child as Node3D + if node && edited_area.has_point(node.global_position): + _update_child_position(node) diff --git a/addons/terrain_3d/utils/terrain_3d_objects.gd.uid b/addons/terrain_3d/utils/terrain_3d_objects.gd.uid new file mode 100644 index 0000000..3a1e873 --- /dev/null +++ b/addons/terrain_3d/utils/terrain_3d_objects.gd.uid @@ -0,0 +1 @@ +uid://dbndw8p05yam7 diff --git a/addons/terrain_3d/utils/transform_changed_notifier.gd b/addons/terrain_3d/utils/transform_changed_notifier.gd new file mode 100644 index 0000000..5feaae8 --- /dev/null +++ b/addons/terrain_3d/utils/transform_changed_notifier.gd @@ -0,0 +1,16 @@ +# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors. +# Transform Changed Notifier for Terrain3D +@tool +extends Node3D + +signal transform_changed + + +func _ready() -> void: + assert(Engine.is_editor_hint()) + set_notify_transform(true) + + +func _notification(what: int) -> void: + if what == NOTIFICATION_TRANSFORM_CHANGED: + transform_changed.emit() diff --git a/addons/terrain_3d/utils/transform_changed_notifier.gd.uid b/addons/terrain_3d/utils/transform_changed_notifier.gd.uid new file mode 100644 index 0000000..fc43825 --- /dev/null +++ b/addons/terrain_3d/utils/transform_changed_notifier.gd.uid @@ -0,0 +1 @@ +uid://claxtgppe8keq diff --git a/demo/CodeGeneratedDemo.tscn b/demo/CodeGeneratedDemo.tscn new file mode 100644 index 0000000..8c7b5e4 --- /dev/null +++ b/demo/CodeGeneratedDemo.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=8 format=3 uid="uid://cofnhdcclon1w"] + +[ext_resource type="Script" path="res://demo/src/CodeGenerated.gd" id="1_h7vyv"] +[ext_resource type="PackedScene" uid="uid://domhm87hbhbg1" path="res://demo/components/Player.tscn" id="2_3v2uf"] +[ext_resource type="PackedScene" uid="uid://bb2lp50sjndus" path="res://demo/components/Environment.tscn" id="3_71ikj"] +[ext_resource type="PackedScene" uid="uid://di5fovhcyd7re" path="res://demo/components/Enemy.tscn" id="4_p8qry"] +[ext_resource type="PackedScene" uid="uid://d2jihfohphuue" path="res://demo/components/UI.tscn" id="4_x5ge4"] +[ext_resource type="Script" path="res://demo/src/RuntimeNavigationBaker.gd" id="5_445ur"] + +[sub_resource type="NavigationMesh" id="NavigationMesh_vs6am"] +geometry_parsed_geometry_type = 1 +agent_height = 2.0 +agent_max_slope = 30.0 + +[node name="CodeGenerated" type="Node"] +script = ExtResource("1_h7vyv") + +[node name="Environment" parent="." instance=ExtResource("3_71ikj")] + +[node name="Player" parent="." instance=ExtResource("2_3v2uf")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 50, 0) + +[node name="Enemy" parent="." node_paths=PackedStringArray("target") instance=ExtResource("4_p8qry")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 50, -10) +target = NodePath("../Player") + +[node name="UI" parent="." instance=ExtResource("4_x5ge4")] + +[node name="RuntimeNavigationBaker" type="Node" parent="." node_paths=PackedStringArray("player")] +script = ExtResource("5_445ur") +enabled = false +template = SubResource("NavigationMesh_vs6am") +player = NodePath("../Player") + +[node name="RunThisSceneLabel3D" type="Label3D" parent="."] +pixel_size = 0.001 +billboard = 1 +no_depth_test = true +fixed_size = true +text = "Run This Scene" +font_size = 64 +outline_size = 10 diff --git a/demo/Demo.tscn b/demo/Demo.tscn new file mode 100644 index 0000000..c11e4ec --- /dev/null +++ b/demo/Demo.tscn @@ -0,0 +1,99 @@ +[gd_scene load_steps=13 format=3 uid="uid://chol2xlfbq7cu"] + +[ext_resource type="Script" uid="uid://chstoagn42gbr" path="res://demo/src/DemoScene.gd" id="1_k7qca"] +[ext_resource type="PackedScene" uid="uid://d2jihfohphuue" path="res://demo/components/UI.tscn" id="2_nqak5"] +[ext_resource type="PackedScene" uid="uid://dwnhqfjq7v1pq" path="res://demo/components/Borders.tscn" id="3_cw38j"] +[ext_resource type="PackedScene" uid="uid://domhm87hbhbg1" path="res://demo/components/Player.tscn" id="3_ht63y"] +[ext_resource type="PackedScene" uid="uid://djhl3foqkj4e2" path="res://demo/components/Tunnel.tscn" id="3_kdh0b"] +[ext_resource type="PackedScene" uid="uid://bb2lp50sjndus" path="res://demo/components/Environment.tscn" id="3_yqldq"] +[ext_resource type="PackedScene" uid="uid://d3sr0a7dxfkr8" path="res://addons/terrain_3d/extras/particle_example/Terrain3DParticles.tscn" id="8_fwrtk"] +[ext_resource type="Terrain3DAssets" uid="uid://dal3jhw6241qg" path="res://demo/data/assets.tres" id="8_g2of2"] + +[sub_resource type="Gradient" id="Gradient_vr1m7"] +offsets = PackedFloat32Array(0.2, 1) +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_d8lcj"] +noise_type = 2 +frequency = 0.03 +cellular_jitter = 3.0 +cellular_return_type = 0 +domain_warp_enabled = true +domain_warp_type = 1 +domain_warp_amplitude = 50.0 +domain_warp_fractal_type = 2 +domain_warp_fractal_lacunarity = 1.5 +domain_warp_fractal_gain = 1.0 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_bov7h"] +seamless = true +color_ramp = SubResource("Gradient_vr1m7") +noise = SubResource("FastNoiseLite_d8lcj") + +[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_jrc01"] +_shader_parameters = { +"_mouse_layer": 2147483648, +"auto_base_texture": 0, +"auto_height_reduction": 0.05, +"auto_overlay_texture": 1, +"auto_slope": 0.45, +"bias_distance": 512.0, +"blend_sharpness": 0.5, +"depth_blur": 0.0, +"dual_scale_far": 170.0, +"dual_scale_near": 100.0, +"dual_scale_reduction": 0.3, +"dual_scale_texture": 0, +"enable_macro_variation": true, +"enable_projection": true, +&"flat_terrain_normals": false, +"macro_variation1": Color(0.855, 0.8625, 0.9, 1), +"macro_variation2": Color(0.9, 0.885, 0.81, 1), +"macro_variation_slope": 0.333, +"mipmap_bias": 1.0, +"noise1_angle": 0.1, +"noise1_offset": Vector2(0.5, 0.5), +"noise1_scale": 0.04, +"noise2_scale": 0.076, +"noise_texture": SubResource("NoiseTexture2D_bov7h"), +"projection_threshold": 0.87, +"tri_scale_reduction": 0.3, +"world_noise_fragment_normals": false, +"world_noise_height": 34.0, +"world_noise_lod_distance": 7500.0, +"world_noise_max_octaves": 4, +"world_noise_min_octaves": 2, +"world_noise_offset": Vector3(2.17, -1.225, 1.9), +"world_noise_region_blend": 0.33, +"world_noise_scale": 9.85 +} +world_background = 2 +auto_shader = true +dual_scaling = true + +[node name="Demo" type="Node"] +script = ExtResource("1_k7qca") + +[node name="UI" parent="." instance=ExtResource("2_nqak5")] + +[node name="Environment" parent="." instance=ExtResource("3_yqldq")] + +[node name="Borders" parent="." instance=ExtResource("3_cw38j")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 512, -3, 512) +collision_mask = 3 + +[node name="Tunnel" parent="." instance=ExtResource("3_kdh0b")] + +[node name="Player" parent="." instance=ExtResource("3_ht63y")] +transform = Transform3D(0.176947, 0, -0.98422, 0, 1, 0, 0.98422, 0, 0.176947, 223.143, 105.348, -1833.08) + +[node name="Terrain3D" type="Terrain3D" parent="."] +data_directory = "res://demo/data" +material = SubResource("Terrain3DMaterial_jrc01") +assets = ExtResource("8_g2of2") +collision_mask = 3 +top_level = true +metadata/_edit_lock_ = true + +[node name="Terrain3DParticles" parent="Terrain3D" node_paths=PackedStringArray("terrain") instance=ExtResource("8_fwrtk")] +terrain = NodePath("..") diff --git a/demo/NavigationDemo.tscn b/demo/NavigationDemo.tscn new file mode 100644 index 0000000..694a1dc --- /dev/null +++ b/demo/NavigationDemo.tscn @@ -0,0 +1,98 @@ +[gd_scene load_steps=14 format=3 uid="uid://x34e4v60vdmy"] + +[ext_resource type="Script" path="res://demo/src/DemoScene.gd" id="1_po4vw"] +[ext_resource type="PackedScene" uid="uid://bb2lp50sjndus" path="res://demo/components/Environment.tscn" id="2_i74wg"] +[ext_resource type="PackedScene" uid="uid://dwnhqfjq7v1pq" path="res://demo/components/Borders.tscn" id="3_3upu0"] +[ext_resource type="PackedScene" uid="uid://domhm87hbhbg1" path="res://demo/components/Player.tscn" id="4_fk3ul"] +[ext_resource type="PackedScene" uid="uid://djhl3foqkj4e2" path="res://demo/components/Tunnel.tscn" id="5_2lvlr"] +[ext_resource type="PackedScene" uid="uid://d2jihfohphuue" path="res://demo/components/UI.tscn" id="5_rc7e2"] +[ext_resource type="NavigationMesh" uid="uid://yf3fu23666k8" path="res://demo/data/nav_mesh.res" id="8_6jfdr"] +[ext_resource type="Terrain3DAssets" uid="uid://dal3jhw6241qg" path="res://demo/data/assets.tres" id="10_qmhh8"] +[ext_resource type="PackedScene" uid="uid://di5fovhcyd7re" path="res://demo/components/Enemy.tscn" id="12_b2xl8"] + +[sub_resource type="Gradient" id="Gradient_vr1m7"] +offsets = PackedFloat32Array(0.2, 1) +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_d8lcj"] +noise_type = 2 +frequency = 0.03 +cellular_jitter = 3.0 +cellular_return_type = 0 +domain_warp_enabled = true +domain_warp_type = 1 +domain_warp_amplitude = 50.0 +domain_warp_fractal_type = 2 +domain_warp_fractal_lacunarity = 1.5 +domain_warp_fractal_gain = 1.0 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_bov7h"] +seamless = true +color_ramp = SubResource("Gradient_vr1m7") +noise = SubResource("FastNoiseLite_d8lcj") + +[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_s5mq5"] +_shader_parameters = { +"_mouse_layer": 2147483648, +"auto_base_texture": 0, +"auto_height_reduction": 0.1, +"auto_overlay_texture": 1, +"auto_slope": 1.0, +"bias_distance": 512.0, +"blend_sharpness": 0.87, +"depth_blur": 0.0, +"dual_scale_far": 170.0, +"dual_scale_near": 100.0, +"dual_scale_reduction": 0.3, +"dual_scale_texture": 0, +"enable_macro_variation": true, +"enable_projection": true, +"height_blending": true, +"macro_variation1": Color(0.878431, 0.862745, 0.901961, 1), +"macro_variation2": Color(0.898039, 0.898039, 0.803922, 1), +"macro_variation_slope": 0.333, +"mipmap_bias": 1.0, +"noise1_angle": 0.1, +"noise1_offset": Vector2(0.5, 0.5), +"noise1_scale": 0.04, +"noise2_scale": 0.076, +"noise3_scale": 0.225, +"noise_texture": SubResource("NoiseTexture2D_bov7h"), +"projection_angular_division": 1.436, +"projection_threshold": 0.8, +"tri_scale_reduction": 0.3 +} +world_background = 0 +auto_shader = true +dual_scaling = true + +[node name="Demo" type="Node"] +script = ExtResource("1_po4vw") + +[node name="UI" parent="." instance=ExtResource("5_rc7e2")] + +[node name="Environment" parent="." instance=ExtResource("2_i74wg")] + +[node name="Borders" parent="." instance=ExtResource("3_3upu0")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 512, -2.5, 512) + +[node name="Tunnel" parent="." instance=ExtResource("5_2lvlr")] + +[node name="Player" parent="." instance=ExtResource("4_fk3ul")] +transform = Transform3D(0.0774673, 0, -0.996995, 0, 1, 0, 0.996995, 0, 0.0774673, 229.418, 104.956, -1838.16) + +[node name="Enemy" parent="." node_paths=PackedStringArray("target") instance=ExtResource("12_b2xl8")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 192.727, 105.171, -1787.81) +target = NodePath("../Player") + +[node name="NavigationRegion3D" type="NavigationRegion3D" parent="."] +navigation_mesh = ExtResource("8_6jfdr") + +[node name="Terrain3D" type="Terrain3D" parent="NavigationRegion3D"] +data_directory = "res://demo/data" +material = SubResource("Terrain3DMaterial_s5mq5") +assets = ExtResource("10_qmhh8") +collision_mask = 3 +mesh_size = 64 +top_level = true +metadata/_edit_lock_ = true diff --git a/demo/assets/materials/M_crystal_blue.tres b/demo/assets/materials/M_crystal_blue.tres new file mode 100644 index 0000000..6d55603 --- /dev/null +++ b/demo/assets/materials/M_crystal_blue.tres @@ -0,0 +1,25 @@ +[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://fkhkir6t1hml"] + +[ext_resource type="Texture2D" uid="uid://c307hdmos4gtm" path="res://demo/assets/textures/rock023_nrm_rgh.png" id="2_3is54"] + +[resource] +transparency = 1 +vertex_color_use_as_albedo = true +albedo_color = Color(0.4, 1, 1, 0.647059) +metallic_specular = 1.0 +roughness = 0.2 +roughness_texture = ExtResource("2_3is54") +roughness_texture_channel = 3 +emission_enabled = true +emission = Color(0, 0.145098, 0.776471, 1) +emission_energy_multiplier = 1.4 +normal_enabled = true +normal_scale = 0.4 +normal_texture = ExtResource("2_3is54") +rim_enabled = true +rim = 0.25 +clearcoat_roughness = 0.0 +ao_light_affect = 1.0 +ao_texture_channel = 3 +refraction_enabled = true +refraction_scale = -0.1 diff --git a/demo/assets/materials/M_crystal_purple.tres b/demo/assets/materials/M_crystal_purple.tres new file mode 100644 index 0000000..a7905c6 --- /dev/null +++ b/demo/assets/materials/M_crystal_purple.tres @@ -0,0 +1,24 @@ +[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cso4f2iyuxpmc"] + +[ext_resource type="Texture2D" uid="uid://c307hdmos4gtm" path="res://demo/assets/textures/rock023_nrm_rgh.png" id="2_1t610"] + +[resource] +transparency = 1 +vertex_color_use_as_albedo = true +albedo_color = Color(0.4, 0.4, 1, 0.556863) +metallic_specular = 1.0 +roughness = 0.2 +roughness_texture = ExtResource("2_1t610") +roughness_texture_channel = 3 +emission_enabled = true +emission = Color(0.235294, 0.145098, 0.776471, 1) +normal_enabled = true +normal_scale = 0.4 +normal_texture = ExtResource("2_1t610") +rim_enabled = true +rim = 0.25 +clearcoat_roughness = 0.0 +ao_light_affect = 1.0 +ao_texture_channel = 3 +refraction_enabled = true +refraction_scale = -0.1 diff --git a/demo/assets/materials/M_crystal_red.tres b/demo/assets/materials/M_crystal_red.tres new file mode 100644 index 0000000..dd8108c --- /dev/null +++ b/demo/assets/materials/M_crystal_red.tres @@ -0,0 +1,24 @@ +[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ickkffutwcvo"] + +[ext_resource type="Texture2D" uid="uid://c307hdmos4gtm" path="res://demo/assets/textures/rock023_nrm_rgh.png" id="2_k2yhv"] + +[resource] +transparency = 1 +albedo_color = Color(0.670588, 0.0588235, 0.384314, 0.509804) +metallic_specular = 1.0 +roughness = 0.2 +roughness_texture = ExtResource("2_k2yhv") +roughness_texture_channel = 3 +emission_enabled = true +emission = Color(0.258824, 0.0823529, 0.25098, 1) +normal_enabled = true +normal_scale = 0.4 +normal_texture = ExtResource("2_k2yhv") +rim_enabled = true +rim = 0.25 +clearcoat_roughness = 0.0 +ao_enabled = true +ao_light_affect = 1.0 +ao_texture_channel = 3 +refraction_enabled = true +refraction_scale = -0.1 diff --git a/demo/assets/materials/M_rock23_black_tp.tres b/demo/assets/materials/M_rock23_black_tp.tres new file mode 100644 index 0000000..57bde2c --- /dev/null +++ b/demo/assets/materials/M_rock23_black_tp.tres @@ -0,0 +1,17 @@ +[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://d0hyi5n6ng25w"] + +[ext_resource type="Texture2D" uid="uid://c88j3oj0lf6om" path="res://demo/assets/textures/rock023_alb_ht.png" id="1_1js8i"] +[ext_resource type="Texture2D" uid="uid://c307hdmos4gtm" path="res://demo/assets/textures/rock023_nrm_rgh.png" id="2_snl3x"] + +[resource] +albedo_color = Color(0.501406, 0.501407, 0.501406, 1) +albedo_texture = ExtResource("1_1js8i") +roughness = 0.95 +roughness_texture = ExtResource("2_snl3x") +roughness_texture_channel = 3 +normal_enabled = true +normal_texture = ExtResource("2_snl3x") +uv1_scale = Vector3(0.4, 0.4, 0.4) +uv1_triplanar = true +uv1_world_triplanar = true +texture_filter = 5 diff --git a/demo/assets/materials/M_rock23_tp.tres b/demo/assets/materials/M_rock23_tp.tres new file mode 100644 index 0000000..268aae1 --- /dev/null +++ b/demo/assets/materials/M_rock23_tp.tres @@ -0,0 +1,16 @@ +[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://nbbdrx8vma80"] + +[ext_resource type="Texture2D" uid="uid://c88j3oj0lf6om" path="res://demo/assets/textures/rock023_alb_ht.png" id="1_mek0c"] +[ext_resource type="Texture2D" uid="uid://c307hdmos4gtm" path="res://demo/assets/textures/rock023_nrm_rgh.png" id="2_pp13c"] + +[resource] +vertex_color_use_as_albedo = true +albedo_color = Color(0.83, 0.83, 0.83, 1) +albedo_texture = ExtResource("1_mek0c") +normal_enabled = true +normal_texture = ExtResource("2_pp13c") +uv1_scale = Vector3(0.02, 0.02, 0.02) +uv1_triplanar = true +uv1_triplanar_sharpness = 6.06286 +uv1_world_triplanar = true +texture_filter = 5 diff --git a/demo/assets/models/CrystalC.tscn b/demo/assets/models/CrystalC.tscn new file mode 100644 index 0000000..ede436b --- /dev/null +++ b/demo/assets/models/CrystalC.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=4 format=3 uid="uid://cribhhvg03u8g"] + +[ext_resource type="PackedScene" uid="uid://c8cx4xjwluvxw" path="res://demo/assets/models/RockC.glb" id="1_1vww1"] +[ext_resource type="Material" uid="uid://fkhkir6t1hml" path="res://demo/assets/materials/M_crystal_blue.tres" id="2_fclne"] + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_ycsjC"] +data = PackedVector3Array(1.3907, -4.3898, 0.264, 0.3707, -6.5026, 0.2358, 0.9197, -5.2139, 0.5803, 1.3907, -4.3898, 0.264, 1.5973, -4.4989, -0.523, 0.3707, -6.5026, 0.2358, 2.7182, -1.9153, 1.6333, 2.6862, -0.2733, 1.344, 2.791, -2.0828, 0.6971, -0.6892, -7.3327, -0.0456, -1.2211, -6.6432, -1.3733, -1.8677, -6.7222, 0.0053, 0.1584, -6.6788, -0.712, 0.8528, -5.1659, -1.2387, -0.129, -6.0155, -1.6627, 0.3707, -6.5026, 0.2358, 0.8249, -4.8431, 1.2373, 0.9197, -5.2139, 0.5803, 0.3707, -6.5026, 0.2358, -0.1504, -6.0468, 1.6347, 0.8249, -4.8431, 1.2373, 2.7182, -1.9153, 1.6333, 2.5729, -0.0463, 2.323, 2.6862, -0.2733, 1.344, -1.5434, -2.0626, 2.9798, -0.0319, -0.907, 3.3884, -0.6296, -2.1168, 3.0274, -1.5434, -2.0626, 2.9798, -2.2391, -1.0013, 3.2378, -0.0319, -0.907, 3.3884, -3.2503, -1.9438, -0.0444, -3.1045, -0.0443, -0.8667, -2.9895, -0.0523, 0.8233, -0.5191, -2.1018, -2.9939, -2.0489, -0.9812, -3.014, -1.4897, -2.0239, -2.8933, -0.5191, -2.1018, -2.9939, 0.0444, -0.8451, -3.3989, -2.0489, -0.9812, -3.014, 3.4189, -1.5098, -2.1519, 3.3947, 0.8197, -1.419, 2.9911, 0.177, -2.5055, -0.9484, -5.3598, 2.2535, -0.8975, -3.7031, 2.6018, -0.1302, -3.9225, 2.4564, -2.8602, -5.2902, -0.0034, -3.2063, -3.9919, -0.0118, -3.0246, -4.4027, 0.8468, -0.9423, -5.2303, -2.2174, -1.6189, -3.1121, -2.5666, -2.3373, -3.6333, -2.2624, -0.9423, -5.2303, -2.2174, -0.9004, -3.6647, -2.5803, -1.6189, -3.1121, -2.5666, 2.4159, -3.3908, 0.0683, 2.6374, -3.7219, -1.0723, 1.5973, -4.4989, -0.523, 0.0817, 0.7564, 3.232, 1.3747, 1.7762, 2.618, 1.9677, 0.877, 2.8315, 0.0817, 0.7564, 3.232, 0.5064, 1.8556, 2.7003, 1.3747, 1.7762, 2.618, -0.2637, 3.5029, 1.8153, 0.4487, 4.8708, 1.6514, 0.6919, 3.2703, 2.2188, -2.3926, 3.3478, 0.3255, -1.6818, 3.3981, 1.0198, -2.0691, 2.5964, 1.5185, -1.2285, 2.4662, -2.4325, -1.544, 3.8438, -1.471, -2.3777, 2.1645, -2.0413, 2.3543, 3.9299, -1.7328, 1.4379, 5.2295, -1.8152, 1.1494, 2.3687, -2.734, 1.4341, 6.0081, 1.2447, 0.9325, 6.924, 0.4365, 2.3528, 6.0999, 0.4838, -1.8677, -6.7222, 0.0053, -2.3434, -5.4566, 1.3758, -1.2352, -6.7568, 1.4079, 3.0694, 0.3768, 0.2917, 3.6836, 2.3906, 0.1427, 3.39, -0.1345, -0.5433, 1.5686, 6.857, -0.4389, 0.7824, 7.1818, -0.4789, 0.9515, 6.8097, -1.0683, 2.4165, 5.7335, -0.6508, 1.4379, 5.2295, -1.8152, 2.3543, 3.9299, -1.7328, 2.0681, 1.0413, -2.9849, 1.1494, 2.3687, -2.734, 0.0399, 0.8971, -3.3453, -0.1803, 5.4522, -1.6664, -0.2609, 6.3493, -0.8464, -1.544, 3.8438, -1.471, -3.1045, -0.0443, -0.8667, -2.9635, 2.0631, -0.0469, -2.9895, -0.0523, 0.8233, -2.8218, -0.0908, -2.3316, -2.8949, 1.7465, -1.4628, -3.1045, -0.0443, -0.8667, -1.137, 5.0901, -0.2048, -0.2548, 6.3653, 0.3115, -0.7059, 4.7856, 0.8682, -1.8973, 4.0438, -0.0231, -1.6818, 3.3981, 1.0198, -2.3926, 3.3478, 0.3255, -2.9895, -0.0523, 0.8233, -2.7222, 1.5834, 1.3251, -2.9289, -0.1232, 2.5316, -0.7059, 4.7856, 0.8682, -0.2548, 6.3653, 0.3115, 0.4487, 4.8708, 1.6514, -0.7059, 4.7856, 0.8682, 0.4487, 4.8708, 1.6514, -0.2637, 3.5029, 1.8153, 3.3947, 0.8197, -1.419, 3.6143, 2.6541, -0.7787, 3.0814, 2.2747, -1.5878, 3.3017, 4.3689, -0.5397, 2.4165, 5.7335, -0.6508, 2.3543, 3.9299, -1.7328, -2.1314, 0.7603, 3.0046, -1.0522, 1.986, 2.2721, 0.0817, 0.7564, 3.232, 0.0399, 0.8971, -3.3453, 1.1494, 2.3687, -2.734, -1.2285, 2.4662, -2.4325, 0.549, 3.3793, -2.5003, 0.4374, 4.5707, -2.224, -0.1459, 3.4745, -2.3857, 1.4341, 6.0081, 1.2447, 2.3528, 6.0999, 0.4838, 2.8818, 4.7444, 1.3483, -3.1045, -0.0443, -0.8667, -2.8949, 1.7465, -1.4628, -2.9635, 2.0631, -0.0469, -2.7186, 2.9035, -1.3821, -2.3162, 3.6228, -0.9721, -2.7435, 3.293, -0.5137, -0.1803, 5.4522, -1.6664, -1.544, 3.8438, -1.471, -1.2285, 2.4662, -2.4325, -2.1314, 0.7603, 3.0046, -2.0691, 2.5964, 1.5185, -1.0522, 1.986, 2.2721, -2.0691, 2.5964, 1.5185, -1.6818, 3.3981, 1.0198, -1.0522, 1.986, 2.2721, 0.0399, 0.8971, -3.3453, -1.2285, 2.4662, -2.4325, -2.0395, 0.8474, -2.9039, 1.9677, 0.877, 2.8315, 1.5121, 2.8416, 2.3106, 2.2766, 3.3307, 2.1367, 1.9677, 0.877, 2.8315, 1.3747, 1.7762, 2.618, 1.5121, 2.8416, 2.3106, 0.6919, 3.2703, 2.2188, 2.2766, 3.3307, 2.1367, 1.5121, 2.8416, 2.3106, 0.6919, 3.2703, 2.2188, 0.4487, 4.8708, 1.6514, 2.2766, 3.3307, 2.1367, 3.3947, 0.8197, -1.419, 3.0814, 2.2747, -1.5878, 2.9911, 0.177, -2.5055, 2.8818, 4.7444, 1.3483, 2.3528, 6.0999, 0.4838, 3.481, 4.5391, 0.4718, 2.0681, 1.0413, -2.9849, 2.3543, 3.9299, -1.7328, 1.1494, 2.3687, -2.734, 2.5729, -0.0463, 2.323, 2.8449, 1.8063, 1.8788, 2.6862, -0.2733, 1.344, -1.4897, -2.0239, -2.8933, -2.3373, -3.6333, -2.2624, -1.6189, -3.1121, -2.5666, -1.4897, -2.0239, -2.8933, -2.0489, -0.9812, -3.014, -2.3373, -3.6333, -2.2624, -2.0395, 0.8474, -2.9039, -1.2285, 2.4662, -2.4325, -2.3777, 2.1645, -2.0413, 2.1308, -0.8122, -3.0291, 0.0444, -0.8451, -3.3989, 1.2123, -2.2074, -2.6786, -3.2503, -1.9438, -0.0444, -2.9895, -0.0523, 0.8233, -3.048, -2.4163, 1.5053, -2.9895, -0.0523, 0.8233, -2.9635, 2.0631, -0.0469, -2.7222, 1.5834, 1.3251, -2.8218, -0.0908, -2.3316, -3.1045, -0.0443, -0.8667, -3.1353, -2.4738, -1.533, -0.6296, -2.1168, 3.0274, -0.0319, -0.907, 3.3884, 0.6607, -2.1929, 2.7904, 0.0817, 0.7564, 3.232, -1.0522, 1.986, 2.2721, 0.5064, 1.8556, 2.7003, 3.0694, 0.3768, 0.2917, 3.39, -0.1345, -0.5433, 3.0799, -1.877, -0.2485, 2.332, -3.2513, 1.4491, 1.8096, -3.8731, 0.517, 1.7532, -3.8773, 1.1862, 2.332, -3.2513, 1.4491, 2.4159, -3.3908, 0.0683, 1.8096, -3.8731, 0.517, 3.0694, 0.3768, 0.2917, 3.2927, 2.696, 1.0915, 3.6836, 2.3906, 0.1427, 0.8528, -5.1659, -1.2387, 0.5989, -4.5033, -1.836, -0.129, -6.0155, -1.6627, 1.6723, -4.1113, -1.5062, 2.2303, -3.7001, -1.8804, 1.5835, -3.611, -1.9401, 2.6485, -2.4319, -2.56, 2.1308, -0.8122, -3.0291, 1.2123, -2.2074, -2.6786, -1.2211, -6.6432, -1.3733, -2.3738, -5.4707, -1.3892, -1.8677, -6.7222, 0.0053, 1.2123, -2.2074, -2.6786, 0.0444, -0.8451, -3.3989, -0.5191, -2.1018, -2.9939, -0.9423, -5.2303, -2.2174, -0.0313, -3.8492, -2.3572, -0.9004, -3.6647, -2.5803, -2.9895, -0.0523, 0.8233, -2.9289, -0.1232, 2.5316, -3.048, -2.4163, 1.5053, -3.1353, -2.4738, -1.533, -3.1045, -0.0443, -0.8667, -3.2503, -1.9438, -0.0444, -2.8602, -5.2902, -0.0034, -3.0733, -4.4498, -0.8737, -3.2063, -3.9919, -0.0118, -0.1504, -6.0468, 1.6347, 0.6052, -4.4095, 1.8566, 0.8249, -4.8431, 1.2373, -2.3213, -3.5933, 2.2613, -1.5434, -2.0626, 2.9798, -1.6095, -3.1051, 2.5592, -2.3213, -3.5933, 2.2613, -2.2391, -1.0013, 3.2378, -1.5434, -2.0626, 2.9798, 3.0799, -1.877, -0.2485, 3.39, -0.1345, -0.5433, 3.4106, -2.2767, -1.2285, -0.0319, -0.907, 3.3884, 1.8364, -0.871, 2.91, 0.6607, -2.1929, 2.7904, 1.7532, -3.8773, 1.1862, 1.5121, -3.4321, 1.801, 2.332, -3.2513, 1.4491, -0.9484, -5.3598, 2.2535, -1.6095, -3.1051, 2.5592, -0.8975, -3.7031, 2.6018, -0.9484, -5.3598, 2.2535, -2.3213, -3.5933, 2.2613, -1.6095, -3.1051, 2.5592, 2.4159, -3.3908, 0.0683, 1.3907, -4.3898, 0.264, 1.8096, -3.8731, 0.517, 2.4159, -3.3908, 0.0683, 1.5973, -4.4989, -0.523, 1.3907, -4.3898, 0.264, 0.6607, -2.1929, 2.7904, 1.8364, -0.871, 2.91, 2.1556, -2.2057, 2.3132, -0.6892, -7.3327, -0.0456, 0.3707, -6.5026, 0.2358, 0.1584, -6.6788, -0.712, 2.7182, -1.9153, 1.6333, 2.332, -3.2513, 1.4491, 2.1556, -2.2057, 2.3132, -0.8975, -3.7031, 2.6018, -1.5434, -2.0626, 2.9798, -0.6296, -2.1168, 3.0274, -0.8975, -3.7031, 2.6018, -1.6095, -3.1051, 2.5592, -1.5434, -2.0626, 2.9798, -0.5191, -2.1018, -2.9939, -1.6189, -3.1121, -2.5666, -0.9004, -3.6647, -2.5803, -0.5191, -2.1018, -2.9939, -1.4897, -2.0239, -2.8933, -1.6189, -3.1121, -2.5666, 3.4106, -2.2767, -1.2285, 2.2303, -3.7001, -1.8804, 2.6374, -3.7219, -1.0723, 2.2303, -3.7001, -1.8804, 3.4189, -1.5098, -2.1519, 2.6485, -2.4319, -2.56, 2.2303, -3.7001, -1.8804, 3.4106, -2.2767, -1.2285, 3.4189, -1.5098, -2.1519, 0.6919, 3.2703, 2.2188, 1.3747, 1.7762, 2.618, 0.5064, 1.8556, 2.7003, 0.6919, 3.2703, 2.2188, 1.5121, 2.8416, 2.3106, 1.3747, 1.7762, 2.618, -2.7186, 2.9035, -1.3821, -2.8949, 1.7465, -1.4628, -2.3777, 2.1645, -2.0413, 3.6143, 2.6541, -0.7787, 3.481, 4.5391, 0.4718, 3.3017, 4.3689, -0.5397, 3.6143, 2.6541, -0.7787, 3.6836, 2.3906, 0.1427, 3.481, 4.5391, 0.4718, 0.7824, 7.1818, -0.4789, -0.2548, 6.3653, 0.3115, -0.2609, 6.3493, -0.8464, 0.7824, 7.1818, -0.4789, 0.9325, 6.924, 0.4365, -0.2548, 6.3653, 0.3115, -0.1504, -6.0468, 1.6347, -1.2352, -6.7568, 1.4079, -0.9484, -5.3598, 2.2535, 1.8096, -3.8731, 0.517, 0.8249, -4.8431, 1.2373, 1.7532, -3.8773, 1.1862, 0.8249, -4.8431, 1.2373, 1.3907, -4.3898, 0.264, 0.9197, -5.2139, 0.5803, 0.8249, -4.8431, 1.2373, 1.8096, -3.8731, 0.517, 1.3907, -4.3898, 0.264, -0.1302, -3.9225, 2.4564, 1.5121, -3.4321, 1.801, 0.6052, -4.4095, 1.8566, -0.1302, -3.9225, 2.4564, 0.6607, -2.1929, 2.7904, 1.5121, -3.4321, 1.801, 2.4159, -3.3908, 0.0683, 2.791, -2.0828, 0.6971, 3.0799, -1.877, -0.2485, 1.5973, -4.4989, -0.523, 1.6723, -4.1113, -1.5062, 0.8528, -5.1659, -1.2387, -3.0246, -4.4027, 0.8468, -2.3213, -3.5933, 2.2613, -2.3434, -5.4566, 1.3758, -3.0246, -4.4027, 0.8468, -3.048, -2.4163, 1.5053, -2.3213, -3.5933, 2.2613, -1.2211, -6.6432, -1.3733, -0.129, -6.0155, -1.6627, -0.9423, -5.2303, -2.2174, -3.0733, -4.4498, -0.8737, -2.3373, -3.6333, -2.2624, -3.1353, -2.4738, -1.533, -3.0733, -4.4498, -0.8737, -2.3738, -5.4707, -1.3892, -2.3373, -3.6333, -2.2624, 1.5835, -3.611, -1.9401, -0.0313, -3.8492, -2.3572, 0.5989, -4.5033, -1.836, 1.5835, -3.611, -1.9401, 1.2123, -2.2074, -2.6786, -0.0313, -3.8492, -2.3572, 2.5729, -0.0463, 2.323, 1.8364, -0.871, 2.91, 1.9677, 0.877, 2.8315, -2.9289, -0.1232, 2.5316, -2.1314, 0.7603, 3.0046, -2.2391, -1.0013, 3.2378, -2.0395, 0.8474, -2.9039, -2.8218, -0.0908, -2.3316, -2.0489, -0.9812, -3.014, 2.1308, -0.8122, -3.0291, 2.9911, 0.177, -2.5055, 2.0681, 1.0413, -2.9849, 3.2927, 2.696, 1.0915, 2.2766, 3.3307, 2.1367, 2.8818, 4.7444, 1.3483, 3.2927, 2.696, 1.0915, 2.8449, 1.8063, 1.8788, 2.2766, 3.3307, 2.1367, -2.9635, 2.0631, -0.0469, -2.7435, 3.293, -0.5137, -2.3926, 3.3478, 0.3255, 2.3528, 6.0999, 0.4838, 1.5686, 6.857, -0.4389, 2.4165, 5.7335, -0.6508, -2.3162, 3.6228, -0.9721, -1.137, 5.0901, -0.2048, -1.8973, 4.0438, -0.0231, -2.3162, 3.6228, -0.9721, -1.544, 3.8438, -1.471, -1.137, 5.0901, -0.2048, 0.4374, 4.5707, -2.224, 0.9515, 6.8097, -1.0683, -0.1803, 5.4522, -1.6664, 0.4374, 4.5707, -2.224, 1.4379, 5.2295, -1.8152, 0.9515, 6.8097, -1.0683, -1.2352, -6.7568, 1.4079, 0.3707, -6.5026, 0.2358, -0.6892, -7.3327, -0.0456, -1.2352, -6.7568, 1.4079, -0.1504, -6.0468, 1.6347, 0.3707, -6.5026, 0.2358, 0.6607, -2.1929, 2.7904, -0.8975, -3.7031, 2.6018, -0.6296, -2.1168, 3.0274, 0.6607, -2.1929, 2.7904, -0.1302, -3.9225, 2.4564, -0.8975, -3.7031, 2.6018, 2.791, -2.0828, 0.6971, 2.332, -3.2513, 1.4491, 2.7182, -1.9153, 1.6333, 2.791, -2.0828, 0.6971, 2.4159, -3.3908, 0.0683, 2.332, -3.2513, 1.4491, 1.6723, -4.1113, -1.5062, 2.6374, -3.7219, -1.0723, 2.2303, -3.7001, -1.8804, 1.6723, -4.1113, -1.5062, 1.5973, -4.4989, -0.523, 2.6374, -3.7219, -1.0723, -3.048, -2.4163, 1.5053, -3.2063, -3.9919, -0.0118, -3.2503, -1.9438, -0.0444, -3.048, -2.4163, 1.5053, -3.0246, -4.4027, 0.8468, -3.2063, -3.9919, -0.0118, -0.129, -6.0155, -1.6627, -0.6892, -7.3327, -0.0456, 0.1584, -6.6788, -0.712, -0.129, -6.0155, -1.6627, -1.2211, -6.6432, -1.3733, -0.6892, -7.3327, -0.0456, 1.2123, -2.2074, -2.6786, 2.2303, -3.7001, -1.8804, 2.6485, -2.4319, -2.56, 1.2123, -2.2074, -2.6786, 1.5835, -3.611, -1.9401, 2.2303, -3.7001, -1.8804, 3.3947, 0.8197, -1.419, 3.6836, 2.3906, 0.1427, 3.6143, 2.6541, -0.7787, 3.3947, 0.8197, -1.419, 3.39, -0.1345, -0.5433, 3.6836, 2.3906, 0.1427, -2.1314, 0.7603, 3.0046, -2.7222, 1.5834, 1.3251, -2.0691, 2.5964, 1.5185, -2.1314, 0.7603, 3.0046, -2.9289, -0.1232, 2.5316, -2.7222, 1.5834, 1.3251, 2.9911, 0.177, -2.5055, 2.6485, -2.4319, -2.56, 3.4189, -1.5098, -2.1519, 2.9911, 0.177, -2.5055, 2.1308, -0.8122, -3.0291, 2.6485, -2.4319, -2.56, -2.7435, 3.293, -0.5137, -2.8949, 1.7465, -1.4628, -2.7186, 2.9035, -1.3821, -2.7435, 3.293, -0.5137, -2.9635, 2.0631, -0.0469, -2.8949, 1.7465, -1.4628, -0.1459, 3.4745, -2.3857, 1.1494, 2.3687, -2.734, 0.549, 3.3793, -2.5003, -0.1459, 3.4745, -2.3857, -1.2285, 2.4662, -2.4325, 1.1494, 2.3687, -2.734, 2.3543, 3.9299, -1.7328, 3.6143, 2.6541, -0.7787, 3.3017, 4.3689, -0.5397, 2.3543, 3.9299, -1.7328, 3.0814, 2.2747, -1.5878, 3.6143, 2.6541, -0.7787, 1.5686, 6.857, -0.4389, 0.9325, 6.924, 0.4365, 0.7824, 7.1818, -0.4789, 1.5686, 6.857, -0.4389, 2.3528, 6.0999, 0.4838, 0.9325, 6.924, 0.4365, -1.544, 3.8438, -1.471, -2.7186, 2.9035, -1.3821, -2.3777, 2.1645, -2.0413, -1.544, 3.8438, -1.471, -2.3162, 3.6228, -0.9721, -2.7186, 2.9035, -1.3821, 1.4379, 5.2295, -1.8152, 0.549, 3.3793, -2.5003, 1.1494, 2.3687, -2.734, 1.4379, 5.2295, -1.8152, 0.4374, 4.5707, -2.224, 0.549, 3.3793, -2.5003, 2.1556, -2.2057, 2.3132, 1.5121, -3.4321, 1.801, 0.6607, -2.1929, 2.7904, 2.1556, -2.2057, 2.3132, 2.332, -3.2513, 1.4491, 1.5121, -3.4321, 1.801, 3.4106, -2.2767, -1.2285, 2.4159, -3.3908, 0.0683, 3.0799, -1.877, -0.2485, 3.4106, -2.2767, -1.2285, 2.6374, -3.7219, -1.0723, 2.4159, -3.3908, 0.0683, 0.1584, -6.6788, -0.712, 1.5973, -4.4989, -0.523, 0.8528, -5.1659, -1.2387, 0.1584, -6.6788, -0.712, 0.3707, -6.5026, 0.2358, 1.5973, -4.4989, -0.523, -3.2503, -1.9438, -0.0444, -3.0733, -4.4498, -0.8737, -3.1353, -2.4738, -1.533, -3.2503, -1.9438, -0.0444, -3.2063, -3.9919, -0.0118, -3.0733, -4.4498, -0.8737, -0.5191, -2.1018, -2.9939, -0.0313, -3.8492, -2.3572, 1.2123, -2.2074, -2.6786, -0.5191, -2.1018, -2.9939, -0.9004, -3.6647, -2.5803, -0.0313, -3.8492, -2.3572, 3.4189, -1.5098, -2.1519, 3.39, -0.1345, -0.5433, 3.3947, 0.8197, -1.419, 3.4189, -1.5098, -2.1519, 3.4106, -2.2767, -1.2285, 3.39, -0.1345, -0.5433, 2.7182, -1.9153, 1.6333, 1.8364, -0.871, 2.91, 2.5729, -0.0463, 2.323, 2.7182, -1.9153, 1.6333, 2.1556, -2.2057, 2.3132, 1.8364, -0.871, 2.91, -2.3777, 2.1645, -2.0413, -2.8218, -0.0908, -2.3316, -2.0395, 0.8474, -2.9039, -2.3777, 2.1645, -2.0413, -2.8949, 1.7465, -1.4628, -2.8218, -0.0908, -2.3316, 3.481, 4.5391, 0.4718, 3.2927, 2.696, 1.0915, 2.8818, 4.7444, 1.3483, 3.481, 4.5391, 0.4718, 3.6836, 2.3906, 0.1427, 3.2927, 2.696, 1.0915, 0.6919, 3.2703, 2.2188, -1.0522, 1.986, 2.2721, -0.2637, 3.5029, 1.8153, 0.6919, 3.2703, 2.2188, 0.5064, 1.8556, 2.7003, -1.0522, 1.986, 2.2721, -2.0691, 2.5964, 1.5185, -2.9635, 2.0631, -0.0469, -2.3926, 3.3478, 0.3255, -2.0691, 2.5964, 1.5185, -2.7222, 1.5834, 1.3251, -2.9635, 2.0631, -0.0469, -0.2548, 6.3653, 0.3115, 1.4341, 6.0081, 1.2447, 0.4487, 4.8708, 1.6514, -0.2548, 6.3653, 0.3115, 0.9325, 6.924, 0.4365, 1.4341, 6.0081, 1.2447, 3.3017, 4.3689, -0.5397, 2.3528, 6.0999, 0.4838, 2.4165, 5.7335, -0.6508, 3.3017, 4.3689, -0.5397, 3.481, 4.5391, 0.4718, 2.3528, 6.0999, 0.4838, -0.2609, 6.3493, -0.8464, -1.137, 5.0901, -0.2048, -1.544, 3.8438, -1.471, -0.2609, 6.3493, -0.8464, -0.2548, 6.3653, 0.3115, -1.137, 5.0901, -0.2048, 0.7824, 7.1818, -0.4789, -0.1803, 5.4522, -1.6664, 0.9515, 6.8097, -1.0683, 0.7824, 7.1818, -0.4789, -0.2609, 6.3493, -0.8464, -0.1803, 5.4522, -1.6664, 2.4165, 5.7335, -0.6508, 0.9515, 6.8097, -1.0683, 1.4379, 5.2295, -1.8152, 2.4165, 5.7335, -0.6508, 1.5686, 6.857, -0.4389, 0.9515, 6.8097, -1.0683, 0.4374, 4.5707, -2.224, -1.2285, 2.4662, -2.4325, -0.1459, 3.4745, -2.3857, 0.4374, 4.5707, -2.224, -0.1803, 5.4522, -1.6664, -1.2285, 2.4662, -2.4325, -1.8973, 4.0438, -0.0231, -0.7059, 4.7856, 0.8682, -1.6818, 3.3981, 1.0198, -1.8973, 4.0438, -0.0231, -1.137, 5.0901, -0.2048, -0.7059, 4.7856, 0.8682, -2.3162, 3.6228, -0.9721, -2.3926, 3.3478, 0.3255, -2.7435, 3.293, -0.5137, -2.3162, 3.6228, -0.9721, -1.8973, 4.0438, -0.0231, -2.3926, 3.3478, 0.3255, -1.6818, 3.3981, 1.0198, -0.2637, 3.5029, 1.8153, -1.0522, 1.986, 2.2721, -1.6818, 3.3981, 1.0198, -0.7059, 4.7856, 0.8682, -0.2637, 3.5029, 1.8153, 0.4487, 4.8708, 1.6514, 2.8818, 4.7444, 1.3483, 2.2766, 3.3307, 2.1367, 0.4487, 4.8708, 1.6514, 1.4341, 6.0081, 1.2447, 2.8818, 4.7444, 1.3483, 3.0814, 2.2747, -1.5878, 2.0681, 1.0413, -2.9849, 2.9911, 0.177, -2.5055, 3.0814, 2.2747, -1.5878, 2.3543, 3.9299, -1.7328, 2.0681, 1.0413, -2.9849, 0.0444, -0.8451, -3.3989, -2.0395, 0.8474, -2.9039, -2.0489, -0.9812, -3.014, 0.0444, -0.8451, -3.3989, 0.0399, 0.8971, -3.3453, -2.0395, 0.8474, -2.9039, -2.2391, -1.0013, 3.2378, 0.0817, 0.7564, 3.232, -0.0319, -0.907, 3.3884, -2.2391, -1.0013, 3.2378, -2.1314, 0.7603, 3.0046, 0.0817, 0.7564, 3.232, 2.5729, -0.0463, 2.323, 2.2766, 3.3307, 2.1367, 2.8449, 1.8063, 1.8788, 2.5729, -0.0463, 2.323, 1.9677, 0.877, 2.8315, 2.2766, 3.3307, 2.1367, 2.8449, 1.8063, 1.8788, 3.0694, 0.3768, 0.2917, 2.6862, -0.2733, 1.344, 2.8449, 1.8063, 1.8788, 3.2927, 2.696, 1.0915, 3.0694, 0.3768, 0.2917, 2.1308, -0.8122, -3.0291, 0.0399, 0.8971, -3.3453, 0.0444, -0.8451, -3.3989, 2.1308, -0.8122, -3.0291, 2.0681, 1.0413, -2.9849, 0.0399, 0.8971, -3.3453, -2.0489, -0.9812, -3.014, -3.1353, -2.4738, -1.533, -2.3373, -3.6333, -2.2624, -2.0489, -0.9812, -3.014, -2.8218, -0.0908, -2.3316, -3.1353, -2.4738, -1.533, -2.9289, -0.1232, 2.5316, -2.3213, -3.5933, 2.2613, -3.048, -2.4163, 1.5053, -2.9289, -0.1232, 2.5316, -2.2391, -1.0013, 3.2378, -2.3213, -3.5933, 2.2613, -0.0319, -0.907, 3.3884, 1.9677, 0.877, 2.8315, 1.8364, -0.871, 2.91, -0.0319, -0.907, 3.3884, 0.0817, 0.7564, 3.232, 1.9677, 0.877, 2.8315, 2.6862, -0.2733, 1.344, 3.0799, -1.877, -0.2485, 2.791, -2.0828, 0.6971, 2.6862, -0.2733, 1.344, 3.0694, 0.3768, 0.2917, 3.0799, -1.877, -0.2485, 0.8528, -5.1659, -1.2387, 1.5835, -3.611, -1.9401, 0.5989, -4.5033, -1.836, 0.8528, -5.1659, -1.2387, 1.6723, -4.1113, -1.5062, 1.5835, -3.611, -1.9401, 0.5989, -4.5033, -1.836, -0.9423, -5.2303, -2.2174, -0.129, -6.0155, -1.6627, 0.5989, -4.5033, -1.836, -0.0313, -3.8492, -2.3572, -0.9423, -5.2303, -2.2174, -1.2211, -6.6432, -1.3733, -2.3373, -3.6333, -2.2624, -2.3738, -5.4707, -1.3892, -1.2211, -6.6432, -1.3733, -0.9423, -5.2303, -2.2174, -2.3373, -3.6333, -2.2624, -2.3738, -5.4707, -1.3892, -2.8602, -5.2902, -0.0034, -1.8677, -6.7222, 0.0053, -2.3738, -5.4707, -1.3892, -3.0733, -4.4498, -0.8737, -2.8602, -5.2902, -0.0034, -1.8677, -6.7222, 0.0053, -3.0246, -4.4027, 0.8468, -2.3434, -5.4566, 1.3758, -1.8677, -6.7222, 0.0053, -2.8602, -5.2902, -0.0034, -3.0246, -4.4027, 0.8468, -2.3434, -5.4566, 1.3758, -0.9484, -5.3598, 2.2535, -1.2352, -6.7568, 1.4079, -2.3434, -5.4566, 1.3758, -2.3213, -3.5933, 2.2613, -0.9484, -5.3598, 2.2535, -0.1504, -6.0468, 1.6347, -0.1302, -3.9225, 2.4564, 0.6052, -4.4095, 1.8566, -0.1504, -6.0468, 1.6347, -0.9484, -5.3598, 2.2535, -0.1302, -3.9225, 2.4564, 0.6052, -4.4095, 1.8566, 1.7532, -3.8773, 1.1862, 0.8249, -4.8431, 1.2373, 0.6052, -4.4095, 1.8566, 1.5121, -3.4321, 1.801, 1.7532, -3.8773, 1.1862, -0.6892, -7.3327, -0.0456, -1.8677, -6.7222, 0.0053, -1.2352, -6.7568, 1.4079) + +[node name="CrystalC" instance=ExtResource("1_1vww1")] +collision_mask = 3 + +[node name="Rock3" parent="." index="0"] +surface_material_override/0 = ExtResource("2_fclne") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." index="1"] +shape = SubResource("ConcavePolygonShape3D_ycsjC") diff --git a/demo/assets/models/LODExample.tscn b/demo/assets/models/LODExample.tscn new file mode 100644 index 0000000..31d95ee --- /dev/null +++ b/demo/assets/models/LODExample.tscn @@ -0,0 +1,56 @@ +[gd_scene load_steps=9 format=3 uid="uid://bn5nf4esciwex"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_788j8"] +albedo_color = Color(1, 0, 0, 1) + +[sub_resource type="SphereMesh" id="SphereMesh_u4ac2"] +material = SubResource("StandardMaterial3D_788j8") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_3i52q"] +albedo_color = Color(1, 0.540167, 0.11, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_xyuxq"] +material = SubResource("StandardMaterial3D_3i52q") +size = Vector3(0.85, 0.85, 0.85) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p0ha4"] +albedo_color = Color(0.48, 1, 0.497333, 1) + +[sub_resource type="PrismMesh" id="PrismMesh_xnm4h"] +material = SubResource("StandardMaterial3D_p0ha4") +size = Vector3(1, 1, 0.855) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_4koei"] +albedo_color = Color(0.45, 0.596667, 1, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_dp7xj"] +material = SubResource("StandardMaterial3D_4koei") +top_radius = 0.0 +bottom_radius = 0.34 +height = 1.54 +radial_segments = 4 + +[node name="TestMultimesh" type="Node3D"] + +[node name="Node3D" type="Node3D" parent="."] + +[node name="MeshInstance3D1" type="MeshInstance3D" parent="Node3D"] +mesh = SubResource("SphereMesh_u4ac2") +skeleton = NodePath("../..") + +[node name="MeshInstance3D2" type="MeshInstance3D" parent="Node3D"] +visible = false +mesh = SubResource("BoxMesh_xyuxq") +skeleton = NodePath("../..") + +[node name="MeshInstance3D3" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.118133, 0) +visible = false +mesh = SubResource("PrismMesh_xnm4h") +skeleton = NodePath("../..") + +[node name="MeshInstance3D4" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.246009, 0) +visible = false +mesh = SubResource("CylinderMesh_dp7xj") +skeleton = NodePath("../..") diff --git a/demo/assets/models/LODExample10.tscn b/demo/assets/models/LODExample10.tscn new file mode 100644 index 0000000..1a6e4c3 --- /dev/null +++ b/demo/assets/models/LODExample10.tscn @@ -0,0 +1,139 @@ +[gd_scene load_steps=21 format=3 uid="uid://dqwgv1ahsvqio"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_788j8"] +albedo_color = Color(1, 0, 0, 1) + +[sub_resource type="SphereMesh" id="SphereMesh_u4ac2"] +material = SubResource("StandardMaterial3D_788j8") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0qa1y"] +albedo_color = Color(1, 0.907, 0.38, 1) + +[sub_resource type="TorusMesh" id="TorusMesh_tjrnq"] +material = SubResource("StandardMaterial3D_0qa1y") +inner_radius = 0.141 +outer_radius = 0.601 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_3i52q"] +albedo_color = Color(1, 0.540167, 0.11, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_xyuxq"] +material = SubResource("StandardMaterial3D_3i52q") +size = Vector3(0.85, 0.85, 0.85) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p0ha4"] +albedo_color = Color(0.48, 1, 0.497333, 1) + +[sub_resource type="PrismMesh" id="PrismMesh_xnm4h"] +material = SubResource("StandardMaterial3D_p0ha4") +size = Vector3(1, 1, 0.855) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_jv6fb"] +albedo_color = Color(0.3384, 0.538933, 0.94, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_i1yhp"] +material = SubResource("StandardMaterial3D_jv6fb") +top_radius = 0.0 +bottom_radius = 0.59 +height = 1.08 +radial_segments = 4 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0qk4s"] +albedo_color = Color(0.62325, 0.495, 0.9, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_bvmel"] +material = SubResource("StandardMaterial3D_0qk4s") +top_radius = 0.765 +bottom_radius = 0.34 +height = 1.54 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_438mn"] +albedo_color = Color(0.933333, 0.2, 1, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_x8oip"] +material = SubResource("StandardMaterial3D_438mn") +top_radius = 0.33 +bottom_radius = 0.34 +height = 1.0 +radial_segments = 7 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_hqr78"] +albedo_color = Color(0.51, 0.456705, 0.3417, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_dp7xj"] +material = SubResource("StandardMaterial3D_hqr78") +top_radius = 0.29 +bottom_radius = 0.59 +height = 0.65 +radial_segments = 4 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_aba40"] +albedo_color = Color(0.1512, 0.36, 0.17208, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_8ctts"] +material = SubResource("StandardMaterial3D_aba40") +top_radius = 0.45 +bottom_radius = 0.495 +height = 1.54 +radial_segments = 4 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_tl8dq"] +albedo_color = Color(0.2279, 0.36888, 0.53, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_w2aj8"] +material = SubResource("StandardMaterial3D_tl8dq") +top_radius = 0.0 +bottom_radius = 0.77 +height = 1.54 +radial_segments = 4 + +[node name="TestMultimesh" type="Node3D"] + +[node name="Node3D" type="Node3D" parent="."] + +[node name="MeshInstance3D0" type="MeshInstance3D" parent="Node3D"] +mesh = SubResource("SphereMesh_u4ac2") +skeleton = NodePath("../..") + +[node name="MeshInstance3D1" type="MeshInstance3D" parent="Node3D"] +mesh = SubResource("TorusMesh_tjrnq") +skeleton = NodePath("../..") + +[node name="MeshInstance3D2" type="MeshInstance3D" parent="Node3D"] +mesh = SubResource("BoxMesh_xyuxq") +skeleton = NodePath("../..") + +[node name="MeshInstance3D3" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.118133, 0) +mesh = SubResource("PrismMesh_xnm4h") +skeleton = NodePath("../..") + +[node name="MeshInstance3D4" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.246009, 0) +mesh = SubResource("CylinderMesh_i1yhp") +skeleton = NodePath("../..") + +[node name="MeshInstance3D5" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.246009, 0) +mesh = SubResource("CylinderMesh_bvmel") +skeleton = NodePath("../..") + +[node name="MeshInstance3D6" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.246009, 0) +mesh = SubResource("CylinderMesh_x8oip") +skeleton = NodePath("../..") + +[node name="MeshInstance3D7" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.246009, 0) +mesh = SubResource("CylinderMesh_dp7xj") +skeleton = NodePath("../..") + +[node name="MeshInstance3D8" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.246009, 0) +mesh = SubResource("CylinderMesh_8ctts") +skeleton = NodePath("../..") + +[node name="MeshInstance3D9" type="MeshInstance3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.246009, 0) +mesh = SubResource("CylinderMesh_w2aj8") +skeleton = NodePath("../..") diff --git a/demo/assets/models/RockA.glb b/demo/assets/models/RockA.glb new file mode 100644 index 0000000..7ee3b6e Binary files /dev/null and b/demo/assets/models/RockA.glb differ diff --git a/demo/assets/models/RockA.glb.import b/demo/assets/models/RockA.glb.import new file mode 100644 index 0000000..b54636b --- /dev/null +++ b/demo/assets/models/RockA.glb.import @@ -0,0 +1,44 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://bxwiqxgwoh630" +path="res://.godot/imported/RockA.glb-2e416adf16cd89c5c5afc8e204027147.scn" + +[deps] + +source_file="res://demo/assets/models/RockA.glb" +dest_files=["res://.godot/imported/RockA.glb-2e416adf16cd89c5c5afc8e204027147.scn"] + +[params] + +nodes/root_type="StaticBody3D" +nodes/root_name="Scene Root" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={ +"materials": { +"@MATERIAL:0": { +"use_external/enabled": true, +"use_external/path": "res://demo/assets/materials/M_rock30.tres" +} +} +} +gltf/naming_version=0 +gltf/embedded_image_handling=1 diff --git a/demo/assets/models/RockA.tscn b/demo/assets/models/RockA.tscn new file mode 100644 index 0000000..0beb068 --- /dev/null +++ b/demo/assets/models/RockA.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=4 format=3 uid="uid://be6nrf0b8j4l0"] + +[ext_resource type="PackedScene" uid="uid://bxwiqxgwoh630" path="res://demo/assets/models/RockA.glb" id="1_nu743"] +[ext_resource type="Material" uid="uid://nbbdrx8vma80" path="res://demo/assets/materials/M_rock23_tp.tres" id="2_pmd5x"] + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_2s34t"] +data = PackedVector3Array(0.8507, -2.8222, -2.0706, 0.5747, -2.1329, -3.01, 0.0002, -3.2065, -2.7359, 2.2873, -1.7649, -0.5811, 2.4378, -0.9615, -0.323, 2.038, -0.9707, -1.2311, -0.6382, -2.68, -2.9376, -1.1067, -1.2731, -2.7048, -1.5545, -2.3633, -2.567, -0.6382, -2.68, -2.9376, -0.2162, -1.825, -3.2439, -1.1067, -1.2731, -2.7048, 0.0002, -3.2065, -2.7359, 0.0411, -3.76, -1.9518, 0.8507, -2.8222, -2.0706, 2.425, -2.0284, 0.49, 2.4024, -1.5988, 1.5279, 2.5851, -1.2056, 0.7305, 0.0831, -2.9699, 1.939, -0.0859, -2.2445, 2.6136, 0.748, -2.001, 2.5127, -2.448, -1.0454, -1.0528, -2.5272, 0.3979, -0.8764, -2.399, -0.7585, 0.2313, -1.5104, 0.6775, -2.512, -1.3227, 1.7291, -2.1514, -2.0387, 1.5996, -2.2267, 0.1427, 2.3057, -2.4478, -0.4979, 2.1368, -2.1727, -0.4143, 1.2902, -3.2951, 0.1351, -3.9012, -0.5924, 0.2299, -3.4688, 0.9248, 0.5827, -3.159, 0.0985, -1.6255, -3.1162, -1.4188, -2.0226, -2.1644, -0.379, -1.2838, -3.0035, 0.2928, -1.1067, -1.2731, -2.7048, -1.5104, 0.6775, -2.512, -1.9542, -0.4605, -2.5215, 0.748, -2.001, 2.5127, 1.4775, -1.3103, 2.8259, 1.9116, -1.7142, 2.341, 1.8789, 1.1592, -0.8303, 1.3001, 2.6786, -0.7585, 0.8831, 2.5385, -1.8483, 0.5951, -0.2972, 3.54, 1.1272, 0.2617, 2.9365, 1.3352, -0.2905, 3.0366, 0.5951, -0.2972, 3.54, 0.7324, 0.4498, 3.1493, 1.1272, 0.2617, 2.9365, -1.3976, 0.6213, 1.8313, -0.8149, 0.6856, 2.232, -1.0617, -0.1771, 2.0331, -0.7449, 2.9351, -0.0395, -0.5981, 2.6867, 0.9116, -1.33, 2.7367, 0.359, 0.9156, 3.0784, 0.1405, 0.1518, 3.0337, 0.6723, 0.0726, 3.4231, -0.5764, 0.7064, 1.456, 2.7883, 1.3708, 1.9744, 2.321, 1.1174, 1.3846, 2.616, 0.7064, 1.456, 2.7883, 0.5198, 2.1281, 2.596, 1.3708, 1.9744, 2.321, -1.6255, -3.1162, -1.4188, -1.2838, -3.0035, 0.2928, -0.6766, -3.9798, -0.6577, 2.4717, 0.9465, 0.6202, 2.4515, -0.0586, -0.1403, 2.6117, 0.0377, 0.454, 2.4515, -0.0586, -0.1403, 2.1036, 1.6103, 0.0759, 1.8789, 1.1592, -0.8303, 2.4515, -0.0586, -0.1403, 2.4717, 0.9465, 0.6202, 2.1036, 1.6103, 0.0759, 1.0451, 2.7721, 1.514, 0.2361, 2.7435, 1.8554, 0.1518, 3.0337, 0.6723, 1.0451, 2.7721, 1.514, 0.1518, 3.0337, 0.6723, 0.9156, 3.0784, 0.1405, 0.1427, 2.3057, -2.4478, -0.1394, 3.1268, -1.5759, -0.4979, 2.1368, -2.1727, 0.1518, 3.0337, 0.6723, 0.2361, 2.7435, 1.8554, -0.5981, 2.6867, 0.9116, 0.1518, 3.0337, 0.6723, -0.5981, 2.6867, 0.9116, -0.7449, 2.9351, -0.0395, -2.4827, 1.6372, -1.6179, -2.4412, 1.9847, -0.6202, -2.5272, 0.3979, -0.8764, -0.7996, 2.0136, 1.7125, -0.1737, 2.1372, 2.2437, -0.5194, 1.6162, 2.2076, -0.7996, 2.0136, 1.7125, -0.5194, 1.6162, 2.2076, -1.313, 1.5855, 1.6731, -1.6866, -0.7727, 1.7598, -1.0617, -0.1771, 2.0331, -1.0177, -1.42, 2.2188, 0.2988, 1.5533, 2.7449, 0.5198, 2.1281, 2.596, 0.7064, 1.456, 2.7883, 0.3266, 0.5073, 3.1476, 0.7324, 0.4498, 3.1493, 0.5951, -0.2972, 3.54, 1.8789, 1.1592, -0.8303, 2.1036, 1.6103, 0.0759, 1.3001, 2.6786, -0.7585, 2.1338, 1.9216, 1.0603, 1.8537, 2.1593, 1.6508, 1.6716, 2.5645, 0.6123, -0.0859, -2.2445, 2.6136, 0.5411, -1.3085, 3.348, 0.748, -2.001, 2.5127, -0.4979, 2.1368, -2.1727, -0.1394, 3.1268, -1.5759, -0.6639, 2.8841, -1.1739, 0.0726, 3.4231, -0.5764, 0.1518, 3.0337, 0.6723, -0.7449, 2.9351, -0.0395, 1.1174, 1.3846, 2.616, 1.9058, 0.4561, 2.6704, 1.3631, 0.7103, 2.7557, 1.1174, 1.3846, 2.616, 1.3708, 1.9744, 2.321, 1.9058, 0.4561, 2.6704, -2.2917, 0.7985, 0.4167, -2.1878, 1.682, 0.5464, -1.9453, 1.0221, 1.1785, -1.533, 2.1485, 1.1174, -0.7996, 2.0136, 1.7125, -1.313, 1.5855, 1.6731, -1.8821, -1.8796, 1.075, -0.8935, -2.6081, 1.7932, -1.2838, -3.0035, 0.2928, -0.3641, -1.322, 2.8122, -0.3719, -0.4418, 2.6845, 0.0592, -0.6578, 3.3401, -0.3719, -0.4418, 2.6845, -0.2183, 0.1183, 2.8781, 0.0592, -0.6578, 3.3401, -2.2917, 0.7985, 0.4167, -1.9453, 1.0221, 1.1785, -2.1903, -0.0178, 1.0505, 1.9116, -1.7142, 2.341, 1.4775, -1.3103, 2.8259, 2.1165, -0.7174, 2.6008, 1.3352, -0.2905, 3.0366, 1.3631, 0.7103, 2.7557, 1.9058, 0.4561, 2.6704, 1.3352, -0.2905, 3.0366, 1.1272, 0.2617, 2.9365, 1.3631, 0.7103, 2.7557, 0.8304, 0.2995, -2.6326, 1.3709, 0.7135, -1.8767, 0.6753, 1.5794, -2.5902, 2.4418, 0.2925, 1.9718, 2.1338, 1.9216, 1.0603, 2.4414, 1.1989, 1.2948, 2.4418, 0.2925, 1.9718, 1.8537, 2.1593, 1.6508, 2.1338, 1.9216, 1.0603, 0.8831, 2.5385, -1.8483, 1.3001, 2.6786, -0.7585, 0.5065, 3.2659, -1.3942, 2.4024, -1.5988, 1.5279, 2.6677, -0.3337, 1.0018, 2.5851, -1.2056, 0.7305, 2.4024, -1.5988, 1.5279, 2.4418, 0.2925, 1.9718, 2.6677, -0.3337, 1.0018, -1.5104, 0.6775, -2.512, -2.0387, 1.5996, -2.2267, -1.9542, -0.4605, -2.5215, -2.0037, 2.5218, -1.5743, -1.3876, 2.8143, -0.9703, -1.9473, 2.7594, -0.6554, 0.8304, 0.2995, -2.6326, 0.6753, 1.5794, -2.5902, 0.0953, 0.6217, -3.4674, -2.0226, -2.1644, -0.379, -1.8821, -1.8796, 1.075, -1.2838, -3.0035, 0.2928, -1.6866, -0.7727, 1.7598, -1.3976, 0.6213, 1.8313, -1.0617, -0.1771, 2.0331, -1.2743, 2.358, -1.6626, -1.3876, 2.8143, -0.9703, -2.0037, 2.5218, -1.5743, 0.2299, -3.4688, 0.9248, 0.6312, -2.7374, 1.3685, 0.5827, -3.159, 0.0985, 0.748, -2.001, 2.5127, 0.5411, -1.3085, 3.348, 1.4775, -1.3103, 2.8259, 1.3964, -0.6655, -2.1748, 0.8304, 0.2995, -2.6326, 0.5493, -0.7511, -3.2244, 1.7659, -2.4495, -1.2002, 1.4806, -1.8538, -1.9812, 0.8507, -2.8222, -2.0706, 2.4418, 0.2925, 1.9718, 2.6117, 0.0377, 0.454, 2.6677, -0.3337, 1.0018, 2.6117, 0.0377, 0.454, 2.4414, 1.1989, 1.2948, 2.4717, 0.9465, 0.6202, 2.6117, 0.0377, 0.454, 2.4418, 0.2925, 1.9718, 2.4414, 1.1989, 1.2948, 0.5493, -0.7511, -3.2244, 0.8304, 0.2995, -2.6326, 0.0953, 0.6217, -3.4674, 2.4515, -0.0586, -0.1403, 2.038, -0.9707, -1.2311, 2.4378, -0.9615, -0.323, 2.4515, -0.0586, -0.1403, 1.8789, 1.1592, -0.8303, 2.038, -0.9707, -1.2311, -0.1975, -0.7247, -3.4884, -0.5122, 0.3139, -3.5925, -0.7053, -0.3406, -3.1144, -1.1067, -1.2731, -2.7048, -1.9542, -0.4605, -2.5215, -1.5545, -2.3633, -2.567, -0.4143, 1.2902, -3.2951, -0.4979, 2.1368, -2.1727, -0.8466, 1.1377, -2.7759, -0.7053, -0.3406, -3.1144, -0.5122, 0.3139, -3.5925, -0.9168, 0.4069, -2.985, -2.4827, 1.6372, -1.6179, -2.5272, 0.3979, -0.8764, -2.4716, -0.4239, -1.8891, -2.4716, -0.4239, -1.8891, -2.5272, 0.3979, -0.8764, -2.448, -1.0454, -1.0528, -2.2072, -1.9264, -1.9655, -2.4716, -0.4239, -1.8891, -2.448, -1.0454, -1.0528, 0.1351, -3.9012, -0.5924, 0.5827, -3.159, 0.0985, 0.6881, -3.2916, -0.9673, -1.2838, -3.0035, 0.2928, -0.8935, -2.6081, 1.7932, -0.3984, -3.542, 1.0253, 1.3964, -0.6655, -2.1748, 1.3709, 0.7135, -1.8767, 0.8304, 0.2995, -2.6326, 1.1446, -2.3077, 1.6179, 1.8479, -2.2708, 1.4206, 1.3113, -2.5503, 0.6426, 1.2555, -2.8919, -0.6692, 1.3113, -2.5503, 0.6426, 1.8655, -2.6668, 0.0778, -0.6766, -3.9798, -0.6577, -1.2838, -3.0035, 0.2928, -0.3984, -3.542, 1.0253, 1.4806, -1.8538, -1.9812, 0.5747, -2.1329, -3.01, 0.8507, -2.8222, -2.0706, 1.3113, -2.5503, 0.6426, 1.8479, -2.2708, 1.4206, 1.8655, -2.6668, 0.0778, -0.6836, -3.6027, -2.5845, 0.0002, -3.2065, -2.7359, -0.6382, -2.68, -2.9376, 1.7659, -2.4495, -1.2002, 2.425, -2.0284, 0.49, 2.2873, -1.7649, -0.5811, 1.7659, -2.4495, -1.2002, 1.8655, -2.6668, 0.0778, 2.425, -2.0284, 0.49, 0.0831, -2.9699, 1.939, 0.2299, -3.4688, 0.9248, -0.3984, -3.542, 1.0253, -0.9168, 0.4069, -2.985, -0.8466, 1.1377, -2.7759, -1.5104, 0.6775, -2.512, -1.9473, 2.7594, -0.6554, -2.1878, 1.682, 0.5464, -2.4412, 1.9847, -0.6202, -2.1878, 1.682, 0.5464, -1.33, 2.7367, 0.359, -1.533, 2.1485, 1.1174, -2.1878, 1.682, 0.5464, -1.9473, 2.7594, -0.6554, -1.33, 2.7367, 0.359, 0.0726, 3.4231, -0.5764, -0.1394, 3.1268, -1.5759, 0.5065, 3.2659, -1.3942, 2.1036, 1.6103, 0.0759, 2.4414, 1.1989, 1.2948, 2.1338, 1.9216, 1.0603, 2.1036, 1.6103, 0.0759, 2.4717, 0.9465, 0.6202, 2.4414, 1.1989, 1.2948, 0.2361, 2.7435, 1.8554, 0.5198, 2.1281, 2.596, -0.1737, 2.1372, 2.2437, 0.0411, -3.76, -1.9518, -0.6766, -3.9798, -0.6577, 0.1351, -3.9012, -0.5924, 0.0411, -3.76, -1.9518, -0.6585, -3.9829, -1.9964, -0.6766, -3.9798, -0.6577, 1.2555, -2.8919, -0.6692, 0.8507, -2.8222, -2.0706, 0.6881, -3.2916, -0.9673, 1.4806, -1.8538, -1.9812, 2.038, -0.9707, -1.2311, 1.3964, -0.6655, -2.1748, -0.2162, -1.825, -3.2439, 0.5493, -0.7511, -3.2244, -0.1975, -0.7247, -3.4884, -0.2162, -1.825, -3.2439, 0.5747, -2.1329, -3.01, 0.5493, -0.7511, -3.2244, -1.1679, -3.5644, -2.3336, -2.2072, -1.9264, -1.9655, -1.6255, -3.1162, -1.4188, -1.1679, -3.5644, -2.3336, -1.5545, -2.3633, -2.567, -2.2072, -1.9264, -1.9655, -0.4143, 1.2902, -3.2951, -0.5122, 0.3139, -3.5925, 0.0953, 0.6217, -3.4674, 2.6677, -0.3337, 1.0018, 2.4378, -0.9615, -0.323, 2.5851, -1.2056, 0.7305, 2.4378, -0.9615, -0.323, 2.6117, 0.0377, 0.454, 2.4515, -0.0586, -0.1403, 2.4378, -0.9615, -0.323, 2.6677, -0.3337, 1.0018, 2.6117, 0.0377, 0.454, 0.6312, -2.7374, 1.3685, 0.748, -2.001, 2.5127, 1.1446, -2.3077, 1.6179, 2.4024, -1.5988, 1.5279, 1.8479, -2.2708, 1.4206, 1.9116, -1.7142, 2.341, -1.8821, -1.8796, 1.075, -2.1903, -0.0178, 1.0505, -1.6866, -0.7727, 1.7598, -1.8821, -1.8796, 1.075, -2.399, -0.7585, 0.2313, -2.1903, -0.0178, 1.0505, -1.0177, -1.42, 2.2188, -0.0859, -2.2445, 2.6136, -0.8935, -2.6081, 1.7932, -1.0177, -1.42, 2.2188, -0.3641, -1.322, 2.8122, -0.0859, -2.2445, 2.6136, -2.0037, 2.5218, -1.5743, -2.4827, 1.6372, -1.6179, -2.0387, 1.5996, -2.2267, 0.8831, 2.5385, -1.8483, 0.1427, 2.3057, -2.4478, 0.6753, 1.5794, -2.5902, -1.3227, 1.7291, -2.1514, -0.4979, 2.1368, -2.1727, -1.2743, 2.358, -1.6626, 2.1165, -0.7174, 2.6008, 1.9058, 0.4561, 2.6704, 2.4418, 0.2925, 1.9718, 0.5951, -0.2972, 3.54, 0.5411, -1.3085, 3.348, 0.0592, -0.6578, 3.3401, -1.9453, 1.0221, 1.1785, -1.313, 1.5855, 1.6731, -1.3976, 0.6213, 1.8313, -0.6639, 2.8841, -1.1739, -0.7449, 2.9351, -0.0395, -1.3876, 2.8143, -0.9703, 1.3001, 2.6786, -0.7585, 1.6716, 2.5645, 0.6123, 0.9156, 3.0784, 0.1405, 1.1174, 1.3846, 2.616, 0.7324, 0.4498, 3.1493, 0.7064, 1.456, 2.7883, 0.7324, 0.4498, 3.1493, 1.3631, 0.7103, 2.7557, 1.1272, 0.2617, 2.9365, 0.7324, 0.4498, 3.1493, 1.1174, 1.3846, 2.616, 1.3631, 0.7103, 2.7557, 1.3708, 1.9744, 2.321, 1.0451, 2.7721, 1.514, 1.8537, 2.1593, 1.6508, -0.8149, 0.6856, 2.232, 0.3266, 0.5073, 3.1476, -0.2183, 0.1183, 2.8781, 0.3266, 0.5073, 3.1476, -0.5194, 1.6162, 2.2076, 0.2988, 1.5533, 2.7449, 0.3266, 0.5073, 3.1476, -0.8149, 0.6856, 2.232, -0.5194, 1.6162, 2.2076, -0.6585, -3.9829, -1.9964, 0.0002, -3.2065, -2.7359, -0.6836, -3.6027, -2.5845, -0.6585, -3.9829, -1.9964, 0.0411, -3.76, -1.9518, 0.0002, -3.2065, -2.7359, 0.8507, -2.8222, -2.0706, 1.8655, -2.6668, 0.0778, 1.7659, -2.4495, -1.2002, 0.8507, -2.8222, -2.0706, 1.2555, -2.8919, -0.6692, 1.8655, -2.6668, 0.0778, 2.038, -0.9707, -1.2311, 1.7659, -2.4495, -1.2002, 2.2873, -1.7649, -0.5811, 2.038, -0.9707, -1.2311, 1.4806, -1.8538, -1.9812, 1.7659, -2.4495, -1.2002, -1.5545, -2.3633, -2.567, -0.6836, -3.6027, -2.5845, -0.6382, -2.68, -2.9376, -1.5545, -2.3633, -2.567, -1.1679, -3.5644, -2.3336, -0.6836, -3.6027, -2.5845, 2.5851, -1.2056, 0.7305, 2.2873, -1.7649, -0.5811, 2.425, -2.0284, 0.49, 2.5851, -1.2056, 0.7305, 2.4378, -0.9615, -0.323, 2.2873, -1.7649, -0.5811, 0.748, -2.001, 2.5127, 0.2299, -3.4688, 0.9248, 0.0831, -2.9699, 1.939, 0.748, -2.001, 2.5127, 0.6312, -2.7374, 1.3685, 0.2299, -3.4688, 0.9248, -2.399, -0.7585, 0.2313, -2.0226, -2.1644, -0.379, -2.448, -1.0454, -1.0528, -2.399, -0.7585, 0.2313, -1.8821, -1.8796, 1.075, -2.0226, -2.1644, -0.379, -0.3641, -1.322, 2.8122, -1.0617, -0.1771, 2.0331, -0.3719, -0.4418, 2.6845, -0.3641, -1.322, 2.8122, -1.0177, -1.42, 2.2188, -1.0617, -0.1771, 2.0331, -2.2917, 0.7985, 0.4167, -2.4412, 1.9847, -0.6202, -2.1878, 1.682, 0.5464, -2.2917, 0.7985, 0.4167, -2.5272, 0.3979, -0.8764, -2.4412, 1.9847, -0.6202, 1.9058, 0.4561, 2.6704, 1.4775, -1.3103, 2.8259, 1.3352, -0.2905, 3.0366, 1.9058, 0.4561, 2.6704, 2.1165, -0.7174, 2.6008, 1.4775, -1.3103, 2.8259, -1.313, 1.5855, 1.6731, -2.1878, 1.682, 0.5464, -1.533, 2.1485, 1.1174, -1.313, 1.5855, 1.6731, -1.9453, 1.0221, 1.1785, -2.1878, 1.682, 0.5464, -0.7449, 2.9351, -0.0395, -0.1394, 3.1268, -1.5759, 0.0726, 3.4231, -0.5764, -0.7449, 2.9351, -0.0395, -0.6639, 2.8841, -1.1739, -0.1394, 3.1268, -1.5759, 1.6716, 2.5645, 0.6123, 2.1036, 1.6103, 0.0759, 2.1338, 1.9216, 1.0603, 1.6716, 2.5645, 0.6123, 1.3001, 2.6786, -0.7585, 2.1036, 1.6103, 0.0759, 1.0451, 2.7721, 1.514, 0.5198, 2.1281, 2.596, 0.2361, 2.7435, 1.8554, 1.0451, 2.7721, 1.514, 1.3708, 1.9744, 2.321, 0.5198, 2.1281, 2.596, -0.8149, 0.6856, 2.232, -0.3719, -0.4418, 2.6845, -1.0617, -0.1771, 2.0331, -0.8149, 0.6856, 2.232, -0.2183, 0.1183, 2.8781, -0.3719, -0.4418, 2.6845, -0.5981, 2.6867, 0.9116, -1.533, 2.1485, 1.1174, -1.33, 2.7367, 0.359, -0.5981, 2.6867, 0.9116, -0.7996, 2.0136, 1.7125, -1.533, 2.1485, 1.1174, -0.3984, -3.542, 1.0253, 0.1351, -3.9012, -0.5924, -0.6766, -3.9798, -0.6577, -0.3984, -3.542, 1.0253, 0.2299, -3.4688, 0.9248, 0.1351, -3.9012, -0.5924, -0.6382, -2.68, -2.9376, 0.5747, -2.1329, -3.01, -0.2162, -1.825, -3.2439, -0.6382, -2.68, -2.9376, 0.0002, -3.2065, -2.7359, 0.5747, -2.1329, -3.01, -2.448, -1.0454, -1.0528, -1.6255, -3.1162, -1.4188, -2.2072, -1.9264, -1.9655, -2.448, -1.0454, -1.0528, -2.0226, -2.1644, -0.379, -1.6255, -3.1162, -1.4188, -0.9168, 0.4069, -2.985, -1.1067, -1.2731, -2.7048, -0.7053, -0.3406, -3.1144, -0.9168, 0.4069, -2.985, -1.5104, 0.6775, -2.512, -1.1067, -1.2731, -2.7048, -0.8466, 1.1377, -2.7759, -0.5122, 0.3139, -3.5925, -0.4143, 1.2902, -3.2951, -0.8466, 1.1377, -2.7759, -0.9168, 0.4069, -2.985, -0.5122, 0.3139, -3.5925, 2.425, -2.0284, 0.49, 1.8479, -2.2708, 1.4206, 2.4024, -1.5988, 1.5279, 2.425, -2.0284, 0.49, 1.8655, -2.6668, 0.0778, 1.8479, -2.2708, 1.4206, 0.0831, -2.9699, 1.939, -0.8935, -2.6081, 1.7932, -0.0859, -2.2445, 2.6136, 0.0831, -2.9699, 1.939, -0.3984, -3.542, 1.0253, -0.8935, -2.6081, 1.7932, -1.9473, 2.7594, -0.6554, -2.4827, 1.6372, -1.6179, -2.0037, 2.5218, -1.5743, -1.9473, 2.7594, -0.6554, -2.4412, 1.9847, -0.6202, -2.4827, 1.6372, -1.6179, 0.5065, 3.2659, -1.3942, 0.1427, 2.3057, -2.4478, 0.8831, 2.5385, -1.8483, 0.5065, 3.2659, -1.3942, -0.1394, 3.1268, -1.5759, 0.1427, 2.3057, -2.4478, -1.5104, 0.6775, -2.512, -0.4979, 2.1368, -2.1727, -1.3227, 1.7291, -2.1514, -1.5104, 0.6775, -2.512, -0.8466, 1.1377, -2.7759, -0.4979, 2.1368, -2.1727, 1.3352, -0.2905, 3.0366, 0.5411, -1.3085, 3.348, 0.5951, -0.2972, 3.54, 1.3352, -0.2905, 3.0366, 1.4775, -1.3103, 2.8259, 0.5411, -1.3085, 3.348, -1.33, 2.7367, 0.359, -1.3876, 2.8143, -0.9703, -0.7449, 2.9351, -0.0395, -1.33, 2.7367, 0.359, -1.9473, 2.7594, -0.6554, -1.3876, 2.8143, -0.9703, 0.0726, 3.4231, -0.5764, 1.3001, 2.6786, -0.7585, 0.9156, 3.0784, 0.1405, 0.0726, 3.4231, -0.5764, 0.5065, 3.2659, -1.3942, 1.3001, 2.6786, -0.7585, -0.1737, 2.1372, 2.2437, 0.2988, 1.5533, 2.7449, -0.5194, 1.6162, 2.2076, -0.1737, 2.1372, 2.2437, 0.5198, 2.1281, 2.596, 0.2988, 1.5533, 2.7449, 0.2361, 2.7435, 1.8554, -0.7996, 2.0136, 1.7125, -0.5981, 2.6867, 0.9116, 0.2361, 2.7435, 1.8554, -0.1737, 2.1372, 2.2437, -0.7996, 2.0136, 1.7125, 1.8537, 2.1593, 1.6508, 0.9156, 3.0784, 0.1405, 1.6716, 2.5645, 0.6123, 1.8537, 2.1593, 1.6508, 1.0451, 2.7721, 1.514, 0.9156, 3.0784, 0.1405, -0.5194, 1.6162, 2.2076, -1.3976, 0.6213, 1.8313, -1.313, 1.5855, 1.6731, -0.5194, 1.6162, 2.2076, -0.8149, 0.6856, 2.232, -1.3976, 0.6213, 1.8313, 0.3266, 0.5073, 3.1476, 0.7064, 1.456, 2.7883, 0.7324, 0.4498, 3.1493, 0.3266, 0.5073, 3.1476, 0.2988, 1.5533, 2.7449, 0.7064, 1.456, 2.7883, -0.2183, 0.1183, 2.8781, 0.5951, -0.2972, 3.54, 0.0592, -0.6578, 3.3401, -0.2183, 0.1183, 2.8781, 0.3266, 0.5073, 3.1476, 0.5951, -0.2972, 3.54, 1.3708, 1.9744, 2.321, 2.4418, 0.2925, 1.9718, 1.9058, 0.4561, 2.6704, 1.3708, 1.9744, 2.321, 1.8537, 2.1593, 1.6508, 2.4418, 0.2925, 1.9718, 1.3709, 0.7135, -1.8767, 0.8831, 2.5385, -1.8483, 0.6753, 1.5794, -2.5902, 1.3709, 0.7135, -1.8767, 1.8789, 1.1592, -0.8303, 0.8831, 2.5385, -1.8483, -1.2743, 2.358, -1.6626, -0.6639, 2.8841, -1.1739, -1.3876, 2.8143, -0.9703, -1.2743, 2.358, -1.6626, -0.4979, 2.1368, -2.1727, -0.6639, 2.8841, -1.1739, -1.3227, 1.7291, -2.1514, -2.0037, 2.5218, -1.5743, -2.0387, 1.5996, -2.2267, -1.3227, 1.7291, -2.1514, -1.2743, 2.358, -1.6626, -2.0037, 2.5218, -1.5743, -2.5272, 0.3979, -0.8764, -2.1903, -0.0178, 1.0505, -2.399, -0.7585, 0.2313, -2.5272, 0.3979, -0.8764, -2.2917, 0.7985, 0.4167, -2.1903, -0.0178, 1.0505, -1.9453, 1.0221, 1.1785, -1.6866, -0.7727, 1.7598, -2.1903, -0.0178, 1.0505, -1.9453, 1.0221, 1.1785, -1.3976, 0.6213, 1.8313, -1.6866, -0.7727, 1.7598, -0.0859, -2.2445, 2.6136, 0.0592, -0.6578, 3.3401, 0.5411, -1.3085, 3.348, -0.0859, -2.2445, 2.6136, -0.3641, -1.322, 2.8122, 0.0592, -0.6578, 3.3401, 2.4024, -1.5988, 1.5279, 2.1165, -0.7174, 2.6008, 2.4418, 0.2925, 1.9718, 2.4024, -1.5988, 1.5279, 1.9116, -1.7142, 2.341, 2.1165, -0.7174, 2.6008, 0.6753, 1.5794, -2.5902, -0.4143, 1.2902, -3.2951, 0.0953, 0.6217, -3.4674, 0.6753, 1.5794, -2.5902, 0.1427, 2.3057, -2.4478, -0.4143, 1.2902, -3.2951, -2.0387, 1.5996, -2.2267, -2.4716, -0.4239, -1.8891, -1.9542, -0.4605, -2.5215, -2.0387, 1.5996, -2.2267, -2.4827, 1.6372, -1.6179, -2.4716, -0.4239, -1.8891, -1.8821, -1.8796, 1.075, -1.0177, -1.42, 2.2188, -0.8935, -2.6081, 1.7932, -1.8821, -1.8796, 1.075, -1.6866, -0.7727, 1.7598, -1.0177, -1.42, 2.2188, 1.1446, -2.3077, 1.6179, 1.9116, -1.7142, 2.341, 1.8479, -2.2708, 1.4206, 1.1446, -2.3077, 1.6179, 0.748, -2.001, 2.5127, 1.9116, -1.7142, 2.341, 0.6312, -2.7374, 1.3685, 1.3113, -2.5503, 0.6426, 0.5827, -3.159, 0.0985, 0.6312, -2.7374, 1.3685, 1.1446, -2.3077, 1.6179, 1.3113, -2.5503, 0.6426, 1.8789, 1.1592, -0.8303, 1.3964, -0.6655, -2.1748, 2.038, -0.9707, -1.2311, 1.8789, 1.1592, -0.8303, 1.3709, 0.7135, -1.8767, 1.3964, -0.6655, -2.1748, -0.1975, -0.7247, -3.4884, 0.0953, 0.6217, -3.4674, -0.5122, 0.3139, -3.5925, -0.1975, -0.7247, -3.4884, 0.5493, -0.7511, -3.2244, 0.0953, 0.6217, -3.4674, -0.2162, -1.825, -3.2439, -0.7053, -0.3406, -3.1144, -1.1067, -1.2731, -2.7048, -0.2162, -1.825, -3.2439, -0.1975, -0.7247, -3.4884, -0.7053, -0.3406, -3.1144, -1.9542, -0.4605, -2.5215, -2.2072, -1.9264, -1.9655, -1.5545, -2.3633, -2.567, -1.9542, -0.4605, -2.5215, -2.4716, -0.4239, -1.8891, -2.2072, -1.9264, -1.9655, -1.1679, -3.5644, -2.3336, -0.6766, -3.9798, -0.6577, -0.6585, -3.9829, -1.9964, -1.1679, -3.5644, -2.3336, -1.6255, -3.1162, -1.4188, -0.6766, -3.9798, -0.6577, 1.4806, -1.8538, -1.9812, 0.5493, -0.7511, -3.2244, 0.5747, -2.1329, -3.01, 1.4806, -1.8538, -1.9812, 1.3964, -0.6655, -2.1748, 0.5493, -0.7511, -3.2244, 0.0411, -3.76, -1.9518, 0.6881, -3.2916, -0.9673, 0.8507, -2.8222, -2.0706, 0.0411, -3.76, -1.9518, 0.1351, -3.9012, -0.5924, 0.6881, -3.2916, -0.9673, 0.5827, -3.159, 0.0985, 1.2555, -2.8919, -0.6692, 0.6881, -3.2916, -0.9673, 0.5827, -3.159, 0.0985, 1.3113, -2.5503, 0.6426, 1.2555, -2.8919, -0.6692, -0.6836, -3.6027, -2.5845, -1.1679, -3.5644, -2.3336, -0.6585, -3.9829, -1.9964) + +[node name="RockA" instance=ExtResource("1_nu743")] +collision_mask = 3 + +[node name="Rock1" parent="." index="0"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) +surface_material_override/0 = ExtResource("2_pmd5x") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." index="1"] +shape = SubResource("ConcavePolygonShape3D_2s34t") diff --git a/demo/assets/models/RockB.glb b/demo/assets/models/RockB.glb new file mode 100644 index 0000000..79c695e Binary files /dev/null and b/demo/assets/models/RockB.glb differ diff --git a/demo/assets/models/RockB.glb.import b/demo/assets/models/RockB.glb.import new file mode 100644 index 0000000..4eba4f1 --- /dev/null +++ b/demo/assets/models/RockB.glb.import @@ -0,0 +1,44 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://nta3sef6c2el" +path="res://.godot/imported/RockB.glb-d0df90244ab14da61106a961f4faa07f.scn" + +[deps] + +source_file="res://demo/assets/models/RockB.glb" +dest_files=["res://.godot/imported/RockB.glb-d0df90244ab14da61106a961f4faa07f.scn"] + +[params] + +nodes/root_type="StaticBody3D" +nodes/root_name="Scene Root" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={ +"materials": { +"@MATERIAL:0": { +"use_external/enabled": true, +"use_external/path": "res://demo/assets/materials/M_rock30.tres" +} +} +} +gltf/naming_version=0 +gltf/embedded_image_handling=1 diff --git a/demo/assets/models/RockB.tscn b/demo/assets/models/RockB.tscn new file mode 100644 index 0000000..97fa9de --- /dev/null +++ b/demo/assets/models/RockB.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=4 format=3 uid="uid://bwvtgwartxt0g"] + +[ext_resource type="PackedScene" uid="uid://nta3sef6c2el" path="res://demo/assets/models/RockB.glb" id="1_2nhli"] +[ext_resource type="Material" uid="uid://nbbdrx8vma80" path="res://demo/assets/materials/M_rock23_tp.tres" id="2_dbm2k"] + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_wfrmp"] +data = PackedVector3Array(0.4584, -3.889, 0.8266, 0.6021, -4.1961, -0.0392, 0.169, -4.9369, 0.2441, 2.1498, -1.9824, 1.4097, 2.1074, -0.9551, 0.9434, 2.3387, -2.1373, 0.6494, -0.4293, -5.0774, 0.0003, -0.5108, -3.8408, -1.1476, -1.1208, -4.5065, 0.1953, 0.0671, -5.0216, -0.4515, 0.4756, -4.5162, -0.6549, 0.1398, -4.5397, -0.9338, 0.169, -4.9369, 0.2441, -0.0922, -4.5871, 1.3087, 0.4584, -3.889, 0.8266, 2.1498, -1.9824, 1.4097, 1.9393, -0.8033, 1.6608, 2.1074, -0.9551, 0.9434, -1.2288, -2.368, 2.4204, -1.4963, -0.9921, 2.5267, -0.7814, -0.8418, 2.7775, -2.6648, -1.8501, 0.307, -2.907, 0.041, -0.3088, -2.5202, -0.0318, 0.8043, -1.0077, -1.3716, -2.1657, -0.7692, -0.6389, -2.6654, -1.6842, -0.4729, -2.3712, 2.1195, -1.771, -1.5705, 2.5987, -0.8743, -1.1872, 1.9584, -0.8816, -2.0923, -0.2829, -3.5923, 2.1108, -0.2939, -2.4569, 2.4482, 0.5442, -2.0915, 2.2664, -1.1208, -4.5065, 0.1953, -2.179, -3.4152, 0.4259, -1.8849, -3.8097, 1.1593, -0.5108, -3.8408, -1.1476, -0.2695, -2.508, -2.0432, -1.1054, -2.8992, -1.0824, 2.1726, -2.8941, -0.5813, 1.87, -2.8735, -1.1419, 1.5863, -3.2514, -0.7541, 0.7315, 0.8274, 2.7196, 1.1136, 1.849, 2.4998, 1.409, 0.9631, 2.386, -0.4271, 2.5556, 2.4897, 0.5261, 4.2194, 1.9538, 0.5038, 3.0339, 2.4087, -1.9764, 3.1849, 0.2685, -1.0116, 3.5059, 0.8103, -1.5979, 2.7577, 1.2075, -0.9393, 2.872, -1.8539, -1.2485, 3.6723, -1.0264, -1.7216, 2.2099, -1.5001, 1.1827, 2.8613, -1.4341, 0.9077, 3.2903, -1.4616, 0.9177, 2.8679, -1.5387, 0.8594, 5.2909, 1.0912, 0.6378, 5.6752, 0.4017, 1.3249, 5.3073, 0.5102, -1.1208, -4.5065, 0.1953, -1.8849, -3.8097, 1.1593, -0.8729, -4.7982, 1.121, 2.4617, 0.7259, 0.0288, 2.5473, 1.387, -0.0726, 2.6196, 0.7185, -0.2944, 0.9445, 5.5277, -0.3666, 0.5746, 5.6649, -0.3989, 0.6884, 5.4332, -0.7011, 1.7744, 4.3299, -0.4393, 1.3226, 4.3217, -0.9655, 2.0312, 2.7158, -1.0135, 0.9877, 0.4313, -2.4389, 0.7444, 0.8429, -2.2856, 0.635, 0.4247, -2.5749, -0.1392, 4.5027, -1.2571, -0.2125, 5.045, -0.6732, -1.2485, 3.6723, -1.0264, -0.1392, 4.5027, -1.2571, -1.2485, 3.6723, -1.0264, -0.9393, 2.872, -1.8539, -1.7965, 0.899, -2.2295, -1.7216, 2.2099, -1.5001, -2.3834, 0.7782, -1.5631, -0.791, 4.3118, -0.0929, -0.2232, 5.1794, 0.1938, -0.5404, 4.4098, 0.4328, -1.3695, 3.5538, -0.0189, -1.0116, 3.5059, 0.8103, -1.9764, 3.1849, 0.2685, -2.5202, -0.0318, 0.8043, -2.1461, 1.5782, 1.2673, -2.0758, -0.0137, 1.8949, -0.5404, 4.4098, 0.4328, -0.2232, 5.1794, 0.1938, -0.0735, 4.938, 0.8308, -1.0116, 3.5059, 0.8103, -0.2982, 4.0929, 1.4648, -0.878, 3.135, 1.7811, 2.6003, 1.0473, -1.0133, 2.4031, 2.6779, -0.4122, 2.0312, 2.7158, -1.0135, 2.4031, 2.6779, -0.4122, 1.7744, 4.3299, -0.4393, 2.0312, 2.7158, -1.0135, -1.0159, 0.9756, 2.6776, -0.4271, 2.5556, 2.4897, -0.2195, 1.1266, 2.8293, -0.0823, 1.3076, -2.4751, 0.0456, 1.662, -2.2329, -0.2095, 1.8203, -2.3278, 0.1709, 2.9305, -1.8154, 0.1823, 3.4347, -1.7089, -0.0988, 3.0024, -1.9036, -2.907, 0.041, -0.3088, -2.575, 1.9843, 0.2578, -2.5202, -0.0318, 0.8043, -2.5502, 1.5321, -0.8246, -1.9974, 2.3952, -0.8364, -2.286, 2.7057, -0.3882, -1.9974, 2.3952, -0.8364, -1.7496, 3.0465, -0.6307, -2.286, 2.7057, -0.3882, 0.8594, 5.2909, 1.0912, 1.3249, 5.3073, 0.5102, 1.6148, 4.6612, 1.1746, -1.6176, 1.4128, 2.2491, -1.7058, 2.0492, 1.8707, -1.3001, 2.2705, 2.1959, -1.5979, 2.7577, 1.2075, -1.0116, 3.5059, 0.8103, -0.878, 3.135, 1.7811, -0.7261, 0.8081, -2.8158, -0.8202, 1.5078, -2.6285, -1.246, 0.719, -2.7492, 1.409, 0.9631, 2.386, 1.1136, 1.849, 2.4998, 1.6219, 2.267, 2.1861, 0.5038, 3.0339, 2.4087, 0.5261, 4.2194, 1.9538, 1.2634, 3.7734, 1.9919, 2.6003, 1.0473, -1.0133, 2.0312, 2.7158, -1.0135, 2.1515, 0.9506, -1.6595, 2.2544, 3.8319, 0.7934, 2.1174, 4.2399, 0.396, 2.3685, 3.5019, 0.414, 1.4453, 1.3219, -1.8647, 1.4442, 1.9, -1.6223, 1.2471, 1.631, -1.7857, 1.9293, 0.908, 1.6849, 2.1901, 2.3652, 1.3543, 2.1038, 1.0245, 0.9114, -1.0077, -1.3716, -2.1657, -1.6842, -0.4729, -2.3712, -1.6361, -1.5711, -1.5378, -1.7965, 0.899, -2.2295, -0.9393, 2.872, -1.8539, -1.7216, 2.2099, -1.5001, 1.1377, -0.8428, -2.7439, 0.7304, -0.9533, -2.8604, 0.9457, -1.6804, -2.7624, -2.6648, -1.8501, 0.307, -2.5202, -0.0318, 0.8043, -2.3406, -2.1709, 1.3672, -2.5202, -0.0318, 0.8043, -2.575, 1.9843, 0.2578, -2.1461, 1.5782, 1.2673, -1.6842, -0.4729, -2.3712, -2.3999, -0.6295, -1.5513, -1.6361, -1.5711, -1.5378, -0.2939, -2.4569, 2.4482, 0.256, -0.9397, 2.7009, 0.5442, -2.0915, 2.2664, -0.2195, 1.1266, 2.8293, -0.4271, 2.5556, 2.4897, 0.5038, 3.0339, 2.4087, 2.4385, -0.7713, 0.0524, 2.634, -0.7691, -0.3318, 2.5652, -1.538, -0.1083, 1.8065, -2.8661, 1.2715, 1.9869, -3.1191, 0.2426, 1.2817, -3.3103, 0.5621, 2.1038, 1.0245, 0.9114, 2.1901, 2.3652, 1.3543, 2.3678, 2.1513, 0.6399, 0.9342, -3.6502, -1.2505, 0.9178, -3.3811, -1.9588, 0.3423, -3.927, -1.4233, 0.9342, -3.6502, -1.2505, 1.4243, -3.0391, -1.5379, 0.9178, -3.3811, -1.9588, 2.1195, -1.771, -1.5705, 1.9584, -0.8816, -2.0923, 1.5426, -2.0265, -2.2438, -0.5108, -3.8408, -1.1476, -1.1054, -2.8992, -1.0824, -1.1208, -4.5065, 0.1953, 0.3194, -2.8417, -2.3407, 0.0974, -1.7758, -2.6186, -0.2695, -2.508, -2.0432, -0.5108, -3.8408, -1.1476, 0.3194, -2.8417, -2.3407, -0.2695, -2.508, -2.0432, -2.5202, -0.0318, 0.8043, -2.0758, -0.0137, 1.8949, -2.3406, -2.1709, 1.3672, -1.9059, -2.3487, -0.7483, -2.5883, -1.4508, -0.7517, -2.3688, -2.5627, -0.2622, -1.809, -3.263, -0.2744, -1.9059, -2.3487, -0.7483, -2.3688, -2.5627, -0.2622, -0.0922, -4.5871, 1.3087, 0.4197, -3.4404, 1.5487, 0.4584, -3.889, 0.8266, -1.7887, -3.0231, 1.9828, -1.4963, -0.9921, 2.5267, -1.2288, -2.368, 2.4204, 2.5358, -1.9021, -0.8254, 2.5987, -0.8743, -1.1872, 2.1195, -1.771, -1.5705, 0.256, -0.9397, 2.7009, 1.2883, -0.8696, 2.2885, 0.5442, -2.0915, 2.2664, 1.2817, -3.3103, 0.5621, 0.9704, -3.0065, 1.4497, 1.8065, -2.8661, 1.2715, -1.1122, -3.8993, 1.9946, -1.7887, -3.0231, 1.9828, -1.2288, -2.368, 2.4204, 1.9869, -3.1191, 0.2426, 1.267, -3.4909, -0.189, 1.2817, -3.3103, 0.5621, 0.5442, -2.0915, 2.2664, 1.2883, -0.8696, 2.2885, 1.6056, -1.9424, 1.9813, -0.4293, -5.0774, 0.0003, 0.169, -4.9369, 0.2441, 0.0671, -5.0216, -0.4515, 2.1498, -1.9824, 1.4097, 1.8065, -2.8661, 1.2715, 1.6056, -1.9424, 1.9813, -2.179, -3.4152, 0.4259, -2.3688, -2.5627, -0.2622, -2.6648, -1.8501, 0.307, 1.87, -2.8735, -1.1419, 2.1195, -1.771, -1.5705, 1.4243, -3.0391, -1.5379, -1.7058, 2.0492, 1.8707, -2.1461, 1.5782, 1.2673, -1.5979, 2.7577, 1.2075, 1.2471, 1.631, -1.7857, 0.0456, 1.662, -2.2329, 0.7444, 0.8429, -2.2856, 0.0456, 1.662, -2.2329, 0.9177, 2.8679, -1.5387, 0.1709, 2.9305, -1.8154, 0.0456, 1.662, -2.2329, 1.2471, 1.631, -1.7857, 0.9177, 2.8679, -1.5387, 2.5473, 1.387, -0.0726, 2.3685, 3.5019, 0.414, 2.4031, 2.6779, -0.4122, 2.5473, 1.387, -0.0726, 2.3678, 2.1513, 0.6399, 2.3685, 3.5019, 0.414, 0.5746, 5.6649, -0.3989, -0.2232, 5.1794, 0.1938, -0.2125, 5.045, -0.6732, 0.5746, 5.6649, -0.3989, 0.6378, 5.6752, 0.4017, -0.2232, 5.1794, 0.1938, -0.0922, -4.5871, 1.3087, -1.1122, -3.8993, 1.9946, -0.2829, -3.5923, 2.1108, -0.0922, -4.5871, 1.3087, -0.8729, -4.7982, 1.121, -1.1122, -3.8993, 1.9946, 0.9704, -3.0065, 1.4497, 0.4197, -3.4404, 1.5487, 0.5442, -2.0915, 2.2664, 2.3387, -2.1373, 0.6494, 2.1726, -2.8941, -0.5813, 1.9869, -3.1191, 0.2426, 2.1726, -2.8941, -0.5813, 2.5652, -1.538, -0.1083, 2.5358, -1.9021, -0.8254, 2.1726, -2.8941, -0.5813, 2.3387, -2.1373, 0.6494, 2.5652, -1.538, -0.1083, 0.9342, -3.6502, -1.2505, 1.267, -3.4909, -0.189, 1.5863, -3.2514, -0.7541, 1.267, -3.4909, -0.189, 0.4756, -4.5162, -0.6549, 0.6021, -4.1961, -0.0392, 1.267, -3.4909, -0.189, 0.9342, -3.6502, -1.2505, 0.4756, -4.5162, -0.6549, -1.8849, -3.8097, 1.1593, -2.3406, -2.1709, 1.3672, -1.7887, -3.0231, 1.9828, -0.5108, -3.8408, -1.1476, 0.1398, -4.5397, -0.9338, 0.3423, -3.927, -1.4233, -1.1054, -2.8992, -1.0824, -1.6361, -1.5711, -1.5378, -1.9059, -2.3487, -0.7483, 0.9178, -3.3811, -1.9588, 0.9457, -1.6804, -2.7624, 0.3194, -2.8417, -2.3407, 0.9178, -3.3811, -1.9588, 1.5426, -2.0265, -2.2438, 0.9457, -1.6804, -2.7624, 2.4617, 0.7259, 0.0288, 2.1074, -0.9551, 0.9434, 2.1038, 1.0245, 0.9114, 2.4617, 0.7259, 0.0288, 2.4385, -0.7713, 0.0524, 2.1074, -0.9551, 0.9434, 2.6196, 0.7185, -0.2944, 2.5987, -0.8743, -1.1872, 2.634, -0.7691, -0.3318, 2.6196, 0.7185, -0.2944, 2.6003, 1.0473, -1.0133, 2.5987, -0.8743, -1.1872, 0.256, -0.9397, 2.7009, -0.2195, 1.1266, 2.8293, 0.7315, 0.8274, 2.7196, 0.256, -0.9397, 2.7009, -0.7814, -0.8418, 2.7775, -0.2195, 1.1266, 2.8293, 1.9393, -0.8033, 1.6608, 1.409, 0.9631, 2.386, 1.9293, 0.908, 1.6849, 1.9393, -0.8033, 1.6608, 1.2883, -0.8696, 2.2885, 1.409, 0.9631, 2.386, -2.0758, -0.0137, 1.8949, -1.0159, 0.9756, 2.6776, -1.4963, -0.9921, 2.5267, -2.0758, -0.0137, 1.8949, -1.6176, 1.4128, 2.2491, -1.0159, 0.9756, 2.6776, -1.246, 0.719, -2.7492, -1.7965, 0.899, -2.2295, -1.6842, -0.4729, -2.3712, -2.5502, 1.5321, -0.8246, -2.3999, -0.6295, -1.5513, -2.3834, 0.7782, -1.5631, -2.3999, -0.6295, -1.5513, -2.907, 0.041, -0.3088, -2.5883, -1.4508, -0.7517, -2.3999, -0.6295, -1.5513, -2.5502, 1.5321, -0.8246, -2.907, 0.041, -0.3088, 1.1377, -0.8428, -2.7439, 1.4453, 1.3219, -1.8647, 0.9877, 0.4313, -2.4389, 1.4453, 1.3219, -1.8647, 1.9584, -0.8816, -2.0923, 2.1515, 0.9506, -1.6595, 1.4453, 1.3219, -1.8647, 1.1377, -0.8428, -2.7439, 1.9584, -0.8816, -2.0923, -0.0823, 1.3076, -2.4751, 0.7304, -0.9533, -2.8604, 0.635, 0.4247, -2.5749, 0.7304, -0.9533, -2.8604, -0.7692, -0.6389, -2.6654, 0.0974, -1.7758, -2.6186, -0.7692, -0.6389, -2.6654, -0.0823, 1.3076, -2.4751, -0.7261, 0.8081, -2.8158, 0.7304, -0.9533, -2.8604, -0.0823, 1.3076, -2.4751, -0.7692, -0.6389, -2.6654, 1.2634, 3.7734, 1.9919, 2.1901, 2.3652, 1.3543, 1.6219, 2.267, 2.1861, 2.1901, 2.3652, 1.3543, 1.6148, 4.6612, 1.1746, 2.2544, 3.8319, 0.7934, 2.1901, 2.3652, 1.3543, 1.2634, 3.7734, 1.9919, 1.6148, 4.6612, 1.1746, -1.3001, 2.2705, 2.1959, -0.878, 3.135, 1.7811, -0.4271, 2.5556, 2.4897, -1.9764, 3.1849, 0.2685, -2.575, 1.9843, 0.2578, -2.286, 2.7057, -0.3882, -0.2095, 1.8203, -2.3278, -0.9393, 2.872, -1.8539, -0.8202, 1.5078, -2.6285, -0.2095, 1.8203, -2.3278, -0.0988, 3.0024, -1.9036, -0.9393, 2.872, -1.8539, 1.4442, 1.9, -1.6223, 2.0312, 2.7158, -1.0135, 1.1827, 2.8613, -1.4341, -0.0735, 4.938, 0.8308, 0.5261, 4.2194, 1.9538, -0.2982, 4.0929, 1.4648, -0.0735, 4.938, 0.8308, 0.8594, 5.2909, 1.0912, 0.5261, 4.2194, 1.9538, 1.3249, 5.3073, 0.5102, 1.7744, 4.3299, -0.4393, 2.1174, 4.2399, 0.396, 1.3249, 5.3073, 0.5102, 0.9445, 5.5277, -0.3666, 1.7744, 4.3299, -0.4393, -1.7496, 3.0465, -0.6307, -0.791, 4.3118, -0.0929, -1.3695, 3.5538, -0.0189, -1.7496, 3.0465, -0.6307, -1.2485, 3.6723, -1.0264, -0.791, 4.3118, -0.0929, 0.9077, 3.2903, -1.4616, -0.1392, 4.5027, -1.2571, 0.1823, 3.4347, -1.7089, -0.1392, 4.5027, -1.2571, 1.3226, 4.3217, -0.9655, 0.6884, 5.4332, -0.7011, -0.1392, 4.5027, -1.2571, 0.9077, 3.2903, -1.4616, 1.3226, 4.3217, -0.9655, -0.8729, -4.7982, 1.121, 0.169, -4.9369, 0.2441, -0.4293, -5.0774, 0.0003, -0.8729, -4.7982, 1.121, -0.0922, -4.5871, 1.3087, 0.169, -4.9369, 0.2441, 2.3387, -2.1373, 0.6494, 1.8065, -2.8661, 1.2715, 2.1498, -1.9824, 1.4097, 2.3387, -2.1373, 0.6494, 1.9869, -3.1191, 0.2426, 1.8065, -2.8661, 1.2715, 0.9342, -3.6502, -1.2505, 1.87, -2.8735, -1.1419, 1.4243, -3.0391, -1.5379, 0.9342, -3.6502, -1.2505, 1.5863, -3.2514, -0.7541, 1.87, -2.8735, -1.1419, -2.3406, -2.1709, 1.3672, -2.179, -3.4152, 0.4259, -2.6648, -1.8501, 0.307, -2.3406, -2.1709, 1.3672, -1.8849, -3.8097, 1.1593, -2.179, -3.4152, 0.4259, 0.1398, -4.5397, -0.9338, -0.4293, -5.0774, 0.0003, 0.0671, -5.0216, -0.4515, 0.1398, -4.5397, -0.9338, -0.5108, -3.8408, -1.1476, -0.4293, -5.0774, 0.0003, -1.6361, -1.5711, -1.5378, -0.2695, -2.508, -2.0432, -1.0077, -1.3716, -2.1657, -1.6361, -1.5711, -1.5378, -1.1054, -2.8992, -1.0824, -0.2695, -2.508, -2.0432, 1.5426, -2.0265, -2.2438, 1.4243, -3.0391, -1.5379, 2.1195, -1.771, -1.5705, 1.5426, -2.0265, -2.2438, 0.9178, -3.3811, -1.9588, 1.4243, -3.0391, -1.5379, 2.6003, 1.0473, -1.0133, 2.5473, 1.387, -0.0726, 2.4031, 2.6779, -0.4122, 2.6003, 1.0473, -1.0133, 2.6196, 0.7185, -0.2944, 2.5473, 1.387, -0.0726, -0.7814, -0.8418, 2.7775, -0.2939, -2.4569, 2.4482, -1.2288, -2.368, 2.4204, -0.7814, -0.8418, 2.7775, 0.256, -0.9397, 2.7009, -0.2939, -2.4569, 2.4482, -1.6176, 1.4128, 2.2491, -2.1461, 1.5782, 1.2673, -1.7058, 2.0492, 1.8707, -1.6176, 1.4128, 2.2491, -2.0758, -0.0137, 1.8949, -2.1461, 1.5782, 1.2673, -2.5502, 1.5321, -0.8246, -1.7216, 2.2099, -1.5001, -1.9974, 2.3952, -0.8364, -2.5502, 1.5321, -0.8246, -2.3834, 0.7782, -1.5631, -1.7216, 2.2099, -1.5001, -0.0823, 1.3076, -2.4751, 0.7444, 0.8429, -2.2856, 0.0456, 1.662, -2.2329, -0.0823, 1.3076, -2.4751, 0.635, 0.4247, -2.5749, 0.7444, 0.8429, -2.2856, 1.2634, 3.7734, 1.9919, 1.1136, 1.849, 2.4998, 0.5038, 3.0339, 2.4087, 1.2634, 3.7734, 1.9919, 1.6219, 2.267, 2.1861, 1.1136, 1.849, 2.4998, -0.878, 3.135, 1.7811, -1.7058, 2.0492, 1.8707, -1.5979, 2.7577, 1.2075, -0.878, 3.135, 1.7811, -1.3001, 2.2705, 2.1959, -1.7058, 2.0492, 1.8707, -0.0988, 3.0024, -1.9036, 0.0456, 1.662, -2.2329, 0.1709, 2.9305, -1.8154, -0.0988, 3.0024, -1.9036, -0.2095, 1.8203, -2.3278, 0.0456, 1.662, -2.2329, 0.9445, 5.5277, -0.3666, 0.6378, 5.6752, 0.4017, 0.5746, 5.6649, -0.3989, 0.9445, 5.5277, -0.3666, 1.3249, 5.3073, 0.5102, 0.6378, 5.6752, 0.4017, -1.2485, 3.6723, -1.0264, -1.9974, 2.3952, -0.8364, -1.7216, 2.2099, -1.5001, -1.2485, 3.6723, -1.0264, -1.7496, 3.0465, -0.6307, -1.9974, 2.3952, -0.8364, 0.9077, 3.2903, -1.4616, 0.1709, 2.9305, -1.8154, 0.9177, 2.8679, -1.5387, 0.9077, 3.2903, -1.4616, 0.1823, 3.4347, -1.7089, 0.1709, 2.9305, -1.8154, -1.2288, -2.368, 2.4204, -0.2829, -3.5923, 2.1108, -1.1122, -3.8993, 1.9946, -1.2288, -2.368, 2.4204, -0.2939, -2.4569, 2.4482, -0.2829, -3.5923, 2.1108, 1.6056, -1.9424, 1.9813, 0.9704, -3.0065, 1.4497, 0.5442, -2.0915, 2.2664, 1.6056, -1.9424, 1.9813, 1.8065, -2.8661, 1.2715, 0.9704, -3.0065, 1.4497, 2.1195, -1.771, -1.5705, 2.1726, -2.8941, -0.5813, 2.5358, -1.9021, -0.8254, 2.1195, -1.771, -1.5705, 1.87, -2.8735, -1.1419, 2.1726, -2.8941, -0.5813, 0.0671, -5.0216, -0.4515, 0.6021, -4.1961, -0.0392, 0.4756, -4.5162, -0.6549, 0.0671, -5.0216, -0.4515, 0.169, -4.9369, 0.2441, 0.6021, -4.1961, -0.0392, -2.3688, -2.5627, -0.2622, -1.1208, -4.5065, 0.1953, -1.809, -3.263, -0.2744, -2.3688, -2.5627, -0.2622, -2.179, -3.4152, 0.4259, -1.1208, -4.5065, 0.1953, 2.3678, 2.1513, 0.6399, 2.4617, 0.7259, 0.0288, 2.1038, 1.0245, 0.9114, 2.3678, 2.1513, 0.6399, 2.5473, 1.387, -0.0726, 2.4617, 0.7259, 0.0288, 0.5038, 3.0339, 2.4087, 0.7315, 0.8274, 2.7196, -0.2195, 1.1266, 2.8293, 0.5038, 3.0339, 2.4087, 1.1136, 1.849, 2.4998, 0.7315, 0.8274, 2.7196, 2.1498, -1.9824, 1.4097, 1.2883, -0.8696, 2.2885, 1.9393, -0.8033, 1.6608, 2.1498, -1.9824, 1.4097, 1.6056, -1.9424, 1.9813, 1.2883, -0.8696, 2.2885, -2.6648, -1.8501, 0.307, -2.5883, -1.4508, -0.7517, -2.907, 0.041, -0.3088, -2.6648, -1.8501, 0.307, -2.3688, -2.5627, -0.2622, -2.5883, -1.4508, -0.7517, 1.2471, 1.631, -1.7857, 0.9877, 0.4313, -2.4389, 1.4453, 1.3219, -1.8647, 1.2471, 1.631, -1.7857, 0.7444, 0.8429, -2.2856, 0.9877, 0.4313, -2.4389, -1.0077, -1.3716, -2.1657, 0.0974, -1.7758, -2.6186, -0.7692, -0.6389, -2.6654, -1.0077, -1.3716, -2.1657, -0.2695, -2.508, -2.0432, 0.0974, -1.7758, -2.6186, 2.3685, 3.5019, 0.414, 2.1901, 2.3652, 1.3543, 2.2544, 3.8319, 0.7934, 2.3685, 3.5019, 0.414, 2.3678, 2.1513, 0.6399, 2.1901, 2.3652, 1.3543, -1.5979, 2.7577, 1.2075, -2.575, 1.9843, 0.2578, -1.9764, 3.1849, 0.2685, -1.5979, 2.7577, 1.2075, -2.1461, 1.5782, 1.2673, -2.575, 1.9843, 0.2578, 0.9177, 2.8679, -1.5387, 1.4442, 1.9, -1.6223, 1.1827, 2.8613, -1.4341, 0.9177, 2.8679, -1.5387, 1.2471, 1.631, -1.7857, 1.4442, 1.9, -1.6223, -0.2232, 5.1794, 0.1938, 0.8594, 5.2909, 1.0912, -0.0735, 4.938, 0.8308, -0.2232, 5.1794, 0.1938, 0.6378, 5.6752, 0.4017, 0.8594, 5.2909, 1.0912, 2.4031, 2.6779, -0.4122, 2.1174, 4.2399, 0.396, 1.7744, 4.3299, -0.4393, 2.4031, 2.6779, -0.4122, 2.3685, 3.5019, 0.414, 2.1174, 4.2399, 0.396, -0.2125, 5.045, -0.6732, -0.791, 4.3118, -0.0929, -1.2485, 3.6723, -1.0264, -0.2125, 5.045, -0.6732, -0.2232, 5.1794, 0.1938, -0.791, 4.3118, -0.0929, 0.5746, 5.6649, -0.3989, -0.1392, 4.5027, -1.2571, 0.6884, 5.4332, -0.7011, 0.5746, 5.6649, -0.3989, -0.2125, 5.045, -0.6732, -0.1392, 4.5027, -1.2571, 1.7744, 4.3299, -0.4393, 0.6884, 5.4332, -0.7011, 1.3226, 4.3217, -0.9655, 1.7744, 4.3299, -0.4393, 0.9445, 5.5277, -0.3666, 0.6884, 5.4332, -0.7011, 1.3226, 4.3217, -0.9655, 1.1827, 2.8613, -1.4341, 2.0312, 2.7158, -1.0135, 1.3226, 4.3217, -0.9655, 0.9077, 3.2903, -1.4616, 1.1827, 2.8613, -1.4341, 0.1823, 3.4347, -1.7089, -0.9393, 2.872, -1.8539, -0.0988, 3.0024, -1.9036, 0.1823, 3.4347, -1.7089, -0.1392, 4.5027, -1.2571, -0.9393, 2.872, -1.8539, -1.3695, 3.5538, -0.0189, -0.5404, 4.4098, 0.4328, -1.0116, 3.5059, 0.8103, -1.3695, 3.5538, -0.0189, -0.791, 4.3118, -0.0929, -0.5404, 4.4098, 0.4328, -1.7496, 3.0465, -0.6307, -1.9764, 3.1849, 0.2685, -2.286, 2.7057, -0.3882, -1.7496, 3.0465, -0.6307, -1.3695, 3.5538, -0.0189, -1.9764, 3.1849, 0.2685, -1.0116, 3.5059, 0.8103, -0.0735, 4.938, 0.8308, -0.2982, 4.0929, 1.4648, -1.0116, 3.5059, 0.8103, -0.5404, 4.4098, 0.4328, -0.0735, 4.938, 0.8308, -0.2982, 4.0929, 1.4648, -0.4271, 2.5556, 2.4897, -0.878, 3.135, 1.7811, -0.2982, 4.0929, 1.4648, 0.5261, 4.2194, 1.9538, -0.4271, 2.5556, 2.4897, 0.5261, 4.2194, 1.9538, 1.6148, 4.6612, 1.1746, 1.2634, 3.7734, 1.9919, 0.5261, 4.2194, 1.9538, 0.8594, 5.2909, 1.0912, 1.6148, 4.6612, 1.1746, 1.3249, 5.3073, 0.5102, 2.2544, 3.8319, 0.7934, 1.6148, 4.6612, 1.1746, 1.3249, 5.3073, 0.5102, 2.1174, 4.2399, 0.396, 2.2544, 3.8319, 0.7934, 2.5987, -0.8743, -1.1872, 2.1515, 0.9506, -1.6595, 1.9584, -0.8816, -2.0923, 2.5987, -0.8743, -1.1872, 2.6003, 1.0473, -1.0133, 2.1515, 0.9506, -1.6595, 2.0312, 2.7158, -1.0135, 1.4453, 1.3219, -1.8647, 2.1515, 0.9506, -1.6595, 2.0312, 2.7158, -1.0135, 1.4442, 1.9, -1.6223, 1.4453, 1.3219, -1.8647, -0.7261, 0.8081, -2.8158, -0.2095, 1.8203, -2.3278, -0.8202, 1.5078, -2.6285, -0.7261, 0.8081, -2.8158, -0.0823, 1.3076, -2.4751, -0.2095, 1.8203, -2.3278, -0.7692, -0.6389, -2.6654, -1.246, 0.719, -2.7492, -1.6842, -0.4729, -2.3712, -0.7692, -0.6389, -2.6654, -0.7261, 0.8081, -2.8158, -1.246, 0.719, -2.7492, -0.8202, 1.5078, -2.6285, -1.7965, 0.899, -2.2295, -1.246, 0.719, -2.7492, -0.8202, 1.5078, -2.6285, -0.9393, 2.872, -1.8539, -1.7965, 0.899, -2.2295, -2.907, 0.041, -0.3088, -2.286, 2.7057, -0.3882, -2.575, 1.9843, 0.2578, -2.907, 0.041, -0.3088, -2.5502, 1.5321, -0.8246, -2.286, 2.7057, -0.3882, -1.0159, 0.9756, 2.6776, -1.3001, 2.2705, 2.1959, -0.4271, 2.5556, 2.4897, -1.0159, 0.9756, 2.6776, -1.6176, 1.4128, 2.2491, -1.3001, 2.2705, 2.1959, -1.4963, -0.9921, 2.5267, -0.2195, 1.1266, 2.8293, -0.7814, -0.8418, 2.7775, -1.4963, -0.9921, 2.5267, -1.0159, 0.9756, 2.6776, -0.2195, 1.1266, 2.8293, 1.9293, 0.908, 1.6849, 1.6219, 2.267, 2.1861, 2.1901, 2.3652, 1.3543, 1.9293, 0.908, 1.6849, 1.409, 0.9631, 2.386, 1.6219, 2.267, 2.1861, 1.9393, -0.8033, 1.6608, 2.1038, 1.0245, 0.9114, 2.1074, -0.9551, 0.9434, 1.9393, -0.8033, 1.6608, 1.9293, 0.908, 1.6849, 2.1038, 1.0245, 0.9114, 1.1377, -0.8428, -2.7439, 0.635, 0.4247, -2.5749, 0.7304, -0.9533, -2.8604, 1.1377, -0.8428, -2.7439, 0.9877, 0.4313, -2.4389, 0.635, 0.4247, -2.5749, 1.9584, -0.8816, -2.0923, 0.9457, -1.6804, -2.7624, 1.5426, -2.0265, -2.2438, 1.9584, -0.8816, -2.0923, 1.1377, -0.8428, -2.7439, 0.9457, -1.6804, -2.7624, 0.7304, -0.9533, -2.8604, 0.3194, -2.8417, -2.3407, 0.9457, -1.6804, -2.7624, 0.7304, -0.9533, -2.8604, 0.0974, -1.7758, -2.6186, 0.3194, -2.8417, -2.3407, -1.6842, -0.4729, -2.3712, -2.3834, 0.7782, -1.5631, -2.3999, -0.6295, -1.5513, -1.6842, -0.4729, -2.3712, -1.7965, 0.899, -2.2295, -2.3834, 0.7782, -1.5631, -2.3999, -0.6295, -1.5513, -1.9059, -2.3487, -0.7483, -1.6361, -1.5711, -1.5378, -2.3999, -0.6295, -1.5513, -2.5883, -1.4508, -0.7517, -1.9059, -2.3487, -0.7483, -2.0758, -0.0137, 1.8949, -1.7887, -3.0231, 1.9828, -2.3406, -2.1709, 1.3672, -2.0758, -0.0137, 1.8949, -1.4963, -0.9921, 2.5267, -1.7887, -3.0231, 1.9828, 0.256, -0.9397, 2.7009, 1.409, 0.9631, 2.386, 1.2883, -0.8696, 2.2885, 0.256, -0.9397, 2.7009, 0.7315, 0.8274, 2.7196, 1.409, 0.9631, 2.386, 2.4385, -0.7713, 0.0524, 2.6196, 0.7185, -0.2944, 2.634, -0.7691, -0.3318, 2.4385, -0.7713, 0.0524, 2.4617, 0.7259, 0.0288, 2.6196, 0.7185, -0.2944, 2.1074, -0.9551, 0.9434, 2.5652, -1.538, -0.1083, 2.3387, -2.1373, 0.6494, 2.1074, -0.9551, 0.9434, 2.4385, -0.7713, 0.0524, 2.5652, -1.538, -0.1083, 2.634, -0.7691, -0.3318, 2.5358, -1.9021, -0.8254, 2.5652, -1.538, -0.1083, 2.634, -0.7691, -0.3318, 2.5987, -0.8743, -1.1872, 2.5358, -1.9021, -0.8254, 0.4756, -4.5162, -0.6549, 0.3423, -3.927, -1.4233, 0.1398, -4.5397, -0.9338, 0.4756, -4.5162, -0.6549, 0.9342, -3.6502, -1.2505, 0.3423, -3.927, -1.4233, 0.9178, -3.3811, -1.9588, -0.5108, -3.8408, -1.1476, 0.3423, -3.927, -1.4233, 0.9178, -3.3811, -1.9588, 0.3194, -2.8417, -2.3407, -0.5108, -3.8408, -1.1476, -1.1054, -2.8992, -1.0824, -1.809, -3.263, -0.2744, -1.1208, -4.5065, 0.1953, -1.1054, -2.8992, -1.0824, -1.9059, -2.3487, -0.7483, -1.809, -3.263, -0.2744, -1.8849, -3.8097, 1.1593, -1.1122, -3.8993, 1.9946, -0.8729, -4.7982, 1.121, -1.8849, -3.8097, 1.1593, -1.7887, -3.0231, 1.9828, -1.1122, -3.8993, 1.9946, 1.9869, -3.1191, 0.2426, 1.5863, -3.2514, -0.7541, 1.267, -3.4909, -0.189, 1.9869, -3.1191, 0.2426, 2.1726, -2.8941, -0.5813, 1.5863, -3.2514, -0.7541, 1.267, -3.4909, -0.189, 0.4584, -3.889, 0.8266, 1.2817, -3.3103, 0.5621, 1.267, -3.4909, -0.189, 0.6021, -4.1961, -0.0392, 0.4584, -3.889, 0.8266, -0.0922, -4.5871, 1.3087, 0.5442, -2.0915, 2.2664, 0.4197, -3.4404, 1.5487, -0.0922, -4.5871, 1.3087, -0.2829, -3.5923, 2.1108, 0.5442, -2.0915, 2.2664, 0.4197, -3.4404, 1.5487, 1.2817, -3.3103, 0.5621, 0.4584, -3.889, 0.8266, 0.4197, -3.4404, 1.5487, 0.9704, -3.0065, 1.4497, 1.2817, -3.3103, 0.5621, -0.4293, -5.0774, 0.0003, -1.1208, -4.5065, 0.1953, -0.8729, -4.7982, 1.121) + +[node name="RockB" instance=ExtResource("1_2nhli")] +collision_mask = 3 + +[node name="Rock2" parent="." index="0"] +surface_material_override/0 = ExtResource("2_dbm2k") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." index="1"] +shape = SubResource("ConcavePolygonShape3D_wfrmp") diff --git a/demo/assets/models/RockC.glb b/demo/assets/models/RockC.glb new file mode 100644 index 0000000..8d87cfd Binary files /dev/null and b/demo/assets/models/RockC.glb differ diff --git a/demo/assets/models/RockC.glb.import b/demo/assets/models/RockC.glb.import new file mode 100644 index 0000000..1ca0672 --- /dev/null +++ b/demo/assets/models/RockC.glb.import @@ -0,0 +1,44 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://c8cx4xjwluvxw" +path="res://.godot/imported/RockC.glb-5881ee1ff2072066a3de122ce4239bee.scn" + +[deps] + +source_file="res://demo/assets/models/RockC.glb" +dest_files=["res://.godot/imported/RockC.glb-5881ee1ff2072066a3de122ce4239bee.scn"] + +[params] + +nodes/root_type="StaticBody3D" +nodes/root_name="Scene Root" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={ +"materials": { +"@MATERIAL:0": { +"use_external/enabled": true, +"use_external/path": "res://demo/assets/materials/M_rock30.tres" +} +} +} +gltf/naming_version=0 +gltf/embedded_image_handling=1 diff --git a/demo/assets/models/RockC.tscn b/demo/assets/models/RockC.tscn new file mode 100644 index 0000000..e8588e2 --- /dev/null +++ b/demo/assets/models/RockC.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=4 format=3 uid="uid://lsvs8a7urkca"] + +[ext_resource type="PackedScene" uid="uid://c8cx4xjwluvxw" path="res://demo/assets/models/RockC.glb" id="1_pb27A"] +[ext_resource type="Material" uid="uid://nbbdrx8vma80" path="res://demo/assets/materials/M_rock23_tp.tres" id="2_pcex8"] + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_ycsjC"] +data = PackedVector3Array(1.3907, -4.3898, 0.264, 0.3707, -6.5026, 0.2358, 0.9197, -5.2139, 0.5803, 1.3907, -4.3898, 0.264, 1.5973, -4.4989, -0.523, 0.3707, -6.5026, 0.2358, 2.7182, -1.9153, 1.6333, 2.6862, -0.2733, 1.344, 2.791, -2.0828, 0.6971, -0.6892, -7.3327, -0.0456, -1.2211, -6.6432, -1.3733, -1.8677, -6.7222, 0.0053, 0.1584, -6.6788, -0.712, 0.8528, -5.1659, -1.2387, -0.129, -6.0155, -1.6627, 0.3707, -6.5026, 0.2358, 0.8249, -4.8431, 1.2373, 0.9197, -5.2139, 0.5803, 0.3707, -6.5026, 0.2358, -0.1504, -6.0468, 1.6347, 0.8249, -4.8431, 1.2373, 2.7182, -1.9153, 1.6333, 2.5729, -0.0463, 2.323, 2.6862, -0.2733, 1.344, -1.5434, -2.0626, 2.9798, -0.0319, -0.907, 3.3884, -0.6296, -2.1168, 3.0274, -1.5434, -2.0626, 2.9798, -2.2391, -1.0013, 3.2378, -0.0319, -0.907, 3.3884, -3.2503, -1.9438, -0.0444, -3.1045, -0.0443, -0.8667, -2.9895, -0.0523, 0.8233, -0.5191, -2.1018, -2.9939, -2.0489, -0.9812, -3.014, -1.4897, -2.0239, -2.8933, -0.5191, -2.1018, -2.9939, 0.0444, -0.8451, -3.3989, -2.0489, -0.9812, -3.014, 3.4189, -1.5098, -2.1519, 3.3947, 0.8197, -1.419, 2.9911, 0.177, -2.5055, -0.9484, -5.3598, 2.2535, -0.8975, -3.7031, 2.6018, -0.1302, -3.9225, 2.4564, -2.8602, -5.2902, -0.0034, -3.2063, -3.9919, -0.0118, -3.0246, -4.4027, 0.8468, -0.9423, -5.2303, -2.2174, -1.6189, -3.1121, -2.5666, -2.3373, -3.6333, -2.2624, -0.9423, -5.2303, -2.2174, -0.9004, -3.6647, -2.5803, -1.6189, -3.1121, -2.5666, 2.4159, -3.3908, 0.0683, 2.6374, -3.7219, -1.0723, 1.5973, -4.4989, -0.523, 0.0817, 0.7564, 3.232, 1.3747, 1.7762, 2.618, 1.9677, 0.877, 2.8315, 0.0817, 0.7564, 3.232, 0.5064, 1.8556, 2.7003, 1.3747, 1.7762, 2.618, -0.2637, 3.5029, 1.8153, 0.4487, 4.8708, 1.6514, 0.6919, 3.2703, 2.2188, -2.3926, 3.3478, 0.3255, -1.6818, 3.3981, 1.0198, -2.0691, 2.5964, 1.5185, -1.2285, 2.4662, -2.4325, -1.544, 3.8438, -1.471, -2.3777, 2.1645, -2.0413, 2.3543, 3.9299, -1.7328, 1.4379, 5.2295, -1.8152, 1.1494, 2.3687, -2.734, 1.4341, 6.0081, 1.2447, 0.9325, 6.924, 0.4365, 2.3528, 6.0999, 0.4838, -1.8677, -6.7222, 0.0053, -2.3434, -5.4566, 1.3758, -1.2352, -6.7568, 1.4079, 3.0694, 0.3768, 0.2917, 3.6836, 2.3906, 0.1427, 3.39, -0.1345, -0.5433, 1.5686, 6.857, -0.4389, 0.7824, 7.1818, -0.4789, 0.9515, 6.8097, -1.0683, 2.4165, 5.7335, -0.6508, 1.4379, 5.2295, -1.8152, 2.3543, 3.9299, -1.7328, 2.0681, 1.0413, -2.9849, 1.1494, 2.3687, -2.734, 0.0399, 0.8971, -3.3453, -0.1803, 5.4522, -1.6664, -0.2609, 6.3493, -0.8464, -1.544, 3.8438, -1.471, -3.1045, -0.0443, -0.8667, -2.9635, 2.0631, -0.0469, -2.9895, -0.0523, 0.8233, -2.8218, -0.0908, -2.3316, -2.8949, 1.7465, -1.4628, -3.1045, -0.0443, -0.8667, -1.137, 5.0901, -0.2048, -0.2548, 6.3653, 0.3115, -0.7059, 4.7856, 0.8682, -1.8973, 4.0438, -0.0231, -1.6818, 3.3981, 1.0198, -2.3926, 3.3478, 0.3255, -2.9895, -0.0523, 0.8233, -2.7222, 1.5834, 1.3251, -2.9289, -0.1232, 2.5316, -0.7059, 4.7856, 0.8682, -0.2548, 6.3653, 0.3115, 0.4487, 4.8708, 1.6514, -0.7059, 4.7856, 0.8682, 0.4487, 4.8708, 1.6514, -0.2637, 3.5029, 1.8153, 3.3947, 0.8197, -1.419, 3.6143, 2.6541, -0.7787, 3.0814, 2.2747, -1.5878, 3.3017, 4.3689, -0.5397, 2.4165, 5.7335, -0.6508, 2.3543, 3.9299, -1.7328, -2.1314, 0.7603, 3.0046, -1.0522, 1.986, 2.2721, 0.0817, 0.7564, 3.232, 0.0399, 0.8971, -3.3453, 1.1494, 2.3687, -2.734, -1.2285, 2.4662, -2.4325, 0.549, 3.3793, -2.5003, 0.4374, 4.5707, -2.224, -0.1459, 3.4745, -2.3857, 1.4341, 6.0081, 1.2447, 2.3528, 6.0999, 0.4838, 2.8818, 4.7444, 1.3483, -3.1045, -0.0443, -0.8667, -2.8949, 1.7465, -1.4628, -2.9635, 2.0631, -0.0469, -2.7186, 2.9035, -1.3821, -2.3162, 3.6228, -0.9721, -2.7435, 3.293, -0.5137, -0.1803, 5.4522, -1.6664, -1.544, 3.8438, -1.471, -1.2285, 2.4662, -2.4325, -2.1314, 0.7603, 3.0046, -2.0691, 2.5964, 1.5185, -1.0522, 1.986, 2.2721, -2.0691, 2.5964, 1.5185, -1.6818, 3.3981, 1.0198, -1.0522, 1.986, 2.2721, 0.0399, 0.8971, -3.3453, -1.2285, 2.4662, -2.4325, -2.0395, 0.8474, -2.9039, 1.9677, 0.877, 2.8315, 1.5121, 2.8416, 2.3106, 2.2766, 3.3307, 2.1367, 1.9677, 0.877, 2.8315, 1.3747, 1.7762, 2.618, 1.5121, 2.8416, 2.3106, 0.6919, 3.2703, 2.2188, 2.2766, 3.3307, 2.1367, 1.5121, 2.8416, 2.3106, 0.6919, 3.2703, 2.2188, 0.4487, 4.8708, 1.6514, 2.2766, 3.3307, 2.1367, 3.3947, 0.8197, -1.419, 3.0814, 2.2747, -1.5878, 2.9911, 0.177, -2.5055, 2.8818, 4.7444, 1.3483, 2.3528, 6.0999, 0.4838, 3.481, 4.5391, 0.4718, 2.0681, 1.0413, -2.9849, 2.3543, 3.9299, -1.7328, 1.1494, 2.3687, -2.734, 2.5729, -0.0463, 2.323, 2.8449, 1.8063, 1.8788, 2.6862, -0.2733, 1.344, -1.4897, -2.0239, -2.8933, -2.3373, -3.6333, -2.2624, -1.6189, -3.1121, -2.5666, -1.4897, -2.0239, -2.8933, -2.0489, -0.9812, -3.014, -2.3373, -3.6333, -2.2624, -2.0395, 0.8474, -2.9039, -1.2285, 2.4662, -2.4325, -2.3777, 2.1645, -2.0413, 2.1308, -0.8122, -3.0291, 0.0444, -0.8451, -3.3989, 1.2123, -2.2074, -2.6786, -3.2503, -1.9438, -0.0444, -2.9895, -0.0523, 0.8233, -3.048, -2.4163, 1.5053, -2.9895, -0.0523, 0.8233, -2.9635, 2.0631, -0.0469, -2.7222, 1.5834, 1.3251, -2.8218, -0.0908, -2.3316, -3.1045, -0.0443, -0.8667, -3.1353, -2.4738, -1.533, -0.6296, -2.1168, 3.0274, -0.0319, -0.907, 3.3884, 0.6607, -2.1929, 2.7904, 0.0817, 0.7564, 3.232, -1.0522, 1.986, 2.2721, 0.5064, 1.8556, 2.7003, 3.0694, 0.3768, 0.2917, 3.39, -0.1345, -0.5433, 3.0799, -1.877, -0.2485, 2.332, -3.2513, 1.4491, 1.8096, -3.8731, 0.517, 1.7532, -3.8773, 1.1862, 2.332, -3.2513, 1.4491, 2.4159, -3.3908, 0.0683, 1.8096, -3.8731, 0.517, 3.0694, 0.3768, 0.2917, 3.2927, 2.696, 1.0915, 3.6836, 2.3906, 0.1427, 0.8528, -5.1659, -1.2387, 0.5989, -4.5033, -1.836, -0.129, -6.0155, -1.6627, 1.6723, -4.1113, -1.5062, 2.2303, -3.7001, -1.8804, 1.5835, -3.611, -1.9401, 2.6485, -2.4319, -2.56, 2.1308, -0.8122, -3.0291, 1.2123, -2.2074, -2.6786, -1.2211, -6.6432, -1.3733, -2.3738, -5.4707, -1.3892, -1.8677, -6.7222, 0.0053, 1.2123, -2.2074, -2.6786, 0.0444, -0.8451, -3.3989, -0.5191, -2.1018, -2.9939, -0.9423, -5.2303, -2.2174, -0.0313, -3.8492, -2.3572, -0.9004, -3.6647, -2.5803, -2.9895, -0.0523, 0.8233, -2.9289, -0.1232, 2.5316, -3.048, -2.4163, 1.5053, -3.1353, -2.4738, -1.533, -3.1045, -0.0443, -0.8667, -3.2503, -1.9438, -0.0444, -2.8602, -5.2902, -0.0034, -3.0733, -4.4498, -0.8737, -3.2063, -3.9919, -0.0118, -0.1504, -6.0468, 1.6347, 0.6052, -4.4095, 1.8566, 0.8249, -4.8431, 1.2373, -2.3213, -3.5933, 2.2613, -1.5434, -2.0626, 2.9798, -1.6095, -3.1051, 2.5592, -2.3213, -3.5933, 2.2613, -2.2391, -1.0013, 3.2378, -1.5434, -2.0626, 2.9798, 3.0799, -1.877, -0.2485, 3.39, -0.1345, -0.5433, 3.4106, -2.2767, -1.2285, -0.0319, -0.907, 3.3884, 1.8364, -0.871, 2.91, 0.6607, -2.1929, 2.7904, 1.7532, -3.8773, 1.1862, 1.5121, -3.4321, 1.801, 2.332, -3.2513, 1.4491, -0.9484, -5.3598, 2.2535, -1.6095, -3.1051, 2.5592, -0.8975, -3.7031, 2.6018, -0.9484, -5.3598, 2.2535, -2.3213, -3.5933, 2.2613, -1.6095, -3.1051, 2.5592, 2.4159, -3.3908, 0.0683, 1.3907, -4.3898, 0.264, 1.8096, -3.8731, 0.517, 2.4159, -3.3908, 0.0683, 1.5973, -4.4989, -0.523, 1.3907, -4.3898, 0.264, 0.6607, -2.1929, 2.7904, 1.8364, -0.871, 2.91, 2.1556, -2.2057, 2.3132, -0.6892, -7.3327, -0.0456, 0.3707, -6.5026, 0.2358, 0.1584, -6.6788, -0.712, 2.7182, -1.9153, 1.6333, 2.332, -3.2513, 1.4491, 2.1556, -2.2057, 2.3132, -0.8975, -3.7031, 2.6018, -1.5434, -2.0626, 2.9798, -0.6296, -2.1168, 3.0274, -0.8975, -3.7031, 2.6018, -1.6095, -3.1051, 2.5592, -1.5434, -2.0626, 2.9798, -0.5191, -2.1018, -2.9939, -1.6189, -3.1121, -2.5666, -0.9004, -3.6647, -2.5803, -0.5191, -2.1018, -2.9939, -1.4897, -2.0239, -2.8933, -1.6189, -3.1121, -2.5666, 3.4106, -2.2767, -1.2285, 2.2303, -3.7001, -1.8804, 2.6374, -3.7219, -1.0723, 2.2303, -3.7001, -1.8804, 3.4189, -1.5098, -2.1519, 2.6485, -2.4319, -2.56, 2.2303, -3.7001, -1.8804, 3.4106, -2.2767, -1.2285, 3.4189, -1.5098, -2.1519, 0.6919, 3.2703, 2.2188, 1.3747, 1.7762, 2.618, 0.5064, 1.8556, 2.7003, 0.6919, 3.2703, 2.2188, 1.5121, 2.8416, 2.3106, 1.3747, 1.7762, 2.618, -2.7186, 2.9035, -1.3821, -2.8949, 1.7465, -1.4628, -2.3777, 2.1645, -2.0413, 3.6143, 2.6541, -0.7787, 3.481, 4.5391, 0.4718, 3.3017, 4.3689, -0.5397, 3.6143, 2.6541, -0.7787, 3.6836, 2.3906, 0.1427, 3.481, 4.5391, 0.4718, 0.7824, 7.1818, -0.4789, -0.2548, 6.3653, 0.3115, -0.2609, 6.3493, -0.8464, 0.7824, 7.1818, -0.4789, 0.9325, 6.924, 0.4365, -0.2548, 6.3653, 0.3115, -0.1504, -6.0468, 1.6347, -1.2352, -6.7568, 1.4079, -0.9484, -5.3598, 2.2535, 1.8096, -3.8731, 0.517, 0.8249, -4.8431, 1.2373, 1.7532, -3.8773, 1.1862, 0.8249, -4.8431, 1.2373, 1.3907, -4.3898, 0.264, 0.9197, -5.2139, 0.5803, 0.8249, -4.8431, 1.2373, 1.8096, -3.8731, 0.517, 1.3907, -4.3898, 0.264, -0.1302, -3.9225, 2.4564, 1.5121, -3.4321, 1.801, 0.6052, -4.4095, 1.8566, -0.1302, -3.9225, 2.4564, 0.6607, -2.1929, 2.7904, 1.5121, -3.4321, 1.801, 2.4159, -3.3908, 0.0683, 2.791, -2.0828, 0.6971, 3.0799, -1.877, -0.2485, 1.5973, -4.4989, -0.523, 1.6723, -4.1113, -1.5062, 0.8528, -5.1659, -1.2387, -3.0246, -4.4027, 0.8468, -2.3213, -3.5933, 2.2613, -2.3434, -5.4566, 1.3758, -3.0246, -4.4027, 0.8468, -3.048, -2.4163, 1.5053, -2.3213, -3.5933, 2.2613, -1.2211, -6.6432, -1.3733, -0.129, -6.0155, -1.6627, -0.9423, -5.2303, -2.2174, -3.0733, -4.4498, -0.8737, -2.3373, -3.6333, -2.2624, -3.1353, -2.4738, -1.533, -3.0733, -4.4498, -0.8737, -2.3738, -5.4707, -1.3892, -2.3373, -3.6333, -2.2624, 1.5835, -3.611, -1.9401, -0.0313, -3.8492, -2.3572, 0.5989, -4.5033, -1.836, 1.5835, -3.611, -1.9401, 1.2123, -2.2074, -2.6786, -0.0313, -3.8492, -2.3572, 2.5729, -0.0463, 2.323, 1.8364, -0.871, 2.91, 1.9677, 0.877, 2.8315, -2.9289, -0.1232, 2.5316, -2.1314, 0.7603, 3.0046, -2.2391, -1.0013, 3.2378, -2.0395, 0.8474, -2.9039, -2.8218, -0.0908, -2.3316, -2.0489, -0.9812, -3.014, 2.1308, -0.8122, -3.0291, 2.9911, 0.177, -2.5055, 2.0681, 1.0413, -2.9849, 3.2927, 2.696, 1.0915, 2.2766, 3.3307, 2.1367, 2.8818, 4.7444, 1.3483, 3.2927, 2.696, 1.0915, 2.8449, 1.8063, 1.8788, 2.2766, 3.3307, 2.1367, -2.9635, 2.0631, -0.0469, -2.7435, 3.293, -0.5137, -2.3926, 3.3478, 0.3255, 2.3528, 6.0999, 0.4838, 1.5686, 6.857, -0.4389, 2.4165, 5.7335, -0.6508, -2.3162, 3.6228, -0.9721, -1.137, 5.0901, -0.2048, -1.8973, 4.0438, -0.0231, -2.3162, 3.6228, -0.9721, -1.544, 3.8438, -1.471, -1.137, 5.0901, -0.2048, 0.4374, 4.5707, -2.224, 0.9515, 6.8097, -1.0683, -0.1803, 5.4522, -1.6664, 0.4374, 4.5707, -2.224, 1.4379, 5.2295, -1.8152, 0.9515, 6.8097, -1.0683, -1.2352, -6.7568, 1.4079, 0.3707, -6.5026, 0.2358, -0.6892, -7.3327, -0.0456, -1.2352, -6.7568, 1.4079, -0.1504, -6.0468, 1.6347, 0.3707, -6.5026, 0.2358, 0.6607, -2.1929, 2.7904, -0.8975, -3.7031, 2.6018, -0.6296, -2.1168, 3.0274, 0.6607, -2.1929, 2.7904, -0.1302, -3.9225, 2.4564, -0.8975, -3.7031, 2.6018, 2.791, -2.0828, 0.6971, 2.332, -3.2513, 1.4491, 2.7182, -1.9153, 1.6333, 2.791, -2.0828, 0.6971, 2.4159, -3.3908, 0.0683, 2.332, -3.2513, 1.4491, 1.6723, -4.1113, -1.5062, 2.6374, -3.7219, -1.0723, 2.2303, -3.7001, -1.8804, 1.6723, -4.1113, -1.5062, 1.5973, -4.4989, -0.523, 2.6374, -3.7219, -1.0723, -3.048, -2.4163, 1.5053, -3.2063, -3.9919, -0.0118, -3.2503, -1.9438, -0.0444, -3.048, -2.4163, 1.5053, -3.0246, -4.4027, 0.8468, -3.2063, -3.9919, -0.0118, -0.129, -6.0155, -1.6627, -0.6892, -7.3327, -0.0456, 0.1584, -6.6788, -0.712, -0.129, -6.0155, -1.6627, -1.2211, -6.6432, -1.3733, -0.6892, -7.3327, -0.0456, 1.2123, -2.2074, -2.6786, 2.2303, -3.7001, -1.8804, 2.6485, -2.4319, -2.56, 1.2123, -2.2074, -2.6786, 1.5835, -3.611, -1.9401, 2.2303, -3.7001, -1.8804, 3.3947, 0.8197, -1.419, 3.6836, 2.3906, 0.1427, 3.6143, 2.6541, -0.7787, 3.3947, 0.8197, -1.419, 3.39, -0.1345, -0.5433, 3.6836, 2.3906, 0.1427, -2.1314, 0.7603, 3.0046, -2.7222, 1.5834, 1.3251, -2.0691, 2.5964, 1.5185, -2.1314, 0.7603, 3.0046, -2.9289, -0.1232, 2.5316, -2.7222, 1.5834, 1.3251, 2.9911, 0.177, -2.5055, 2.6485, -2.4319, -2.56, 3.4189, -1.5098, -2.1519, 2.9911, 0.177, -2.5055, 2.1308, -0.8122, -3.0291, 2.6485, -2.4319, -2.56, -2.7435, 3.293, -0.5137, -2.8949, 1.7465, -1.4628, -2.7186, 2.9035, -1.3821, -2.7435, 3.293, -0.5137, -2.9635, 2.0631, -0.0469, -2.8949, 1.7465, -1.4628, -0.1459, 3.4745, -2.3857, 1.1494, 2.3687, -2.734, 0.549, 3.3793, -2.5003, -0.1459, 3.4745, -2.3857, -1.2285, 2.4662, -2.4325, 1.1494, 2.3687, -2.734, 2.3543, 3.9299, -1.7328, 3.6143, 2.6541, -0.7787, 3.3017, 4.3689, -0.5397, 2.3543, 3.9299, -1.7328, 3.0814, 2.2747, -1.5878, 3.6143, 2.6541, -0.7787, 1.5686, 6.857, -0.4389, 0.9325, 6.924, 0.4365, 0.7824, 7.1818, -0.4789, 1.5686, 6.857, -0.4389, 2.3528, 6.0999, 0.4838, 0.9325, 6.924, 0.4365, -1.544, 3.8438, -1.471, -2.7186, 2.9035, -1.3821, -2.3777, 2.1645, -2.0413, -1.544, 3.8438, -1.471, -2.3162, 3.6228, -0.9721, -2.7186, 2.9035, -1.3821, 1.4379, 5.2295, -1.8152, 0.549, 3.3793, -2.5003, 1.1494, 2.3687, -2.734, 1.4379, 5.2295, -1.8152, 0.4374, 4.5707, -2.224, 0.549, 3.3793, -2.5003, 2.1556, -2.2057, 2.3132, 1.5121, -3.4321, 1.801, 0.6607, -2.1929, 2.7904, 2.1556, -2.2057, 2.3132, 2.332, -3.2513, 1.4491, 1.5121, -3.4321, 1.801, 3.4106, -2.2767, -1.2285, 2.4159, -3.3908, 0.0683, 3.0799, -1.877, -0.2485, 3.4106, -2.2767, -1.2285, 2.6374, -3.7219, -1.0723, 2.4159, -3.3908, 0.0683, 0.1584, -6.6788, -0.712, 1.5973, -4.4989, -0.523, 0.8528, -5.1659, -1.2387, 0.1584, -6.6788, -0.712, 0.3707, -6.5026, 0.2358, 1.5973, -4.4989, -0.523, -3.2503, -1.9438, -0.0444, -3.0733, -4.4498, -0.8737, -3.1353, -2.4738, -1.533, -3.2503, -1.9438, -0.0444, -3.2063, -3.9919, -0.0118, -3.0733, -4.4498, -0.8737, -0.5191, -2.1018, -2.9939, -0.0313, -3.8492, -2.3572, 1.2123, -2.2074, -2.6786, -0.5191, -2.1018, -2.9939, -0.9004, -3.6647, -2.5803, -0.0313, -3.8492, -2.3572, 3.4189, -1.5098, -2.1519, 3.39, -0.1345, -0.5433, 3.3947, 0.8197, -1.419, 3.4189, -1.5098, -2.1519, 3.4106, -2.2767, -1.2285, 3.39, -0.1345, -0.5433, 2.7182, -1.9153, 1.6333, 1.8364, -0.871, 2.91, 2.5729, -0.0463, 2.323, 2.7182, -1.9153, 1.6333, 2.1556, -2.2057, 2.3132, 1.8364, -0.871, 2.91, -2.3777, 2.1645, -2.0413, -2.8218, -0.0908, -2.3316, -2.0395, 0.8474, -2.9039, -2.3777, 2.1645, -2.0413, -2.8949, 1.7465, -1.4628, -2.8218, -0.0908, -2.3316, 3.481, 4.5391, 0.4718, 3.2927, 2.696, 1.0915, 2.8818, 4.7444, 1.3483, 3.481, 4.5391, 0.4718, 3.6836, 2.3906, 0.1427, 3.2927, 2.696, 1.0915, 0.6919, 3.2703, 2.2188, -1.0522, 1.986, 2.2721, -0.2637, 3.5029, 1.8153, 0.6919, 3.2703, 2.2188, 0.5064, 1.8556, 2.7003, -1.0522, 1.986, 2.2721, -2.0691, 2.5964, 1.5185, -2.9635, 2.0631, -0.0469, -2.3926, 3.3478, 0.3255, -2.0691, 2.5964, 1.5185, -2.7222, 1.5834, 1.3251, -2.9635, 2.0631, -0.0469, -0.2548, 6.3653, 0.3115, 1.4341, 6.0081, 1.2447, 0.4487, 4.8708, 1.6514, -0.2548, 6.3653, 0.3115, 0.9325, 6.924, 0.4365, 1.4341, 6.0081, 1.2447, 3.3017, 4.3689, -0.5397, 2.3528, 6.0999, 0.4838, 2.4165, 5.7335, -0.6508, 3.3017, 4.3689, -0.5397, 3.481, 4.5391, 0.4718, 2.3528, 6.0999, 0.4838, -0.2609, 6.3493, -0.8464, -1.137, 5.0901, -0.2048, -1.544, 3.8438, -1.471, -0.2609, 6.3493, -0.8464, -0.2548, 6.3653, 0.3115, -1.137, 5.0901, -0.2048, 0.7824, 7.1818, -0.4789, -0.1803, 5.4522, -1.6664, 0.9515, 6.8097, -1.0683, 0.7824, 7.1818, -0.4789, -0.2609, 6.3493, -0.8464, -0.1803, 5.4522, -1.6664, 2.4165, 5.7335, -0.6508, 0.9515, 6.8097, -1.0683, 1.4379, 5.2295, -1.8152, 2.4165, 5.7335, -0.6508, 1.5686, 6.857, -0.4389, 0.9515, 6.8097, -1.0683, 0.4374, 4.5707, -2.224, -1.2285, 2.4662, -2.4325, -0.1459, 3.4745, -2.3857, 0.4374, 4.5707, -2.224, -0.1803, 5.4522, -1.6664, -1.2285, 2.4662, -2.4325, -1.8973, 4.0438, -0.0231, -0.7059, 4.7856, 0.8682, -1.6818, 3.3981, 1.0198, -1.8973, 4.0438, -0.0231, -1.137, 5.0901, -0.2048, -0.7059, 4.7856, 0.8682, -2.3162, 3.6228, -0.9721, -2.3926, 3.3478, 0.3255, -2.7435, 3.293, -0.5137, -2.3162, 3.6228, -0.9721, -1.8973, 4.0438, -0.0231, -2.3926, 3.3478, 0.3255, -1.6818, 3.3981, 1.0198, -0.2637, 3.5029, 1.8153, -1.0522, 1.986, 2.2721, -1.6818, 3.3981, 1.0198, -0.7059, 4.7856, 0.8682, -0.2637, 3.5029, 1.8153, 0.4487, 4.8708, 1.6514, 2.8818, 4.7444, 1.3483, 2.2766, 3.3307, 2.1367, 0.4487, 4.8708, 1.6514, 1.4341, 6.0081, 1.2447, 2.8818, 4.7444, 1.3483, 3.0814, 2.2747, -1.5878, 2.0681, 1.0413, -2.9849, 2.9911, 0.177, -2.5055, 3.0814, 2.2747, -1.5878, 2.3543, 3.9299, -1.7328, 2.0681, 1.0413, -2.9849, 0.0444, -0.8451, -3.3989, -2.0395, 0.8474, -2.9039, -2.0489, -0.9812, -3.014, 0.0444, -0.8451, -3.3989, 0.0399, 0.8971, -3.3453, -2.0395, 0.8474, -2.9039, -2.2391, -1.0013, 3.2378, 0.0817, 0.7564, 3.232, -0.0319, -0.907, 3.3884, -2.2391, -1.0013, 3.2378, -2.1314, 0.7603, 3.0046, 0.0817, 0.7564, 3.232, 2.5729, -0.0463, 2.323, 2.2766, 3.3307, 2.1367, 2.8449, 1.8063, 1.8788, 2.5729, -0.0463, 2.323, 1.9677, 0.877, 2.8315, 2.2766, 3.3307, 2.1367, 2.8449, 1.8063, 1.8788, 3.0694, 0.3768, 0.2917, 2.6862, -0.2733, 1.344, 2.8449, 1.8063, 1.8788, 3.2927, 2.696, 1.0915, 3.0694, 0.3768, 0.2917, 2.1308, -0.8122, -3.0291, 0.0399, 0.8971, -3.3453, 0.0444, -0.8451, -3.3989, 2.1308, -0.8122, -3.0291, 2.0681, 1.0413, -2.9849, 0.0399, 0.8971, -3.3453, -2.0489, -0.9812, -3.014, -3.1353, -2.4738, -1.533, -2.3373, -3.6333, -2.2624, -2.0489, -0.9812, -3.014, -2.8218, -0.0908, -2.3316, -3.1353, -2.4738, -1.533, -2.9289, -0.1232, 2.5316, -2.3213, -3.5933, 2.2613, -3.048, -2.4163, 1.5053, -2.9289, -0.1232, 2.5316, -2.2391, -1.0013, 3.2378, -2.3213, -3.5933, 2.2613, -0.0319, -0.907, 3.3884, 1.9677, 0.877, 2.8315, 1.8364, -0.871, 2.91, -0.0319, -0.907, 3.3884, 0.0817, 0.7564, 3.232, 1.9677, 0.877, 2.8315, 2.6862, -0.2733, 1.344, 3.0799, -1.877, -0.2485, 2.791, -2.0828, 0.6971, 2.6862, -0.2733, 1.344, 3.0694, 0.3768, 0.2917, 3.0799, -1.877, -0.2485, 0.8528, -5.1659, -1.2387, 1.5835, -3.611, -1.9401, 0.5989, -4.5033, -1.836, 0.8528, -5.1659, -1.2387, 1.6723, -4.1113, -1.5062, 1.5835, -3.611, -1.9401, 0.5989, -4.5033, -1.836, -0.9423, -5.2303, -2.2174, -0.129, -6.0155, -1.6627, 0.5989, -4.5033, -1.836, -0.0313, -3.8492, -2.3572, -0.9423, -5.2303, -2.2174, -1.2211, -6.6432, -1.3733, -2.3373, -3.6333, -2.2624, -2.3738, -5.4707, -1.3892, -1.2211, -6.6432, -1.3733, -0.9423, -5.2303, -2.2174, -2.3373, -3.6333, -2.2624, -2.3738, -5.4707, -1.3892, -2.8602, -5.2902, -0.0034, -1.8677, -6.7222, 0.0053, -2.3738, -5.4707, -1.3892, -3.0733, -4.4498, -0.8737, -2.8602, -5.2902, -0.0034, -1.8677, -6.7222, 0.0053, -3.0246, -4.4027, 0.8468, -2.3434, -5.4566, 1.3758, -1.8677, -6.7222, 0.0053, -2.8602, -5.2902, -0.0034, -3.0246, -4.4027, 0.8468, -2.3434, -5.4566, 1.3758, -0.9484, -5.3598, 2.2535, -1.2352, -6.7568, 1.4079, -2.3434, -5.4566, 1.3758, -2.3213, -3.5933, 2.2613, -0.9484, -5.3598, 2.2535, -0.1504, -6.0468, 1.6347, -0.1302, -3.9225, 2.4564, 0.6052, -4.4095, 1.8566, -0.1504, -6.0468, 1.6347, -0.9484, -5.3598, 2.2535, -0.1302, -3.9225, 2.4564, 0.6052, -4.4095, 1.8566, 1.7532, -3.8773, 1.1862, 0.8249, -4.8431, 1.2373, 0.6052, -4.4095, 1.8566, 1.5121, -3.4321, 1.801, 1.7532, -3.8773, 1.1862, -0.6892, -7.3327, -0.0456, -1.8677, -6.7222, 0.0053, -1.2352, -6.7568, 1.4079) + +[node name="RockC" instance=ExtResource("1_pb27A")] +collision_mask = 3 + +[node name="Rock3" parent="." index="0"] +surface_material_override/0 = ExtResource("2_pcex8") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." index="1"] +shape = SubResource("ConcavePolygonShape3D_ycsjC") diff --git a/demo/assets/models/Tunnel.glb b/demo/assets/models/Tunnel.glb new file mode 100644 index 0000000..ce0cc4f Binary files /dev/null and b/demo/assets/models/Tunnel.glb differ diff --git a/demo/assets/models/Tunnel.glb.import b/demo/assets/models/Tunnel.glb.import new file mode 100644 index 0000000..e9fac26 --- /dev/null +++ b/demo/assets/models/Tunnel.glb.import @@ -0,0 +1,44 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://jib546bbort5" +path="res://.godot/imported/Tunnel.glb-09729773791c3078e933c866961e1b60.scn" + +[deps] + +source_file="res://demo/assets/models/Tunnel.glb" +dest_files=["res://.godot/imported/Tunnel.glb-09729773791c3078e933c866961e1b60.scn"] + +[params] + +nodes/root_type="StaticBody3D" +nodes/root_name="Scene Root" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=true +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={ +"materials": { +"material_0": { +"use_external/enabled": false, +"use_external/path": "uid://nbbdrx8vma80" +} +} +} +gltf/naming_version=0 +gltf/embedded_image_handling=1 diff --git a/demo/assets/models/Tunnel.tscn b/demo/assets/models/Tunnel.tscn new file mode 100644 index 0000000..d2fdf8d --- /dev/null +++ b/demo/assets/models/Tunnel.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=4 format=3 uid="uid://vvayjv3rbx1d"] + +[ext_resource type="PackedScene" uid="uid://jib546bbort5" path="res://demo/assets/models/Tunnel.glb" id="1_1sr0i"] +[ext_resource type="Material" uid="uid://nbbdrx8vma80" path="res://demo/assets/materials/M_rock23_tp.tres" id="2_lkb1r"] + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_bh6xx"] +data = PackedVector3Array(266.67, 5.3424, -18.2649, 266.427, 5.495, -16.0799, 266.642, 5.495, -18.2666, 267.292, 1.9054, -18.2263, 267.068, 1.9054, -15.9524, 266.67, 5.3424, -18.2649, 267.068, 1.9054, -15.9524, 266.427, 5.495, -16.0799, 266.67, 5.3424, -18.2649, 264.802, 8.7484, -18.3807, 264.54, 8.8761, -16.4552, 264.73, 8.8761, -18.3851, 266.642, 5.495, -18.2666, 266.427, 5.495, -16.0799, 264.802, 8.7484, -18.3807, 266.427, 5.495, -16.0799, 264.54, 8.8761, -16.4552, 264.802, 8.7484, -18.3807, 261.76, 11.7626, -18.5693, 261.518, 11.852, -17.0563, 261.668, 11.852, -18.575, 264.73, 8.8761, -18.3851, 264.54, 8.8761, -16.4552, 261.76, 11.7626, -18.5693, 264.54, 8.8761, -16.4552, 261.518, 11.852, -17.0563, 261.76, 11.7626, -18.5693, 257.712, 14.2028, -18.8203, 257.536, 14.2498, -17.8483, 257.633, 14.2498, -18.8252, 261.668, 11.852, -18.575, 261.518, 11.852, -17.0563, 257.712, 14.2028, -18.8203, 261.518, 11.852, -17.0563, 257.536, 14.2498, -17.8483, 257.712, 14.2028, -18.8203, 252.892, 15.9187, -19.1192, 252.826, 15.9302, -18.7853, 252.859, 15.9302, -19.1212, 257.633, 14.2498, -18.8252, 257.536, 14.2498, -17.8483, 252.892, 15.9187, -19.1192, 257.536, 14.2498, -17.8483, 252.826, 15.9302, -18.7853, 252.892, 15.9187, -19.1192, 252.859, 15.9302, -19.1212, 252.826, 15.9302, -18.7853, 250.357, 16.3438, -19.2763, 252.823, -12.1253, -19.1234, 252.826, -12.1193, -18.7853, 252.859, -12.1193, -19.1212, 250.357, -12.5329, -19.2763, 252.826, -12.1193, -18.7853, 252.823, -12.1253, -19.1234, 257.538, -10.4722, -18.8311, 257.536, -10.4389, -17.8483, 257.633, -10.4389, -18.8252, 252.859, -12.1193, -19.1212, 252.826, -12.1193, -18.7853, 257.538, -10.4722, -18.8311, 252.826, -12.1193, -18.7853, 257.536, -10.4389, -17.8483, 257.538, -10.4722, -18.8311, 261.546, -8.1137, -18.5826, 261.518, -8.0411, -17.0563, 261.668, -8.0411, -18.575, 257.633, -10.4389, -18.8252, 257.536, -10.4389, -17.8483, 261.546, -8.1137, -18.5826, 257.536, -10.4389, -17.8483, 261.518, -8.0411, -17.0563, 261.546, -8.1137, -18.5826, 264.614, -5.1782, -18.3923, 264.54, -5.0652, -16.4552, 264.73, -5.0652, -18.3851, 261.668, -8.0411, -18.575, 261.518, -8.0411, -17.0563, 264.614, -5.1782, -18.3923, 261.518, -8.0411, -17.0563, 264.54, -5.0652, -16.4552, 264.614, -5.1782, -18.3923, 266.56, -1.8284, -18.2717, 266.427, -1.6842, -16.0799, 266.642, -1.6842, -18.2666, 264.73, -5.0652, -18.3851, 264.54, -5.0652, -16.4552, 266.56, -1.8284, -18.2717, 264.54, -5.0652, -16.4552, 266.427, -1.6842, -16.0799, 266.56, -1.8284, -18.2717, 267.263, 1.7469, -18.2281, 267.068, 1.9054, -15.9524, 267.292, 1.9054, -18.2263, 266.642, -1.6842, -18.2666, 266.427, -1.6842, -16.0799, 267.263, 1.7469, -18.2281, 266.427, -1.6842, -16.0799, 267.068, 1.9054, -15.9524, 267.263, 1.7469, -18.2281, 267.068, 1.9054, -15.9524, 251.436, 5.495, 33.3375, 266.427, 5.495, -16.0799, 252.04, 1.9054, 33.5877, 251.436, 5.495, 33.3375, 267.068, 1.9054, -15.9524, 266.427, 5.495, -16.0799, 249.659, 8.876, 32.6014, 264.54, 8.8761, -16.4552, 251.436, 5.495, 33.3375, 249.659, 8.876, 32.6014, 266.427, 5.495, -16.0799, 264.54, 8.8761, -16.4552, 246.812, 11.8519, 31.4223, 261.518, 11.852, -17.0563, 249.659, 8.876, 32.6014, 246.812, 11.8519, 31.4223, 264.54, 8.8761, -16.4552, 261.518, 11.852, -17.0563, 243.061, 14.2498, 29.8687, 257.536, 14.2498, -17.8483, 246.812, 11.8519, 31.4223, 243.061, 14.2498, 29.8687, 261.518, 11.852, -17.0563, 257.536, 14.2498, -17.8483, 238.624, 15.9302, 28.0308, 252.826, 15.9302, -18.7853, 243.061, 14.2498, 29.8687, 238.624, 15.9302, 28.0308, 257.536, 14.2498, -17.8483, 250.357, 16.3438, -19.2763, 252.826, 15.9302, -18.7853, 247.551, 16.7956, -19.4503, 252.826, 15.9302, -18.7853, 233.759, 16.7956, 26.0154, 247.551, 16.7956, -19.4503, 238.624, 15.9302, 28.0308, 233.759, 16.7956, 26.0154, 252.826, 15.9302, -18.7853, 247.505, 16.7956, -19.4531, 228.748, 16.7956, 23.9398, 242.014, 16.7956, -19.7936, 247.551, 16.7956, -19.4503, 233.759, 16.7956, 26.0154, 247.505, 16.7956, -19.4531, 233.759, 16.7956, 26.0154, 228.748, 16.7956, 23.9398, 247.505, 16.7956, -19.4531, 241.88, 16.774, -19.8019, 223.882, 15.9302, 21.9244, 236.638, 15.9302, -20.1269, 242.014, 16.7956, -19.7936, 228.748, 16.7956, 23.9398, 241.88, 16.774, -19.8019, 228.748, 16.7956, 23.9398, 223.882, 15.9302, 21.9244, 241.88, 16.774, -19.8019, 236.433, 15.8598, -20.1396, 219.445, 14.2498, 20.0865, 231.736, 14.2498, -20.4309, 236.638, 15.9302, -20.1269, 223.882, 15.9302, 21.9244, 236.433, 15.8598, -20.1396, 223.882, 15.9302, 21.9244, 219.445, 14.2498, 20.0865, 236.433, 15.8598, -20.1396, 231.497, 14.1113, -20.4457, 215.694, 11.8519, 18.5328, 227.592, 11.8519, -20.6878, 231.736, 14.2498, -20.4309, 219.445, 14.2498, 20.0865, 231.497, 14.1113, -20.4457, 219.445, 14.2498, 20.0865, 215.694, 11.8519, 18.5328, 231.497, 14.1113, -20.4457, 227.367, 11.6395, -20.7018, 212.848, 8.876, 17.3537, 224.447, 8.876, -20.8828, 227.592, 11.8519, -20.6878, 215.694, 11.8519, 18.5328, 227.367, 11.6395, -20.7018, 215.694, 11.8519, 18.5328, 212.848, 8.876, 17.3537, 227.367, 11.6395, -20.7018, 224.286, 8.6, -20.8928, 211.071, 5.4951, 16.6177, 222.483, 5.4951, -21.0046, 224.447, 8.876, -20.8828, 212.848, 8.876, 17.3537, 224.286, 8.6, -20.8928, 212.848, 8.876, 17.3537, 211.071, 5.495, 16.6177, 224.286, 8.6, -20.8928, 222.425, 5.18, -21.0082, 210.467, 1.9054, 16.3675, 221.816, 1.9054, -21.046, 222.483, 5.4951, -21.0046, 211.071, 5.495, 16.6177, 222.425, 5.18, -21.0082, 211.071, 5.495, 16.6177, 210.467, 1.9054, 16.3675, 222.425, 5.18, -21.0082, 221.876, 1.5852, -21.0423, 211.071, -1.6842, 16.6177, 222.483, -1.6842, -21.0046, 221.816, 1.9054, -21.046, 210.467, 1.9054, 16.3675, 221.876, 1.5852, -21.0423, 210.467, 1.9054, 16.3675, 211.071, -1.6842, 16.6177, 221.876, 1.5852, -21.0423, 222.652, -1.975, -20.9941, 212.848, -5.0652, 17.3537, 224.447, -5.0652, -20.8828, 222.483, -1.6842, -21.0046, 211.071, -1.6842, 16.6177, 222.652, -1.975, -20.9941, 211.071, -1.6842, 16.6177, 212.848, -5.0652, 17.3537, 222.652, -1.975, -20.9941, 224.694, -5.2991, -20.8675, 215.694, -8.0411, 18.5329, 227.592, -8.0411, -20.6878, 224.447, -5.0652, -20.8828, 212.848, -5.0652, 17.3537, 224.694, -5.2991, -20.8675, 212.848, -5.0652, 17.3537, 215.694, -8.0411, 18.5329, 224.694, -5.2991, -20.8675, 227.872, -8.2033, -20.6705, 219.445, -10.4389, 20.0865, 231.736, -10.4389, -20.4309, 227.592, -8.0411, -20.6878, 215.694, -8.0411, 18.5329, 227.872, -8.2033, -20.6705, 215.694, -8.0411, 18.5329, 219.445, -10.4389, 20.0865, 227.872, -8.2033, -20.6705, 232.001, -10.5298, -20.4144, 223.882, -12.1193, 21.9244, 236.638, -12.1193, -20.1269, 231.736, -10.4389, -20.4309, 219.445, -10.4389, 20.0865, 232.001, -10.5298, -20.4144, 219.445, -10.4389, 20.0865, 223.882, -12.1193, 21.9244, 232.001, -10.5298, -20.4144, 236.848, -12.153, -20.1139, 228.748, -12.9847, 23.9398, 242.014, -12.9847, -19.7936, 236.638, -12.1193, -20.1269, 223.882, -12.1193, 21.9244, 236.848, -12.153, -20.1139, 223.882, -12.1193, 21.9244, 228.748, -12.9847, 23.9398, 236.848, -12.153, -20.1139, 242.142, -12.9847, -19.7857, 233.759, -12.9847, 26.0154, 247.551, -12.9847, -19.4503, 242.014, -12.9847, -19.7936, 228.748, -12.9847, 23.9398, 242.142, -12.9847, -19.7857, 228.748, -12.9847, 23.9398, 233.759, -12.9847, 26.0154, 242.142, -12.9847, -19.7857, 247.592, -12.9781, -19.4478, 238.624, -12.1193, 28.0308, 252.826, -12.1193, -18.7853, 247.592, -12.9781, -19.4478, 252.826, -12.1193, -18.7853, 250.357, -12.5329, -19.2763, 247.551, -12.9847, -19.4503, 233.759, -12.9847, 26.0154, 247.592, -12.9781, -19.4478, 233.759, -12.9847, 26.0154, 238.624, -12.1193, 28.0308, 247.592, -12.9781, -19.4478, 252.826, -12.1193, -18.7853, 243.061, -10.4389, 29.8687, 257.536, -10.4389, -17.8483, 238.624, -12.1193, 28.0308, 243.061, -10.4389, 29.8687, 252.826, -12.1193, -18.7853, 257.536, -10.4389, -17.8483, 246.812, -8.0411, 31.4223, 261.518, -8.0411, -17.0563, 243.061, -10.4389, 29.8687, 246.812, -8.0411, 31.4223, 257.536, -10.4389, -17.8483, 261.518, -8.0411, -17.0563, 249.659, -5.0652, 32.6014, 264.54, -5.0652, -16.4552, 246.812, -8.0411, 31.4223, 249.659, -5.0652, 32.6014, 261.518, -8.0411, -17.0563, 264.54, -5.0652, -16.4552, 251.436, -1.6842, 33.3375, 266.427, -1.6842, -16.0799, 249.659, -5.0652, 32.6014, 251.436, -1.6842, 33.3375, 264.54, -5.0652, -16.4552, 266.427, -1.6842, -16.0799, 252.04, 1.9054, 33.5877, 267.068, 1.9054, -15.9524, 251.436, -1.6842, 33.3375, 252.04, 1.9054, 33.5877, 266.427, -1.6842, -16.0799, 252.04, 1.9054, 33.5877, 227.092, 5.495, 78.8808, 251.436, 5.495, 33.3375, 227.636, 1.9054, 79.2441, 227.092, 5.495, 78.8808, 252.04, 1.9054, 33.5877, 251.436, 5.495, 33.3375, 225.493, 8.876, 77.8123, 249.659, 8.876, 32.6014, 227.092, 5.495, 78.8808, 225.493, 8.876, 77.8123, 251.436, 5.495, 33.3375, 249.659, 8.876, 32.6014, 222.931, 11.8519, 76.1005, 246.812, 11.8519, 31.4223, 225.493, 8.876, 77.8123, 222.931, 11.8519, 76.1005, 249.659, 8.876, 32.6014, 246.812, 11.8519, 31.4223, 219.556, 14.2498, 73.8449, 243.061, 14.2498, 29.8687, 222.931, 11.8519, 76.1005, 219.556, 14.2498, 73.8449, 246.812, 11.8519, 31.4223, 243.061, 14.2498, 29.8687, 215.562, 15.9302, 71.1767, 238.624, 15.9302, 28.0308, 219.556, 14.2498, 73.8449, 215.562, 15.9302, 71.1767, 243.061, 14.2498, 29.8687, 238.624, 15.9302, 28.0308, 211.184, 16.7956, 68.2508, 233.759, 16.7956, 26.0154, 215.562, 15.9302, 71.1767, 211.184, 16.7956, 68.2508, 238.624, 15.9302, 28.0308, 233.759, 16.7956, 26.0154, 206.674, 16.7956, 65.2375, 228.748, 16.7956, 23.9398, 211.184, 16.7956, 68.2508, 206.674, 16.7956, 65.2375, 233.759, 16.7956, 26.0154, 228.748, 16.7956, 23.9398, 202.295, 15.9302, 62.3116, 223.882, 15.9302, 21.9244, 206.674, 16.7956, 65.2375, 202.295, 15.9302, 62.3116, 228.748, 16.7956, 23.9398, 223.882, 15.9302, 21.9244, 198.302, 14.2498, 59.6434, 219.445, 14.2498, 20.0865, 202.295, 15.9302, 62.3116, 198.302, 14.2498, 59.6434, 223.882, 15.9302, 21.9244, 219.445, 14.2498, 20.0865, 194.926, 11.8519, 57.3878, 215.694, 11.8519, 18.5328, 198.302, 14.2498, 59.6434, 194.926, 11.8519, 57.3878, 219.445, 14.2498, 20.0865, 215.694, 11.8519, 18.5328, 192.364, 8.876, 55.676, 212.848, 8.876, 17.3537, 194.926, 11.8519, 57.3878, 192.364, 8.876, 55.676, 215.694, 11.8519, 18.5328, 212.848, 8.876, 17.3537, 190.765, 5.495, 54.6075, 211.071, 5.495, 16.6177, 192.364, 8.876, 55.676, 190.765, 5.495, 54.6075, 212.848, 8.876, 17.3537, 211.071, 5.495, 16.6177, 190.221, 1.9054, 54.2442, 210.467, 1.9054, 16.3675, 190.765, 5.495, 54.6075, 190.221, 1.9054, 54.2442, 211.071, 5.495, 16.6177, 210.467, 1.9054, 16.3675, 190.765, -1.6842, 54.6075, 211.071, -1.6842, 16.6177, 190.221, 1.9054, 54.2442, 190.765, -1.6842, 54.6075, 210.467, 1.9054, 16.3675, 211.071, -1.6842, 16.6177, 192.364, -5.0652, 55.676, 212.848, -5.0652, 17.3537, 190.765, -1.6842, 54.6075, 192.364, -5.0652, 55.676, 211.071, -1.6842, 16.6177, 212.848, -5.0652, 17.3537, 194.926, -8.0411, 57.3878, 215.694, -8.0411, 18.5329, 192.364, -5.0652, 55.676, 194.926, -8.0411, 57.3878, 212.848, -5.0652, 17.3537, 215.694, -8.0411, 18.5329, 198.302, -10.4389, 59.6434, 219.445, -10.4389, 20.0865, 194.926, -8.0411, 57.3878, 198.302, -10.4389, 59.6434, 215.694, -8.0411, 18.5329, 219.445, -10.4389, 20.0865, 202.295, -12.1193, 62.3116, 223.882, -12.1193, 21.9244, 198.302, -10.4389, 59.6434, 202.295, -12.1193, 62.3116, 219.445, -10.4389, 20.0865, 223.882, -12.1193, 21.9244, 206.674, -12.9847, 65.2375, 228.748, -12.9847, 23.9398, 202.295, -12.1193, 62.3116, 206.674, -12.9847, 65.2375, 223.882, -12.1193, 21.9244, 228.748, -12.9847, 23.9398, 211.184, -12.9847, 68.2508, 233.759, -12.9847, 26.0154, 206.674, -12.9847, 65.2375, 211.184, -12.9847, 68.2508, 228.748, -12.9847, 23.9398, 233.759, -12.9847, 26.0154, 215.562, -12.1193, 71.1767, 238.624, -12.1193, 28.0308, 211.184, -12.9847, 68.2508, 215.562, -12.1193, 71.1767, 233.759, -12.9847, 26.0154, 238.624, -12.1193, 28.0308, 219.556, -10.4389, 73.8449, 243.061, -10.4389, 29.8687, 215.562, -12.1193, 71.1767, 219.556, -10.4389, 73.8449, 238.624, -12.1193, 28.0308, 243.061, -10.4389, 29.8687, 222.931, -8.0411, 76.1005, 246.812, -8.0411, 31.4223, 219.556, -10.4389, 73.8449, 222.931, -8.0411, 76.1005, 243.061, -10.4389, 29.8687, 246.812, -8.0411, 31.4223, 225.493, -5.0652, 77.8123, 249.659, -5.0652, 32.6014, 222.931, -8.0411, 76.1005, 225.493, -5.0652, 77.8123, 246.812, -8.0411, 31.4223, 249.659, -5.0652, 32.6014, 227.092, -1.6842, 78.8808, 251.436, -1.6842, 33.3375, 225.493, -5.0652, 77.8123, 227.092, -1.6842, 78.8808, 249.659, -5.0652, 32.6014, 251.436, -1.6842, 33.3375, 227.636, 1.9054, 79.2441, 252.04, 1.9054, 33.5877, 227.092, -1.6842, 78.8808, 227.636, 1.9054, 79.2441, 251.436, -1.6842, 33.3375, 227.636, 1.9054, 79.2441, 194.332, 5.495, 118.8, 227.092, 5.495, 78.8808, 194.794, 1.9054, 119.262, 194.332, 5.495, 118.8, 227.636, 1.9054, 79.2441, 227.092, 5.495, 78.8808, 192.972, 8.876, 117.44, 225.493, 8.876, 77.8123, 194.332, 5.495, 118.8, 192.972, 8.876, 117.44, 227.092, 5.495, 78.8808, 225.493, 8.876, 77.8123, 190.793, 11.8519, 115.261, 222.931, 11.8519, 76.1005, 192.972, 8.876, 117.44, 190.793, 11.8519, 115.261, 225.493, 8.876, 77.8123, 222.931, 11.8519, 76.1005, 187.922, 14.2498, 112.39, 219.556, 14.2498, 73.8449, 190.793, 11.8519, 115.261, 187.922, 14.2498, 112.39, 222.931, 11.8519, 76.1005, 219.556, 14.2498, 73.8449, 184.526, 15.9302, 108.994, 215.562, 15.9302, 71.1767, 187.922, 14.2498, 112.39, 184.526, 15.9302, 108.994, 219.556, 14.2498, 73.8449, 215.562, 15.9302, 71.1767, 180.802, 16.7956, 105.271, 211.184, 16.7956, 68.2508, 184.526, 15.9302, 108.994, 180.802, 16.7956, 105.271, 215.562, 15.9302, 71.1767, 211.184, 16.7956, 68.2508, 176.967, 16.7956, 101.435, 206.674, 16.7956, 65.2375, 180.802, 16.7956, 105.271, 176.967, 16.7956, 101.435, 211.184, 16.7956, 68.2508, 206.674, 16.7956, 65.2375, 173.243, 15.9302, 97.7113, 202.295, 15.9302, 62.3116, 176.967, 16.7956, 101.435, 173.243, 15.9302, 97.7113, 206.674, 16.7956, 65.2375, 202.295, 15.9302, 62.3116, 169.847, 14.2498, 94.3153, 198.302, 14.2498, 59.6434, 173.243, 15.9302, 97.7113, 169.847, 14.2498, 94.3153, 202.295, 15.9302, 62.3116, 198.302, 14.2498, 59.6434, 166.976, 11.8519, 91.4445, 194.926, 11.8519, 57.3878, 169.847, 14.2498, 94.3153, 166.976, 11.8519, 91.4445, 198.302, 14.2498, 59.6434, 194.926, 11.8519, 57.3878, 164.798, 8.876, 89.2658, 192.364, 8.876, 55.676, 166.976, 11.8519, 91.4445, 164.798, 8.876, 89.2658, 194.926, 11.8519, 57.3878, 192.364, 8.876, 55.676, 163.438, 5.495, 87.9057, 190.765, 5.495, 54.6075, 164.798, 8.876, 89.2658, 163.438, 5.495, 87.9057, 192.364, 8.876, 55.676, 190.765, 5.495, 54.6075, 162.975, 1.9054, 87.4435, 190.221, 1.9054, 54.2442, 163.438, 5.495, 87.9057, 162.975, 1.9054, 87.4435, 190.765, 5.495, 54.6075, 190.221, 1.9054, 54.2442, 163.438, -1.6842, 87.9057, 190.765, -1.6842, 54.6075, 162.975, 1.9054, 87.4435, 163.438, -1.6842, 87.9057, 190.221, 1.9054, 54.2442, 190.765, -1.6842, 54.6075, 164.798, -5.0652, 89.2658, 192.364, -5.0652, 55.676, 163.438, -1.6842, 87.9057, 164.798, -5.0652, 89.2658, 190.765, -1.6842, 54.6075, 192.364, -5.0652, 55.676, 166.976, -8.0411, 91.4445, 194.926, -8.0411, 57.3878, 164.798, -5.0652, 89.2658, 166.976, -8.0411, 91.4445, 192.364, -5.0652, 55.676, 194.926, -8.0411, 57.3878, 169.847, -10.4389, 94.3153, 198.302, -10.4389, 59.6434, 166.976, -8.0411, 91.4445, 169.847, -10.4389, 94.3153, 194.926, -8.0411, 57.3878, 198.302, -10.4389, 59.6434, 173.243, -12.1193, 97.7113, 202.295, -12.1193, 62.3116, 169.847, -10.4389, 94.3153, 173.243, -12.1193, 97.7113, 198.302, -10.4389, 59.6434, 202.295, -12.1193, 62.3116, 176.967, -12.9847, 101.435, 206.674, -12.9847, 65.2375, 173.243, -12.1193, 97.7113, 176.967, -12.9847, 101.435, 202.295, -12.1193, 62.3116, 206.674, -12.9847, 65.2375, 180.802, -12.9847, 105.271, 211.184, -12.9847, 68.2508, 176.967, -12.9847, 101.435, 180.802, -12.9847, 105.271, 206.674, -12.9847, 65.2375, 211.184, -12.9847, 68.2508, 184.526, -12.1193, 108.994, 215.562, -12.1193, 71.1767, 180.802, -12.9847, 105.271, 184.526, -12.1193, 108.994, 211.184, -12.9847, 68.2508, 215.562, -12.1193, 71.1767, 187.922, -10.4389, 112.39, 219.556, -10.4389, 73.8449, 184.526, -12.1193, 108.994, 187.922, -10.4389, 112.39, 215.562, -12.1193, 71.1767, 219.556, -10.4389, 73.8449, 190.793, -8.0411, 115.261, 222.931, -8.0411, 76.1005, 187.922, -10.4389, 112.39, 190.793, -8.0411, 115.261, 219.556, -10.4389, 73.8449, 222.931, -8.0411, 76.1005, 192.972, -5.0652, 117.44, 225.493, -5.0652, 77.8123, 190.793, -8.0411, 115.261, 192.972, -5.0652, 117.44, 222.931, -8.0411, 76.1005, 225.493, -5.0652, 77.8123, 194.332, -1.6842, 118.8, 227.092, -1.6842, 78.8808, 192.972, -5.0652, 117.44, 194.332, -1.6842, 118.8, 225.493, -5.0652, 77.8123, 227.092, -1.6842, 78.8808, 194.794, 1.9054, 119.262, 227.636, 1.9054, 79.2441, 194.332, -1.6842, 118.8, 194.794, 1.9054, 119.262, 227.092, -1.6842, 78.8808, 194.794, 1.9054, 119.262, 154.413, 5.495, 151.561, 194.332, 5.495, 118.8, 154.776, 1.9054, 152.104, 154.413, 5.495, 151.561, 194.794, 1.9054, 119.262, 194.332, 5.495, 118.8, 153.344, 8.876, 149.961, 192.972, 8.876, 117.44, 154.413, 5.495, 151.561, 153.344, 8.876, 149.961, 194.332, 5.495, 118.8, 192.972, 8.876, 117.44, 151.632, 11.8519, 147.399, 190.793, 11.8519, 115.261, 153.344, 8.876, 149.961, 151.632, 11.8519, 147.399, 192.972, 8.876, 117.44, 190.793, 11.8519, 115.261, 149.377, 14.2498, 144.024, 187.922, 14.2498, 112.39, 151.632, 11.8519, 147.399, 149.377, 14.2498, 144.024, 190.793, 11.8519, 115.261, 187.922, 14.2498, 112.39, 146.709, 15.9302, 140.031, 184.526, 15.9302, 108.994, 149.377, 14.2498, 144.024, 146.709, 15.9302, 140.031, 187.922, 14.2498, 112.39, 184.526, 15.9302, 108.994, 143.783, 16.7956, 135.652, 180.802, 16.7956, 105.271, 146.709, 15.9302, 140.031, 143.783, 16.7956, 135.652, 184.526, 15.9302, 108.994, 180.802, 16.7956, 105.271, 140.769, 16.7956, 131.142, 176.967, 16.7956, 101.435, 143.783, 16.7956, 135.652, 140.769, 16.7956, 131.142, 180.802, 16.7956, 105.271, 176.967, 16.7956, 101.435, 137.843, 15.9302, 126.763, 173.243, 15.9302, 97.7113, 140.769, 16.7956, 131.142, 137.843, 15.9302, 126.763, 176.967, 16.7956, 101.435, 173.243, 15.9302, 97.7113, 135.175, 14.2498, 122.77, 169.847, 14.2498, 94.3153, 137.843, 15.9302, 126.763, 135.175, 14.2498, 122.77, 173.243, 15.9302, 97.7113, 169.847, 14.2498, 94.3153, 132.92, 11.8519, 119.394, 166.976, 11.8519, 91.4445, 135.175, 14.2498, 122.77, 132.92, 11.8519, 119.394, 169.847, 14.2498, 94.3153, 166.976, 11.8519, 91.4445, 131.208, 8.876, 116.832, 164.798, 8.876, 89.2658, 132.92, 11.8519, 119.394, 131.208, 8.876, 116.832, 166.976, 11.8519, 91.4445, 164.798, 8.876, 89.2658, 130.139, 5.495, 115.233, 163.438, 5.495, 87.9057, 131.208, 8.876, 116.832, 130.139, 5.495, 115.233, 164.798, 8.876, 89.2658, 163.438, 5.495, 87.9057, 129.776, 1.9054, 114.689, 162.975, 1.9054, 87.4435, 130.139, 5.495, 115.233, 129.776, 1.9054, 114.689, 163.438, 5.495, 87.9057, 162.975, 1.9054, 87.4435, 130.139, -1.6842, 115.233, 163.438, -1.6842, 87.9057, 129.776, 1.9054, 114.689, 130.139, -1.6842, 115.233, 162.975, 1.9054, 87.4435, 163.438, -1.6842, 87.9057, 131.208, -5.0652, 116.832, 164.798, -5.0652, 89.2658, 130.139, -1.6842, 115.233, 131.208, -5.0652, 116.832, 163.438, -1.6842, 87.9057, 164.798, -5.0652, 89.2658, 132.92, -8.0411, 119.394, 166.976, -8.0411, 91.4445, 131.208, -5.0652, 116.832, 132.92, -8.0411, 119.394, 164.798, -5.0652, 89.2658, 166.976, -8.0411, 91.4445, 135.175, -10.4389, 122.77, 169.847, -10.4389, 94.3153, 132.92, -8.0411, 119.394, 135.175, -10.4389, 122.77, 166.976, -8.0411, 91.4445, 169.847, -10.4389, 94.3153, 137.843, -12.1193, 126.763, 173.243, -12.1193, 97.7113, 135.175, -10.4389, 122.77, 137.843, -12.1193, 126.763, 169.847, -10.4389, 94.3153, 173.243, -12.1193, 97.7113, 140.769, -12.9847, 131.142, 176.967, -12.9847, 101.435, 137.843, -12.1193, 126.763, 140.769, -12.9847, 131.142, 173.243, -12.1193, 97.7113, 176.967, -12.9847, 101.435, 143.783, -12.9847, 135.652, 180.802, -12.9847, 105.271, 140.769, -12.9847, 131.142, 143.783, -12.9847, 135.652, 176.967, -12.9847, 101.435, 180.802, -12.9847, 105.271, 146.709, -12.1193, 140.031, 184.526, -12.1193, 108.994, 143.783, -12.9847, 135.652, 146.709, -12.1193, 140.031, 180.802, -12.9847, 105.271, 184.526, -12.1193, 108.994, 149.377, -10.4389, 144.024, 187.922, -10.4389, 112.39, 146.709, -12.1193, 140.031, 149.377, -10.4389, 144.024, 184.526, -12.1193, 108.994, 187.922, -10.4389, 112.39, 151.632, -8.0411, 147.399, 190.793, -8.0411, 115.261, 149.377, -10.4389, 144.024, 151.632, -8.0411, 147.399, 187.922, -10.4389, 112.39, 190.793, -8.0411, 115.261, 153.344, -5.0652, 149.961, 192.972, -5.0652, 117.44, 151.632, -8.0411, 147.399, 153.344, -5.0652, 149.961, 190.793, -8.0411, 115.261, 192.972, -5.0652, 117.44, 154.413, -1.6842, 151.561, 194.332, -1.6842, 118.8, 153.344, -5.0652, 149.961, 154.413, -1.6842, 151.561, 192.972, -5.0652, 117.44, 194.332, -1.6842, 118.8, 154.776, 1.9054, 152.104, 194.794, 1.9054, 119.262, 154.413, -1.6842, 151.561, 154.776, 1.9054, 152.104, 194.332, -1.6842, 118.8, 154.776, 1.9054, 152.104, 108.869, 5.495, 175.904, 154.413, 5.495, 151.561, 109.12, 1.9054, 176.508, 108.869, 5.495, 175.904, 154.776, 1.9054, 152.104, 154.413, 5.495, 151.561, 108.133, 8.876, 174.127, 153.344, 8.876, 149.961, 108.869, 5.495, 175.904, 108.133, 8.876, 174.127, 154.413, 5.495, 151.561, 153.344, 8.876, 149.961, 106.954, 11.8519, 171.281, 151.632, 11.8519, 147.399, 108.133, 8.876, 174.127, 106.954, 11.8519, 171.281, 153.344, 8.876, 149.961, 151.632, 11.8519, 147.399, 105.401, 14.2498, 167.53, 149.377, 14.2498, 144.024, 106.954, 11.8519, 171.281, 105.401, 14.2498, 167.53, 151.632, 11.8519, 147.399, 149.377, 14.2498, 144.024, 103.563, 15.9302, 163.092, 146.709, 15.9302, 140.031, 105.401, 14.2498, 167.53, 103.563, 15.9302, 163.092, 149.377, 14.2498, 144.024, 146.709, 15.9302, 140.031, 101.547, 16.7956, 158.227, 143.783, 16.7956, 135.652, 103.563, 15.9302, 163.092, 101.547, 16.7956, 158.227, 146.709, 15.9302, 140.031, 143.783, 16.7956, 135.652, 99.4717, 16.7956, 153.216, 140.769, 16.7956, 131.142, 101.547, 16.7956, 158.227, 99.4717, 16.7956, 153.216, 143.783, 16.7956, 135.652, 140.769, 16.7956, 131.142, 97.4563, 15.9302, 148.35, 137.843, 15.9302, 126.763, 99.4717, 16.7956, 153.216, 97.4563, 15.9302, 148.35, 140.769, 16.7956, 131.142, 137.843, 15.9302, 126.763, 95.6184, 14.2498, 143.913, 135.175, 14.2498, 122.77, 97.4563, 15.9302, 148.35, 95.6184, 14.2498, 143.913, 137.843, 15.9302, 126.763, 135.175, 14.2498, 122.77, 94.0647, 11.8519, 140.162, 132.92, 11.8519, 119.394, 95.6184, 14.2498, 143.913, 94.0647, 11.8519, 140.162, 135.175, 14.2498, 122.77, 132.92, 11.8519, 119.394, 92.8856, 8.876, 137.316, 131.208, 8.876, 116.832, 94.0647, 11.8519, 140.162, 92.8856, 8.876, 137.316, 132.92, 11.8519, 119.394, 131.208, 8.876, 116.832, 92.1496, 5.495, 135.539, 130.139, 5.495, 115.233, 92.8856, 8.876, 137.316, 92.1496, 5.495, 135.539, 131.208, 8.876, 116.832, 130.139, 5.495, 115.233, 91.8994, 1.9054, 134.935, 129.776, 1.9054, 114.689, 92.1496, 5.495, 135.539, 91.8994, 1.9054, 134.935, 130.139, 5.495, 115.233, 129.776, 1.9054, 114.689, 92.1496, -1.6842, 135.539, 130.139, -1.6842, 115.233, 91.8994, 1.9054, 134.935, 92.1496, -1.6842, 135.539, 129.776, 1.9054, 114.689, 130.139, -1.6842, 115.233, 92.8856, -5.0652, 137.316, 131.208, -5.0652, 116.832, 92.1496, -1.6842, 135.539, 92.8856, -5.0652, 137.316, 130.139, -1.6842, 115.233, 131.208, -5.0652, 116.832, 94.0647, -8.0411, 140.162, 132.92, -8.0411, 119.394, 92.8856, -5.0652, 137.316, 94.0647, -8.0411, 140.162, 131.208, -5.0652, 116.832, 132.92, -8.0411, 119.394, 95.6184, -10.4389, 143.913, 135.175, -10.4389, 122.77, 94.0647, -8.0411, 140.162, 95.6184, -10.4389, 143.913, 132.92, -8.0411, 119.394, 135.175, -10.4389, 122.77, 97.4563, -12.1193, 148.35, 137.843, -12.1193, 126.763, 95.6184, -10.4389, 143.913, 97.4563, -12.1193, 148.35, 135.175, -10.4389, 122.77, 137.843, -12.1193, 126.763, 99.4717, -12.9847, 153.216, 140.769, -12.9847, 131.142, 97.4563, -12.1193, 148.35, 99.4717, -12.9847, 153.216, 137.843, -12.1193, 126.763, 140.769, -12.9847, 131.142, 101.547, -12.9847, 158.227, 143.783, -12.9847, 135.652, 99.4717, -12.9847, 153.216, 101.547, -12.9847, 158.227, 140.769, -12.9847, 131.142, 143.783, -12.9847, 135.652, 103.563, -12.1193, 163.092, 146.709, -12.1193, 140.031, 101.547, -12.9847, 158.227, 103.563, -12.1193, 163.092, 143.783, -12.9847, 135.652, 146.709, -12.1193, 140.031, 105.401, -10.4389, 167.53, 149.377, -10.4389, 144.024, 103.563, -12.1193, 163.092, 105.401, -10.4389, 167.53, 146.709, -12.1193, 140.031, 149.377, -10.4389, 144.024, 106.954, -8.0411, 171.281, 151.632, -8.0411, 147.399, 105.401, -10.4389, 167.53, 106.954, -8.0411, 171.281, 149.377, -10.4389, 144.024, 151.632, -8.0411, 147.399, 108.133, -5.0652, 174.127, 153.344, -5.0652, 149.961, 106.954, -8.0411, 171.281, 108.133, -5.0652, 174.127, 151.632, -8.0411, 147.399, 153.344, -5.0652, 149.961, 108.869, -1.6842, 175.904, 154.413, -1.6842, 151.561, 108.133, -5.0652, 174.127, 108.869, -1.6842, 175.904, 153.344, -5.0652, 149.961, 154.413, -1.6842, 151.561, 109.12, 1.9054, 176.508, 154.776, 1.9054, 152.104, 108.869, -1.6842, 175.904, 109.12, 1.9054, 176.508, 154.413, -1.6842, 151.561, 109.12, 1.9054, 176.508, 59.452, 5.495, 190.895, 108.869, 5.495, 175.904, 59.5795, 1.9054, 191.536, 59.452, 5.495, 190.895, 109.12, 1.9054, 176.508, 108.869, 5.495, 175.904, 59.0767, 8.876, 189.008, 108.133, 8.876, 174.127, 59.452, 5.495, 190.895, 59.0767, 8.876, 189.008, 108.869, 5.495, 175.904, 108.133, 8.876, 174.127, 58.4756, 11.8519, 185.986, 106.954, 11.8519, 171.281, 59.0767, 8.876, 189.008, 58.4756, 11.8519, 185.986, 108.133, 8.876, 174.127, 106.954, 11.8519, 171.281, 57.6836, 14.2498, 182.004, 105.401, 14.2498, 167.53, 58.4756, 11.8519, 185.986, 57.6836, 14.2498, 182.004, 106.954, 11.8519, 171.281, 105.401, 14.2498, 167.53, 56.7466, 15.9302, 177.294, 103.563, 15.9302, 163.092, 57.6836, 14.2498, 182.004, 56.7466, 15.9302, 177.294, 105.401, 14.2498, 167.53, 103.563, 15.9302, 163.092, 55.7192, 16.7956, 172.129, 101.547, 16.7956, 158.227, 56.7466, 15.9302, 177.294, 55.7192, 16.7956, 172.129, 103.563, 15.9302, 163.092, 101.547, 16.7956, 158.227, 54.6611, 16.7956, 166.809, 99.4717, 16.7956, 153.216, 55.7192, 16.7956, 172.129, 54.6611, 16.7956, 166.809, 101.547, 16.7956, 158.227, 99.4717, 16.7956, 153.216, 53.6336, 15.9302, 161.644, 97.4563, 15.9302, 148.35, 54.6611, 16.7956, 166.809, 53.6336, 15.9302, 161.644, 99.4717, 16.7956, 153.216, 97.4563, 15.9302, 148.35, 52.6967, 14.2498, 156.934, 95.6184, 14.2498, 143.913, 53.6336, 15.9302, 161.644, 52.6967, 14.2498, 156.934, 97.4563, 15.9302, 148.35, 95.6184, 14.2498, 143.913, 51.9046, 11.8519, 152.952, 94.0647, 11.8519, 140.162, 52.6967, 14.2498, 156.934, 51.9046, 11.8519, 152.952, 95.6184, 14.2498, 143.913, 94.0647, 11.8519, 140.162, 51.3035, 8.876, 149.93, 92.8856, 8.876, 137.316, 51.9046, 11.8519, 152.952, 51.3035, 8.876, 149.93, 94.0647, 11.8519, 140.162, 92.8856, 8.876, 137.316, 50.9283, 5.495, 148.043, 92.1496, 5.495, 135.539, 51.3035, 8.876, 149.93, 50.9283, 5.495, 148.043, 92.8856, 8.876, 137.316, 92.1496, 5.495, 135.539, 50.8007, 1.9054, 147.402, 91.8994, 1.9054, 134.935, 50.9283, 5.495, 148.043, 50.8007, 1.9054, 147.402, 92.1496, 5.495, 135.539, 91.8994, 1.9054, 134.935, 50.9283, -1.6842, 148.043, 92.1496, -1.6842, 135.539, 50.8007, 1.9054, 147.402, 50.9283, -1.6842, 148.043, 91.8994, 1.9054, 134.935, 92.1496, -1.6842, 135.539, 51.3035, -5.0652, 149.93, 92.8856, -5.0652, 137.316, 50.9283, -1.6842, 148.043, 51.3035, -5.0652, 149.93, 92.1496, -1.6842, 135.539, 92.8856, -5.0652, 137.316, 51.9046, -8.0411, 152.952, 94.0647, -8.0411, 140.162, 51.3035, -5.0652, 149.93, 51.9046, -8.0411, 152.952, 92.8856, -5.0652, 137.316, 94.0647, -8.0411, 140.162, 52.6967, -10.4389, 156.934, 95.6184, -10.4389, 143.913, 51.9046, -8.0411, 152.952, 52.6967, -10.4389, 156.934, 94.0647, -8.0411, 140.162, 95.6184, -10.4389, 143.913, 53.6336, -12.1193, 161.644, 97.4563, -12.1193, 148.35, 52.6967, -10.4389, 156.934, 53.6336, -12.1193, 161.644, 95.6184, -10.4389, 143.913, 97.4563, -12.1193, 148.35, 54.6611, -12.9847, 166.809, 99.4717, -12.9847, 153.216, 53.6336, -12.1193, 161.644, 54.6611, -12.9847, 166.809, 97.4563, -12.1193, 148.35, 99.4717, -12.9847, 153.216, 55.7192, -12.9847, 172.129, 101.547, -12.9847, 158.227, 54.6611, -12.9847, 166.809, 55.7192, -12.9847, 172.129, 99.4717, -12.9847, 153.216, 101.547, -12.9847, 158.227, 56.7466, -12.1193, 177.294, 103.563, -12.1193, 163.092, 55.7192, -12.9847, 172.129, 56.7466, -12.1193, 177.294, 101.547, -12.9847, 158.227, 103.563, -12.1193, 163.092, 57.6836, -10.4389, 182.004, 105.401, -10.4389, 167.53, 56.7466, -12.1193, 177.294, 57.6836, -10.4389, 182.004, 103.563, -12.1193, 163.092, 105.401, -10.4389, 167.53, 58.4756, -8.0411, 185.986, 106.954, -8.0411, 171.281, 57.6836, -10.4389, 182.004, 58.4756, -8.0411, 185.986, 105.401, -10.4389, 167.53, 106.954, -8.0411, 171.281, 59.0767, -5.0652, 189.008, 108.133, -5.0652, 174.127, 58.4756, -8.0411, 185.986, 59.0767, -5.0652, 189.008, 106.954, -8.0411, 171.281, 108.133, -5.0652, 174.127, 59.452, -1.6842, 190.895, 108.869, -1.6842, 175.904, 59.0767, -5.0652, 189.008, 59.452, -1.6842, 190.895, 108.133, -5.0652, 174.127, 108.869, -1.6842, 175.904, 59.5795, 1.9054, 191.536, 109.12, 1.9054, 176.508, 59.452, -1.6842, 190.895, 59.5795, 1.9054, 191.536, 108.869, -1.6842, 175.904, 59.5795, 1.9054, 191.536, 8.0596, 5.495, 195.956, 59.452, 5.495, 190.895, 8.0596, 1.9054, 196.61, 8.0596, 5.495, 195.956, 59.5795, 1.9054, 191.536, 59.452, 5.495, 190.895, 8.0596, 8.876, 194.033, 59.0767, 8.876, 189.008, 8.0596, 5.495, 195.956, 8.0596, 8.876, 194.033, 59.452, 5.495, 190.895, 59.0767, 8.876, 189.008, 8.0596, 11.8519, 190.952, 58.4756, 11.8519, 185.986, 8.0596, 8.876, 194.033, 8.0596, 11.8519, 190.952, 59.0767, 8.876, 189.008, 58.4756, 11.8519, 185.986, 8.0596, 14.2498, 186.892, 57.6836, 14.2498, 182.004, 8.0596, 11.8519, 190.952, 8.0596, 14.2498, 186.892, 58.4756, 11.8519, 185.986, 57.6836, 14.2498, 182.004, 8.0596, 15.9302, 182.089, 56.7466, 15.9302, 177.294, 8.0596, 14.2498, 186.892, 8.0596, 15.9302, 182.089, 57.6836, 14.2498, 182.004, 56.7466, 15.9302, 177.294, 8.0596, 16.7956, 176.823, 55.7192, 16.7956, 172.129, 8.0596, 15.9302, 182.089, 8.0596, 16.7956, 176.823, 56.7466, 15.9302, 177.294, 55.7192, 16.7956, 172.129, 8.0596, 16.7956, 171.399, 54.6611, 16.7956, 166.809, 8.0596, 16.7956, 176.823, 8.0596, 16.7956, 171.399, 55.7192, 16.7956, 172.129, 54.6611, 16.7956, 166.809, 8.0596, 15.9302, 166.133, 53.6336, 15.9302, 161.644, 8.0596, 16.7956, 171.399, 8.0596, 15.9302, 166.133, 54.6611, 16.7956, 166.809, 53.6336, 15.9302, 161.644, 8.0596, 14.2498, 161.33, 52.6967, 14.2498, 156.934, 8.0596, 15.9302, 166.133, 8.0596, 14.2498, 161.33, 53.6336, 15.9302, 161.644, 52.6967, 14.2498, 156.934, 8.0596, 11.8519, 157.27, 51.9046, 11.8519, 152.952, 8.0596, 14.2498, 161.33, 8.0596, 11.8519, 157.27, 52.6967, 14.2498, 156.934, 51.9046, 11.8519, 152.952, 8.0596, 8.876, 154.189, 51.3035, 8.876, 149.93, 8.0596, 11.8519, 157.27, 8.0596, 8.876, 154.189, 51.9046, 11.8519, 152.952, 51.3035, 8.876, 149.93, 8.0596, 5.495, 152.266, 50.9283, 5.495, 148.043, 8.0596, 8.876, 154.189, 8.0596, 5.495, 152.266, 51.3035, 8.876, 149.93, 50.9283, 5.495, 148.043, 8.0596, 1.9054, 151.612, 50.8007, 1.9054, 147.402, 8.0596, 5.495, 152.266, 8.0596, 1.9054, 151.612, 50.9283, 5.495, 148.043, 50.8007, 1.9054, 147.402, 8.0596, -1.6842, 152.266, 50.9283, -1.6842, 148.043, 8.0596, 1.9054, 151.612, 8.0596, -1.6842, 152.266, 50.8007, 1.9054, 147.402, 50.9283, -1.6842, 148.043, 8.0596, -5.0652, 154.189, 51.3035, -5.0652, 149.93, 8.0596, -1.6842, 152.266, 8.0596, -5.0652, 154.189, 50.9283, -1.6842, 148.043, 51.3035, -5.0652, 149.93, 8.0596, -8.0411, 157.27, 51.9046, -8.0411, 152.952, 8.0596, -5.0652, 154.189, 8.0596, -8.0411, 157.27, 51.3035, -5.0652, 149.93, 51.9046, -8.0411, 152.952, 8.0596, -10.4389, 161.33, 52.6967, -10.4389, 156.934, 8.0596, -8.0411, 157.27, 8.0596, -10.4389, 161.33, 51.9046, -8.0411, 152.952, 52.6967, -10.4389, 156.934, 8.0596, -12.1193, 166.133, 53.6336, -12.1193, 161.644, 8.0596, -10.4389, 161.33, 8.0596, -12.1193, 166.133, 52.6967, -10.4389, 156.934, 53.6336, -12.1193, 161.644, 8.0596, -12.9847, 171.399, 54.6611, -12.9847, 166.809, 8.0596, -12.1193, 166.133, 8.0596, -12.9847, 171.399, 53.6336, -12.1193, 161.644, 54.6611, -12.9847, 166.809, 8.0596, -12.9847, 176.823, 55.7192, -12.9847, 172.129, 8.0596, -12.9847, 171.399, 8.0596, -12.9847, 176.823, 54.6611, -12.9847, 166.809, 55.7192, -12.9847, 172.129, 8.0596, -12.1193, 182.089, 56.7466, -12.1193, 177.294, 8.0596, -12.9847, 176.823, 8.0596, -12.1193, 182.089, 55.7192, -12.9847, 172.129, 56.7466, -12.1193, 177.294, 8.0596, -10.4389, 186.892, 57.6836, -10.4389, 182.004, 8.0596, -12.1193, 182.089, 8.0596, -10.4389, 186.892, 56.7466, -12.1193, 177.294, 57.6836, -10.4389, 182.004, 8.0596, -8.0411, 190.952, 58.4756, -8.0411, 185.986, 8.0596, -10.4389, 186.892, 8.0596, -8.0411, 190.952, 57.6836, -10.4389, 182.004, 58.4756, -8.0411, 185.986, 8.0596, -5.0652, 194.033, 59.0767, -5.0652, 189.008, 8.0596, -8.0411, 190.952, 8.0596, -5.0652, 194.033, 58.4756, -8.0411, 185.986, 59.0767, -5.0652, 189.008, 8.0596, -1.6842, 195.956, 59.452, -1.6842, 190.895, 8.0596, -5.0652, 194.033, 8.0596, -1.6842, 195.956, 59.0767, -5.0652, 189.008, 59.452, -1.6842, 190.895, 8.0596, 1.9054, 196.61, 59.5795, 1.9054, 191.536, 8.0596, -1.6842, 195.956, 8.0596, 1.9054, 196.61, 59.452, -1.6842, 190.895, 8.0596, 1.9054, 196.61, -43.3328, 5.495, 190.895, 8.0596, 5.495, 195.956, -43.4604, 1.9054, 191.536, -43.3328, 5.495, 190.895, 8.0596, 1.9054, 196.61, 8.0596, 5.495, 195.956, -42.9576, 8.876, 189.008, 8.0596, 8.876, 194.033, -43.3328, 5.495, 190.895, -42.9576, 8.876, 189.008, 8.0596, 5.495, 195.956, 8.0596, 8.876, 194.033, -42.3565, 11.8519, 185.986, 8.0596, 11.8519, 190.952, -42.9576, 8.876, 189.008, -42.3565, 11.8519, 185.986, 8.0596, 8.876, 194.033, 8.0596, 11.8519, 190.952, -41.5644, 14.2498, 182.004, 8.0596, 14.2498, 186.892, -42.3565, 11.8519, 185.986, -41.5644, 14.2498, 182.004, 8.0596, 11.8519, 190.952, 8.0596, 14.2498, 186.892, -40.6275, 15.9302, 177.294, 8.0596, 15.9302, 182.089, -41.5644, 14.2498, 182.004, -40.6275, 15.9302, 177.294, 8.0596, 14.2498, 186.892, 8.0596, 15.9302, 182.089, -39.6001, 16.7956, 172.129, 8.0596, 16.7956, 176.823, -40.6275, 15.9302, 177.294, -39.6001, 16.7956, 172.129, 8.0596, 15.9302, 182.089, 8.0596, 16.7956, 176.823, -38.5419, 16.7956, 166.809, 8.0596, 16.7956, 171.399, -39.6001, 16.7956, 172.129, -38.5419, 16.7956, 166.809, 8.0596, 16.7956, 176.823, 8.0596, 16.7956, 171.399, -37.5145, 15.9302, 161.644, 8.0596, 15.9302, 166.133, -38.5419, 16.7956, 166.809, -37.5145, 15.9302, 161.644, 8.0596, 16.7956, 171.399, 8.0596, 15.9302, 166.133, -36.5775, 14.2498, 156.934, 8.0596, 14.2498, 161.33, -37.5145, 15.9302, 161.644, -36.5775, 14.2498, 156.934, 8.0596, 15.9302, 166.133, 8.0596, 14.2498, 161.33, -35.7855, 11.8519, 152.952, 8.0596, 11.8519, 157.27, -36.5775, 14.2498, 156.934, -35.7855, 11.8519, 152.952, 8.0596, 14.2498, 161.33, 8.0596, 11.8519, 157.27, -35.1844, 8.876, 149.93, 8.0596, 8.876, 154.189, -35.7855, 11.8519, 152.952, -35.1844, 8.876, 149.93, 8.0596, 11.8519, 157.27, 8.0596, 8.876, 154.189, -34.8091, 5.495, 148.043, 8.0596, 5.495, 152.266, -35.1844, 8.876, 149.93, -34.8091, 5.495, 148.043, 8.0596, 8.876, 154.189, 8.0596, 5.495, 152.266, -34.6816, 1.9054, 147.402, 8.0596, 1.9054, 151.612, -34.8091, 5.495, 148.043, -34.6816, 1.9054, 147.402, 8.0596, 5.495, 152.266, 8.0596, 1.9054, 151.612, -34.8091, -1.6842, 148.043, 8.0596, -1.6842, 152.266, -34.6816, 1.9054, 147.402, -34.8091, -1.6842, 148.043, 8.0596, 1.9054, 151.612, 8.0596, -1.6842, 152.266, -35.1844, -5.0652, 149.93, 8.0596, -5.0652, 154.189, -34.8091, -1.6842, 148.043, -35.1844, -5.0652, 149.93, 8.0596, -1.6842, 152.266, 8.0596, -5.0652, 154.189, -35.7855, -8.0411, 152.952, 8.0596, -8.0411, 157.27, -35.1844, -5.0652, 149.93, -35.7855, -8.0411, 152.952, 8.0596, -5.0652, 154.189, 8.0596, -8.0411, 157.27, -36.5775, -10.4389, 156.934, 8.0596, -10.4389, 161.33, -35.7855, -8.0411, 152.952, -36.5775, -10.4389, 156.934, 8.0596, -8.0411, 157.27, 8.0596, -10.4389, 161.33, -37.5145, -12.1193, 161.644, 8.0596, -12.1193, 166.133, -36.5775, -10.4389, 156.934, -37.5145, -12.1193, 161.644, 8.0596, -10.4389, 161.33, 8.0596, -12.1193, 166.133, -38.5419, -12.9847, 166.809, 8.0596, -12.9847, 171.399, -37.5145, -12.1193, 161.644, -38.5419, -12.9847, 166.809, 8.0596, -12.1193, 166.133, 8.0596, -12.9847, 171.399, -39.6001, -12.9847, 172.129, 8.0596, -12.9847, 176.823, -38.5419, -12.9847, 166.809, -39.6001, -12.9847, 172.129, 8.0596, -12.9847, 171.399, 8.0596, -12.9847, 176.823, -40.6275, -12.1193, 177.294, 8.0596, -12.1193, 182.089, -39.6001, -12.9847, 172.129, -40.6275, -12.1193, 177.294, 8.0596, -12.9847, 176.823, 8.0596, -12.1193, 182.089, -41.5644, -10.4389, 182.004, 8.0596, -10.4389, 186.892, -40.6275, -12.1193, 177.294, -41.5644, -10.4389, 182.004, 8.0596, -12.1193, 182.089, 8.0596, -10.4389, 186.892, -42.3565, -8.0411, 185.986, 8.0596, -8.0411, 190.952, -41.5644, -10.4389, 182.004, -42.3565, -8.0411, 185.986, 8.0596, -10.4389, 186.892, 8.0596, -8.0411, 190.952, -42.9576, -5.0652, 189.008, 8.0596, -5.0652, 194.033, -42.3565, -8.0411, 185.986, -42.9576, -5.0652, 189.008, 8.0596, -8.0411, 190.952, 8.0596, -5.0652, 194.033, -43.3328, -1.6842, 190.895, 8.0596, -1.6842, 195.956, -42.9576, -5.0652, 189.008, -43.3328, -1.6842, 190.895, 8.0596, -5.0652, 194.033, 8.0596, -1.6842, 195.956, -43.4604, 1.9054, 191.536, 8.0596, 1.9054, 196.61, -43.3328, -1.6842, 190.895, -43.4604, 1.9054, 191.536, 8.0596, -1.6842, 195.956, -43.4604, 1.9054, 191.536, -92.7502, 5.495, 175.904, -43.3328, 5.495, 190.895, -93.0004, 1.9054, 176.508, -92.7502, 5.495, 175.904, -43.4604, 1.9054, 191.536, -43.3328, 5.495, 190.895, -92.0142, 8.876, 174.127, -42.9576, 8.876, 189.008, -92.7502, 5.495, 175.904, -92.0142, 8.876, 174.127, -43.3328, 5.495, 190.895, -42.9576, 8.876, 189.008, -90.8351, 11.8519, 171.281, -42.3565, 11.8519, 185.986, -92.0142, 8.876, 174.127, -90.8351, 11.8519, 171.281, -42.9576, 8.876, 189.008, -42.3565, 11.8519, 185.986, -89.2814, 14.2498, 167.53, -41.5644, 14.2498, 182.004, -90.8351, 11.8519, 171.281, -89.2814, 14.2498, 167.53, -42.3565, 11.8519, 185.986, -41.5644, 14.2498, 182.004, -87.4435, 15.9302, 163.092, -40.6275, 15.9302, 177.294, -89.2814, 14.2498, 167.53, -87.4435, 15.9302, 163.092, -41.5644, 14.2498, 182.004, -40.6275, 15.9302, 177.294, -85.4282, 16.7956, 158.227, -39.6001, 16.7956, 172.129, -87.4435, 15.9302, 163.092, -85.4282, 16.7956, 158.227, -40.6275, 15.9302, 177.294, -39.6001, 16.7956, 172.129, -83.3525, 16.7956, 153.216, -38.5419, 16.7956, 166.809, -85.4282, 16.7956, 158.227, -83.3525, 16.7956, 153.216, -39.6001, 16.7956, 172.129, -38.5419, 16.7956, 166.809, -81.3372, 15.9302, 148.35, -37.5145, 15.9302, 161.644, -83.3525, 16.7956, 153.216, -81.3372, 15.9302, 148.35, -38.5419, 16.7956, 166.809, -37.5145, 15.9302, 161.644, -79.4992, 14.2498, 143.913, -36.5775, 14.2498, 156.934, -81.3372, 15.9302, 148.35, -79.4992, 14.2498, 143.913, -37.5145, 15.9302, 161.644, -36.5775, 14.2498, 156.934, -77.9456, 11.8519, 140.162, -35.7855, 11.8519, 152.952, -79.4992, 14.2498, 143.913, -77.9456, 11.8519, 140.162, -36.5775, 14.2498, 156.934, -35.7855, 11.8519, 152.952, -76.7665, 8.876, 137.316, -35.1844, 8.876, 149.93, -77.9456, 11.8519, 140.162, -76.7665, 8.876, 137.316, -35.7855, 11.8519, 152.952, -35.1844, 8.876, 149.93, -76.0304, 5.495, 135.539, -34.8091, 5.495, 148.043, -76.7665, 8.876, 137.316, -76.0304, 5.495, 135.539, -35.1844, 8.876, 149.93, -34.8091, 5.495, 148.043, -75.7802, 1.9054, 134.935, -34.6816, 1.9054, 147.402, -76.0304, 5.495, 135.539, -75.7802, 1.9054, 134.935, -34.8091, 5.495, 148.043, -34.6816, 1.9054, 147.402, -76.0304, -1.6842, 135.539, -34.8091, -1.6842, 148.043, -75.7802, 1.9054, 134.935, -76.0304, -1.6842, 135.539, -34.6816, 1.9054, 147.402, -34.8091, -1.6842, 148.043, -76.7665, -5.0652, 137.316, -35.1844, -5.0652, 149.93, -76.0304, -1.6842, 135.539, -76.7665, -5.0652, 137.316, -34.8091, -1.6842, 148.043, -35.1844, -5.0652, 149.93, -77.9456, -8.0411, 140.162, -35.7855, -8.0411, 152.952, -76.7665, -5.0652, 137.316, -77.9456, -8.0411, 140.162, -35.1844, -5.0652, 149.93, -35.7855, -8.0411, 152.952, -79.4992, -10.4389, 143.913, -36.5775, -10.4389, 156.934, -77.9456, -8.0411, 140.162, -79.4992, -10.4389, 143.913, -35.7855, -8.0411, 152.952, -36.5775, -10.4389, 156.934, -81.3372, -12.1193, 148.35, -37.5145, -12.1193, 161.644, -79.4992, -10.4389, 143.913, -81.3372, -12.1193, 148.35, -36.5775, -10.4389, 156.934, -37.5145, -12.1193, 161.644, -83.3525, -12.9847, 153.216, -38.5419, -12.9847, 166.809, -81.3372, -12.1193, 148.35, -83.3525, -12.9847, 153.216, -37.5145, -12.1193, 161.644, -38.5419, -12.9847, 166.809, -85.4282, -12.9847, 158.227, -39.6001, -12.9847, 172.129, -83.3525, -12.9847, 153.216, -85.4282, -12.9847, 158.227, -38.5419, -12.9847, 166.809, -39.6001, -12.9847, 172.129, -87.4435, -12.1193, 163.092, -40.6275, -12.1193, 177.294, -85.4282, -12.9847, 158.227, -87.4435, -12.1193, 163.092, -39.6001, -12.9847, 172.129, -40.6275, -12.1193, 177.294, -89.2814, -10.4389, 167.53, -41.5644, -10.4389, 182.004, -87.4435, -12.1193, 163.092, -89.2814, -10.4389, 167.53, -40.6275, -12.1193, 177.294, -41.5644, -10.4389, 182.004, -90.8351, -8.0411, 171.281, -42.3565, -8.0411, 185.986, -89.2814, -10.4389, 167.53, -90.8351, -8.0411, 171.281, -41.5644, -10.4389, 182.004, -42.3565, -8.0411, 185.986, -92.0142, -5.0652, 174.127, -42.9576, -5.0652, 189.008, -90.8351, -8.0411, 171.281, -92.0142, -5.0652, 174.127, -42.3565, -8.0411, 185.986, -42.9576, -5.0652, 189.008, -92.7502, -1.6842, 175.904, -43.3328, -1.6842, 190.895, -92.0142, -5.0652, 174.127, -92.7502, -1.6842, 175.904, -42.9576, -5.0652, 189.008, -43.3328, -1.6842, 190.895, -93.0004, 1.9054, 176.508, -43.4604, 1.9054, 191.536, -92.7502, -1.6842, 175.904, -93.0004, 1.9054, 176.508, -43.3328, -1.6842, 190.895, -93.0004, 1.9054, 176.508, -138.294, 5.495, 151.561, -92.7502, 5.495, 175.904, -138.657, 1.9054, 152.104, -138.294, 5.495, 151.561, -93.0004, 1.9054, 176.508, -92.7502, 5.495, 175.904, -137.225, 8.876, 149.961, -92.0142, 8.876, 174.127, -138.294, 5.495, 151.561, -137.225, 8.876, 149.961, -92.7502, 5.495, 175.904, -92.0142, 8.876, 174.127, -135.513, 11.8519, 147.399, -90.8351, 11.8519, 171.281, -137.225, 8.876, 149.961, -135.513, 11.8519, 147.399, -92.0142, 8.876, 174.127, -90.8351, 11.8519, 171.281, -133.258, 14.2498, 144.024, -89.2814, 14.2498, 167.53, -135.513, 11.8519, 147.399, -133.258, 14.2498, 144.024, -90.8351, 11.8519, 171.281, -89.2814, 14.2498, 167.53, -130.589, 15.9302, 140.031, -87.4435, 15.9302, 163.092, -133.258, 14.2498, 144.024, -130.589, 15.9302, 140.031, -89.2814, 14.2498, 167.53, -87.4435, 15.9302, 163.092, -127.664, 16.7956, 135.652, -85.4282, 16.7956, 158.227, -130.589, 15.9302, 140.031, -127.664, 16.7956, 135.652, -87.4435, 15.9302, 163.092, -85.4282, 16.7956, 158.227, -124.65, 16.7956, 131.142, -83.3525, 16.7956, 153.216, -127.664, 16.7956, 135.652, -124.65, 16.7956, 131.142, -85.4282, 16.7956, 158.227, -83.3525, 16.7956, 153.216, -121.724, 15.9302, 126.763, -81.3372, 15.9302, 148.35, -124.65, 16.7956, 131.142, -121.724, 15.9302, 126.763, -83.3525, 16.7956, 153.216, -81.3372, 15.9302, 148.35, -119.056, 14.2498, 122.77, -79.4992, 14.2498, 143.913, -121.724, 15.9302, 126.763, -119.056, 14.2498, 122.77, -81.3372, 15.9302, 148.35, -79.4992, 14.2498, 143.913, -116.801, 11.8519, 119.394, -77.9456, 11.8519, 140.162, -119.056, 14.2498, 122.77, -116.801, 11.8519, 119.394, -79.4992, 14.2498, 143.913, -77.9456, 11.8519, 140.162, -115.089, 8.876, 116.832, -76.7665, 8.876, 137.316, -116.801, 11.8519, 119.394, -115.089, 8.876, 116.832, -77.9456, 11.8519, 140.162, -76.7665, 8.876, 137.316, -114.02, 5.495, 115.233, -76.0304, 5.495, 135.539, -115.089, 8.876, 116.832, -114.02, 5.495, 115.233, -76.7665, 8.876, 137.316, -76.0304, 5.495, 135.539, -113.657, 1.9054, 114.689, -75.7802, 1.9054, 134.935, -114.02, 5.495, 115.233, -113.657, 1.9054, 114.689, -76.0304, 5.495, 135.539, -75.7802, 1.9054, 134.935, -114.02, -1.6842, 115.233, -76.0304, -1.6842, 135.539, -113.657, 1.9054, 114.689, -114.02, -1.6842, 115.233, -75.7802, 1.9054, 134.935, -76.0304, -1.6842, 135.539, -115.089, -5.0652, 116.832, -76.7665, -5.0652, 137.316, -114.02, -1.6842, 115.233, -115.089, -5.0652, 116.832, -76.0304, -1.6842, 135.539, -76.7665, -5.0652, 137.316, -116.801, -8.0411, 119.394, -77.9456, -8.0411, 140.162, -115.089, -5.0652, 116.832, -116.801, -8.0411, 119.394, -76.7665, -5.0652, 137.316, -77.9456, -8.0411, 140.162, -119.056, -10.4389, 122.77, -79.4992, -10.4389, 143.913, -116.801, -8.0411, 119.394, -119.056, -10.4389, 122.77, -77.9456, -8.0411, 140.162, -79.4992, -10.4389, 143.913, -121.724, -12.1193, 126.763, -81.3372, -12.1193, 148.35, -119.056, -10.4389, 122.77, -121.724, -12.1193, 126.763, -79.4992, -10.4389, 143.913, -81.3372, -12.1193, 148.35, -124.65, -12.9847, 131.142, -83.3525, -12.9847, 153.216, -121.724, -12.1193, 126.763, -124.65, -12.9847, 131.142, -81.3372, -12.1193, 148.35, -83.3525, -12.9847, 153.216, -127.664, -12.9847, 135.652, -85.4282, -12.9847, 158.227, -124.65, -12.9847, 131.142, -127.664, -12.9847, 135.652, -83.3525, -12.9847, 153.216, -85.4282, -12.9847, 158.227, -130.589, -12.1193, 140.031, -87.4435, -12.1193, 163.092, -127.664, -12.9847, 135.652, -130.589, -12.1193, 140.031, -85.4282, -12.9847, 158.227, -87.4435, -12.1193, 163.092, -133.258, -10.4389, 144.024, -89.2814, -10.4389, 167.53, -130.589, -12.1193, 140.031, -133.258, -10.4389, 144.024, -87.4435, -12.1193, 163.092, -89.2814, -10.4389, 167.53, -135.513, -8.0411, 147.399, -90.8351, -8.0411, 171.281, -133.258, -10.4389, 144.024, -135.513, -8.0411, 147.399, -89.2814, -10.4389, 167.53, -90.8351, -8.0411, 171.281, -137.225, -5.0652, 149.961, -92.0142, -5.0652, 174.127, -135.513, -8.0411, 147.399, -137.225, -5.0652, 149.961, -90.8351, -8.0411, 171.281, -92.0142, -5.0652, 174.127, -138.294, -1.6842, 151.561, -92.7502, -1.6842, 175.904, -137.225, -5.0652, 149.961, -138.294, -1.6842, 151.561, -92.0142, -5.0652, 174.127, -92.7502, -1.6842, 175.904, -138.657, 1.9054, 152.104, -93.0004, 1.9054, 176.508, -138.294, -1.6842, 151.561, -138.657, 1.9054, 152.104, -92.7502, -1.6842, 175.904, -138.657, 1.9054, 152.104, -178.213, 5.495, 118.8, -138.294, 5.495, 151.561, -178.675, 1.9054, 119.262, -178.213, 5.495, 118.8, -138.657, 1.9054, 152.104, -138.294, 5.495, 151.561, -176.853, 8.876, 117.44, -137.225, 8.876, 149.961, -178.213, 5.495, 118.8, -176.853, 8.876, 117.44, -138.294, 5.495, 151.561, -137.225, 8.876, 149.961, -174.674, 11.8519, 115.261, -135.513, 11.8519, 147.399, -176.853, 8.876, 117.44, -174.674, 11.8519, 115.261, -137.225, 8.876, 149.961, -135.513, 11.8519, 147.399, -171.803, 14.2498, 112.39, -133.258, 14.2498, 144.024, -174.674, 11.8519, 115.261, -171.803, 14.2498, 112.39, -135.513, 11.8519, 147.399, -133.258, 14.2498, 144.024, -168.407, 15.9302, 108.994, -130.589, 15.9302, 140.031, -171.803, 14.2498, 112.39, -168.407, 15.9302, 108.994, -133.258, 14.2498, 144.024, -130.589, 15.9302, 140.031, -164.683, 16.7956, 105.271, -127.664, 16.7956, 135.652, -168.407, 15.9302, 108.994, -164.683, 16.7956, 105.271, -130.589, 15.9302, 140.031, -127.664, 16.7956, 135.652, -160.848, 16.7956, 101.435, -124.65, 16.7956, 131.142, -164.683, 16.7956, 105.271, -160.848, 16.7956, 101.435, -127.664, 16.7956, 135.652, -124.65, 16.7956, 131.142, -157.124, 15.9302, 97.7113, -121.724, 15.9302, 126.763, -160.848, 16.7956, 101.435, -157.124, 15.9302, 97.7113, -124.65, 16.7956, 131.142, -121.724, 15.9302, 126.763, -153.728, 14.2498, 94.3153, -119.056, 14.2498, 122.77, -157.124, 15.9302, 97.7113, -153.728, 14.2498, 94.3153, -121.724, 15.9302, 126.763, -119.056, 14.2498, 122.77, -150.857, 11.8519, 91.4445, -116.801, 11.8519, 119.394, -153.728, 14.2498, 94.3153, -150.857, 11.8519, 91.4445, -119.056, 14.2498, 122.77, -116.801, 11.8519, 119.394, -148.678, 8.876, 89.2658, -115.089, 8.876, 116.832, -150.857, 11.8519, 91.4445, -148.678, 8.876, 89.2658, -116.801, 11.8519, 119.394, -115.089, 8.876, 116.832, -147.318, 5.495, 87.9057, -114.02, 5.495, 115.233, -148.678, 8.876, 89.2658, -147.318, 5.495, 87.9057, -115.089, 8.876, 116.832, -114.02, 5.495, 115.233, -146.856, 1.9054, 87.4435, -113.657, 1.9054, 114.689, -147.318, 5.495, 87.9057, -146.856, 1.9054, 87.4435, -114.02, 5.495, 115.233, -113.657, 1.9054, 114.689, -147.318, -1.6842, 87.9057, -114.02, -1.6842, 115.233, -146.856, 1.9054, 87.4435, -147.318, -1.6842, 87.9057, -113.657, 1.9054, 114.689, -114.02, -1.6842, 115.233, -148.678, -5.0652, 89.2658, -115.089, -5.0652, 116.832, -147.318, -1.6842, 87.9057, -148.678, -5.0652, 89.2658, -114.02, -1.6842, 115.233, -115.089, -5.0652, 116.832, -150.857, -8.0411, 91.4445, -116.801, -8.0411, 119.394, -148.678, -5.0652, 89.2658, -150.857, -8.0411, 91.4445, -115.089, -5.0652, 116.832, -116.801, -8.0411, 119.394, -153.728, -10.4389, 94.3153, -119.056, -10.4389, 122.77, -150.857, -8.0411, 91.4445, -153.728, -10.4389, 94.3153, -116.801, -8.0411, 119.394, -119.056, -10.4389, 122.77, -157.124, -12.1193, 97.7113, -121.724, -12.1193, 126.763, -153.728, -10.4389, 94.3153, -157.124, -12.1193, 97.7113, -119.056, -10.4389, 122.77, -121.724, -12.1193, 126.763, -160.848, -12.9847, 101.435, -124.65, -12.9847, 131.142, -157.124, -12.1193, 97.7113, -160.848, -12.9847, 101.435, -121.724, -12.1193, 126.763, -124.65, -12.9847, 131.142, -164.683, -12.9847, 105.271, -127.664, -12.9847, 135.652, -160.848, -12.9847, 101.435, -164.683, -12.9847, 105.271, -124.65, -12.9847, 131.142, -127.664, -12.9847, 135.652, -168.407, -12.1193, 108.994, -130.589, -12.1193, 140.031, -164.683, -12.9847, 105.271, -168.407, -12.1193, 108.994, -127.664, -12.9847, 135.652, -130.589, -12.1193, 140.031, -171.803, -10.4389, 112.39, -133.258, -10.4389, 144.024, -168.407, -12.1193, 108.994, -171.803, -10.4389, 112.39, -130.589, -12.1193, 140.031, -133.258, -10.4389, 144.024, -174.674, -8.0411, 115.261, -135.513, -8.0411, 147.399, -171.803, -10.4389, 112.39, -174.674, -8.0411, 115.261, -133.258, -10.4389, 144.024, -135.513, -8.0411, 147.399, -176.853, -5.0652, 117.44, -137.225, -5.0652, 149.961, -174.674, -8.0411, 115.261, -176.853, -5.0652, 117.44, -135.513, -8.0411, 147.399, -137.225, -5.0652, 149.961, -178.213, -1.6842, 118.8, -138.294, -1.6842, 151.561, -176.853, -5.0652, 117.44, -178.213, -1.6842, 118.8, -137.225, -5.0652, 149.961, -138.294, -1.6842, 151.561, -178.675, 1.9054, 119.262, -138.657, 1.9054, 152.104, -178.213, -1.6842, 118.8, -178.675, 1.9054, 119.262, -138.294, -1.6842, 151.561, -178.675, 1.9054, 119.262, -210.973, 5.495, 78.8808, -178.213, 5.495, 118.8, -211.517, 1.9054, 79.244, -210.973, 5.495, 78.8808, -178.675, 1.9054, 119.262, -178.213, 5.495, 118.8, -209.374, 8.876, 77.8122, -176.853, 8.876, 117.44, -210.973, 5.495, 78.8808, -209.374, 8.876, 77.8122, -178.213, 5.495, 118.8, -176.853, 8.876, 117.44, -206.812, 11.8519, 76.1004, -174.674, 11.8519, 115.261, -209.374, 8.876, 77.8122, -206.812, 11.8519, 76.1004, -176.853, 8.876, 117.44, -174.674, 11.8519, 115.261, -203.437, 14.2498, 73.8449, -171.803, 14.2498, 112.39, -206.812, 11.8519, 76.1004, -203.437, 14.2498, 73.8449, -174.674, 11.8519, 115.261, -171.803, 14.2498, 112.39, -199.443, 15.9302, 71.1767, -168.407, 15.9302, 108.994, -203.437, 14.2498, 73.8449, -199.443, 15.9302, 71.1767, -171.803, 14.2498, 112.39, -168.407, 15.9302, 108.994, -195.064, 16.7956, 68.2508, -164.683, 16.7956, 105.271, -199.443, 15.9302, 71.1767, -195.064, 16.7956, 68.2508, -168.407, 15.9302, 108.994, -164.683, 16.7956, 105.271, -190.555, 16.7956, 65.2374, -160.848, 16.7956, 101.435, -195.064, 16.7956, 68.2508, -190.555, 16.7956, 65.2374, -164.683, 16.7956, 105.271, -160.848, 16.7956, 101.435, -186.176, 15.9302, 62.3116, -157.124, 15.9302, 97.7113, -190.555, 16.7956, 65.2374, -186.176, 15.9302, 62.3116, -160.848, 16.7956, 101.435, -157.124, 15.9302, 97.7113, -182.182, 14.2498, 59.6434, -153.728, 14.2498, 94.3153, -186.176, 15.9302, 62.3116, -182.182, 14.2498, 59.6434, -157.124, 15.9302, 97.7113, -153.728, 14.2498, 94.3153, -178.807, 11.8519, 57.3878, -150.857, 11.8519, 91.4445, -182.182, 14.2498, 59.6434, -178.807, 11.8519, 57.3878, -153.728, 14.2498, 94.3153, -150.857, 11.8519, 91.4445, -176.245, 8.876, 55.676, -148.678, 8.876, 89.2658, -178.807, 11.8519, 57.3878, -176.245, 8.876, 55.676, -150.857, 11.8519, 91.4445, -148.678, 8.876, 89.2658, -174.646, 5.495, 54.6074, -147.318, 5.495, 87.9057, -176.245, 8.876, 55.676, -174.646, 5.495, 54.6074, -148.678, 8.876, 89.2658, -147.318, 5.495, 87.9057, -174.102, 1.9054, 54.2442, -146.856, 1.9054, 87.4435, -174.646, 5.495, 54.6074, -174.102, 1.9054, 54.2442, -147.318, 5.495, 87.9057, -146.856, 1.9054, 87.4435, -174.646, -1.6842, 54.6074, -147.318, -1.6842, 87.9057, -174.102, 1.9054, 54.2442, -174.646, -1.6842, 54.6074, -146.856, 1.9054, 87.4435, -147.318, -1.6842, 87.9057, -176.245, -5.0652, 55.676, -148.678, -5.0652, 89.2658, -174.646, -1.6842, 54.6074, -176.245, -5.0652, 55.676, -147.318, -1.6842, 87.9057, -148.678, -5.0652, 89.2658, -178.807, -8.0411, 57.3878, -150.857, -8.0411, 91.4445, -176.245, -5.0652, 55.676, -178.807, -8.0411, 57.3878, -148.678, -5.0652, 89.2658, -150.857, -8.0411, 91.4445, -182.182, -10.4389, 59.6434, -153.728, -10.4389, 94.3153, -178.807, -8.0411, 57.3878, -182.182, -10.4389, 59.6434, -150.857, -8.0411, 91.4445, -153.728, -10.4389, 94.3153, -186.176, -12.1193, 62.3116, -157.124, -12.1193, 97.7113, -182.182, -10.4389, 59.6434, -186.176, -12.1193, 62.3116, -153.728, -10.4389, 94.3153, -157.124, -12.1193, 97.7113, -190.555, -12.9847, 65.2374, -160.848, -12.9847, 101.435, -186.176, -12.1193, 62.3116, -190.555, -12.9847, 65.2374, -157.124, -12.1193, 97.7113, -160.848, -12.9847, 101.435, -195.064, -12.9847, 68.2508, -164.683, -12.9847, 105.271, -190.555, -12.9847, 65.2374, -195.064, -12.9847, 68.2508, -160.848, -12.9847, 101.435, -164.683, -12.9847, 105.271, -199.443, -12.1193, 71.1767, -168.407, -12.1193, 108.994, -195.064, -12.9847, 68.2508, -199.443, -12.1193, 71.1767, -164.683, -12.9847, 105.271, -168.407, -12.1193, 108.994, -203.437, -10.4389, 73.8449, -171.803, -10.4389, 112.39, -199.443, -12.1193, 71.1767, -203.437, -10.4389, 73.8449, -168.407, -12.1193, 108.994, -171.803, -10.4389, 112.39, -206.812, -8.0411, 76.1004, -174.674, -8.0411, 115.261, -203.437, -10.4389, 73.8449, -206.812, -8.0411, 76.1004, -171.803, -10.4389, 112.39, -174.674, -8.0411, 115.261, -209.374, -5.0652, 77.8122, -176.853, -5.0652, 117.44, -206.812, -8.0411, 76.1004, -209.374, -5.0652, 77.8122, -174.674, -8.0411, 115.261, -176.853, -5.0652, 117.44, -210.973, -1.6842, 78.8808, -178.213, -1.6842, 118.8, -209.374, -5.0652, 77.8122, -210.973, -1.6842, 78.8808, -176.853, -5.0652, 117.44, -178.213, -1.6842, 118.8, -211.517, 1.9054, 79.244, -178.675, 1.9054, 119.262, -210.973, -1.6842, 78.8808, -211.517, 1.9054, 79.244, -178.213, -1.6842, 118.8, -211.517, 1.9054, 79.244, -235.317, 5.495, 33.3375, -210.973, 5.495, 78.8808, -235.921, 1.9054, 33.5877, -235.317, 5.495, 33.3375, -211.517, 1.9054, 79.244, -210.973, 5.495, 78.8808, -233.54, 8.876, 32.6014, -209.374, 8.876, 77.8122, -235.317, 5.495, 33.3375, -233.54, 8.876, 32.6014, -210.973, 5.495, 78.8808, -209.374, 8.876, 77.8122, -230.693, 11.8519, 31.4223, -206.812, 11.8519, 76.1004, -233.54, 8.876, 32.6014, -230.693, 11.8519, 31.4223, -209.374, 8.876, 77.8122, -206.812, 11.8519, 76.1004, -226.942, 14.2498, 29.8687, -203.437, 14.2498, 73.8449, -230.693, 11.8519, 31.4223, -226.942, 14.2498, 29.8687, -206.812, 11.8519, 76.1004, -203.437, 14.2498, 73.8449, -222.505, 15.9302, 28.0308, -199.443, 15.9302, 71.1767, -226.942, 14.2498, 29.8687, -222.505, 15.9302, 28.0308, -203.437, 14.2498, 73.8449, -199.443, 15.9302, 71.1767, -217.64, 16.7956, 26.0154, -195.064, 16.7956, 68.2508, -222.505, 15.9302, 28.0308, -217.64, 16.7956, 26.0154, -199.443, 15.9302, 71.1767, -195.064, 16.7956, 68.2508, -212.629, 16.7956, 23.9398, -190.555, 16.7956, 65.2374, -217.64, 16.7956, 26.0154, -212.629, 16.7956, 23.9398, -195.064, 16.7956, 68.2508, -190.555, 16.7956, 65.2374, -207.763, 15.9302, 21.9244, -186.176, 15.9302, 62.3116, -212.629, 16.7956, 23.9398, -207.763, 15.9302, 21.9244, -190.555, 16.7956, 65.2374, -186.176, 15.9302, 62.3116, -203.326, 14.2498, 20.0865, -182.182, 14.2498, 59.6434, -207.763, 15.9302, 21.9244, -203.326, 14.2498, 20.0865, -186.176, 15.9302, 62.3116, -182.182, 14.2498, 59.6434, -199.575, 11.8519, 18.5329, -178.807, 11.8519, 57.3878, -203.326, 14.2498, 20.0865, -199.575, 11.8519, 18.5329, -182.182, 14.2498, 59.6434, -178.807, 11.8519, 57.3878, -196.729, 8.876, 17.3537, -176.245, 8.876, 55.676, -199.575, 11.8519, 18.5329, -196.729, 8.876, 17.3537, -178.807, 11.8519, 57.3878, -176.245, 8.876, 55.676, -194.952, 5.495, 16.6177, -174.646, 5.495, 54.6074, -196.729, 8.876, 17.3537, -194.952, 5.495, 16.6177, -176.245, 8.876, 55.676, -174.646, 5.495, 54.6074, -194.348, 1.9054, 16.3675, -174.102, 1.9054, 54.2442, -194.952, 5.495, 16.6177, -194.348, 1.9054, 16.3675, -174.646, 5.495, 54.6074, -174.102, 1.9054, 54.2442, -194.952, -1.6842, 16.6177, -174.646, -1.6842, 54.6074, -194.348, 1.9054, 16.3675, -194.952, -1.6842, 16.6177, -174.102, 1.9054, 54.2442, -174.646, -1.6842, 54.6074, -196.729, -5.0652, 17.3537, -176.245, -5.0652, 55.676, -194.952, -1.6842, 16.6177, -196.729, -5.0652, 17.3537, -174.646, -1.6842, 54.6074, -176.245, -5.0652, 55.676, -199.575, -8.0411, 18.5329, -178.807, -8.0411, 57.3878, -196.729, -5.0652, 17.3537, -199.575, -8.0411, 18.5329, -176.245, -5.0652, 55.676, -178.807, -8.0411, 57.3878, -203.326, -10.4389, 20.0865, -182.182, -10.4389, 59.6434, -199.575, -8.0411, 18.5329, -203.326, -10.4389, 20.0865, -178.807, -8.0411, 57.3878, -182.182, -10.4389, 59.6434, -207.763, -12.1193, 21.9244, -186.176, -12.1193, 62.3116, -203.326, -10.4389, 20.0865, -207.763, -12.1193, 21.9244, -182.182, -10.4389, 59.6434, -186.176, -12.1193, 62.3116, -212.629, -12.9847, 23.9398, -190.555, -12.9847, 65.2374, -207.763, -12.1193, 21.9244, -212.629, -12.9847, 23.9398, -186.176, -12.1193, 62.3116, -190.555, -12.9847, 65.2374, -217.64, -12.9847, 26.0154, -195.064, -12.9847, 68.2508, -212.629, -12.9847, 23.9398, -217.64, -12.9847, 26.0154, -190.555, -12.9847, 65.2374, -195.064, -12.9847, 68.2508, -222.505, -12.1193, 28.0308, -199.443, -12.1193, 71.1767, -217.64, -12.9847, 26.0154, -222.505, -12.1193, 28.0308, -195.064, -12.9847, 68.2508, -199.443, -12.1193, 71.1767, -226.942, -10.4389, 29.8687, -203.437, -10.4389, 73.8449, -222.505, -12.1193, 28.0308, -226.942, -10.4389, 29.8687, -199.443, -12.1193, 71.1767, -203.437, -10.4389, 73.8449, -230.693, -8.0411, 31.4223, -206.812, -8.0411, 76.1004, -226.942, -10.4389, 29.8687, -230.693, -8.0411, 31.4223, -203.437, -10.4389, 73.8449, -206.812, -8.0411, 76.1004, -233.54, -5.0652, 32.6014, -209.374, -5.0652, 77.8122, -230.693, -8.0411, 31.4223, -233.54, -5.0652, 32.6014, -206.812, -8.0411, 76.1004, -209.374, -5.0652, 77.8122, -235.317, -1.6842, 33.3375, -210.973, -1.6842, 78.8808, -233.54, -5.0652, 32.6014, -235.317, -1.6842, 33.3375, -209.374, -5.0652, 77.8122, -210.973, -1.6842, 78.8808, -235.921, 1.9054, 33.5877, -211.517, 1.9054, 79.244, -235.317, -1.6842, 33.3375, -235.921, 1.9054, 33.5877, -210.973, -1.6842, 78.8808, -235.921, 1.9054, 33.5877, -250.307, 5.495, -16.0799, -235.317, 5.495, 33.3375, -250.949, 1.9054, -15.9524, -250.307, 5.495, -16.0799, -235.921, 1.9054, 33.5877, -235.317, 5.495, 33.3375, -248.421, 8.876, -16.4552, -233.54, 8.876, 32.6014, -250.307, 5.495, -16.0799, -248.421, 8.876, -16.4552, -235.317, 5.495, 33.3375, -233.54, 8.876, 32.6014, -245.399, 11.8519, -17.0563, -230.693, 11.8519, 31.4223, -248.421, 8.876, -16.4552, -245.399, 11.8519, -17.0563, -233.54, 8.876, 32.6014, -230.693, 11.8519, 31.4223, -241.417, 14.2498, -17.8483, -226.942, 14.2498, 29.8687, -245.399, 11.8519, -17.0563, -241.417, 14.2498, -17.8483, -230.693, 11.8519, 31.4223, -226.942, 14.2498, 29.8687, -236.707, 15.9302, -18.7853, -222.505, 15.9302, 28.0308, -241.417, 14.2498, -17.8483, -236.707, 15.9302, -18.7853, -226.942, 14.2498, 29.8687, -222.505, 15.9302, 28.0308, -231.542, 16.7956, -19.8127, -217.64, 16.7956, 26.0154, -236.707, 15.9302, -18.7853, -231.542, 16.7956, -19.8127, -222.505, 15.9302, 28.0308, -217.64, 16.7956, 26.0154, -226.222, 16.7956, -20.8709, -212.629, 16.7956, 23.9398, -231.542, 16.7956, -19.8127, -226.222, 16.7956, -20.8709, -217.64, 16.7956, 26.0154, -212.629, 16.7956, 23.9398, -221.057, 15.9302, -21.8983, -207.763, 15.9302, 21.9244, -226.222, 16.7956, -20.8709, -221.057, 15.9302, -21.8983, -212.629, 16.7956, 23.9398, -207.763, 15.9302, 21.9244, -216.346, 14.2498, -22.8352, -203.326, 14.2498, 20.0865, -221.057, 15.9302, -21.8983, -216.346, 14.2498, -22.8352, -207.763, 15.9302, 21.9244, -203.326, 14.2498, 20.0865, -212.364, 11.8519, -23.6273, -199.575, 11.8519, 18.5329, -216.346, 14.2498, -22.8352, -212.364, 11.8519, -23.6273, -203.326, 14.2498, 20.0865, -199.575, 11.8519, 18.5329, -209.342, 8.876, -24.2284, -196.729, 8.876, 17.3537, -212.364, 11.8519, -23.6273, -209.342, 8.876, -24.2284, -199.575, 11.8519, 18.5329, -196.729, 8.876, 17.3537, -207.456, 5.495, -24.6036, -194.952, 5.495, 16.6177, -209.342, 8.876, -24.2284, -207.456, 5.495, -24.6036, -196.729, 8.876, 17.3537, -194.952, 5.495, 16.6177, -206.815, 1.9054, -24.7312, -194.348, 1.9054, 16.3675, -207.456, 5.495, -24.6036, -206.815, 1.9054, -24.7312, -194.952, 5.495, 16.6177, -194.348, 1.9054, 16.3675, -207.456, -1.6842, -24.6036, -194.952, -1.6842, 16.6177, -206.815, 1.9054, -24.7312, -207.456, -1.6842, -24.6036, -194.348, 1.9054, 16.3675, -194.952, -1.6842, 16.6177, -209.342, -5.0652, -24.2284, -196.729, -5.0652, 17.3537, -207.456, -1.6842, -24.6036, -209.342, -5.0652, -24.2284, -194.952, -1.6842, 16.6177, -196.729, -5.0652, 17.3537, -212.364, -8.0411, -23.6273, -199.575, -8.0411, 18.5329, -209.342, -5.0652, -24.2284, -212.364, -8.0411, -23.6273, -196.729, -5.0652, 17.3537, -199.575, -8.0411, 18.5329, -216.346, -10.4389, -22.8352, -203.326, -10.4389, 20.0865, -212.364, -8.0411, -23.6273, -216.346, -10.4389, -22.8352, -199.575, -8.0411, 18.5329, -203.326, -10.4389, 20.0865, -221.057, -12.1193, -21.8983, -207.763, -12.1193, 21.9244, -216.346, -10.4389, -22.8352, -221.057, -12.1193, -21.8983, -203.326, -10.4389, 20.0865, -207.763, -12.1193, 21.9244, -226.222, -12.9847, -20.8709, -212.629, -12.9847, 23.9398, -221.057, -12.1193, -21.8983, -226.222, -12.9847, -20.8709, -207.763, -12.1193, 21.9244, -212.629, -12.9847, 23.9398, -231.542, -12.9847, -19.8127, -217.64, -12.9847, 26.0154, -226.222, -12.9847, -20.8709, -231.542, -12.9847, -19.8127, -212.629, -12.9847, 23.9398, -217.64, -12.9847, 26.0154, -236.707, -12.1193, -18.7853, -222.505, -12.1193, 28.0308, -231.542, -12.9847, -19.8127, -236.707, -12.1193, -18.7853, -217.64, -12.9847, 26.0154, -222.505, -12.1193, 28.0308, -241.417, -10.4389, -17.8483, -226.942, -10.4389, 29.8687, -236.707, -12.1193, -18.7853, -241.417, -10.4389, -17.8483, -222.505, -12.1193, 28.0308, -226.942, -10.4389, 29.8687, -245.399, -8.0411, -17.0563, -230.693, -8.0411, 31.4223, -241.417, -10.4389, -17.8483, -245.399, -8.0411, -17.0563, -226.942, -10.4389, 29.8687, -230.693, -8.0411, 31.4223, -248.421, -5.0652, -16.4552, -233.54, -5.0652, 32.6014, -245.399, -8.0411, -17.0563, -248.421, -5.0652, -16.4552, -230.693, -8.0411, 31.4223, -233.54, -5.0652, 32.6014, -250.307, -1.6842, -16.0799, -235.317, -1.6842, 33.3375, -248.421, -5.0652, -16.4552, -250.307, -1.6842, -16.0799, -233.54, -5.0652, 32.6014, -235.317, -1.6842, 33.3375, -250.949, 1.9054, -15.9524, -235.921, 1.9054, 33.5877, -250.307, -1.6842, -16.0799, -250.949, 1.9054, -15.9524, -235.317, -1.6842, 33.3375, -253.7, 5.495, -50.5297, -250.307, 5.495, -16.0799, -253.917, 4.3155, -50.5431, -250.307, 5.495, -16.0799, -250.949, 1.9054, -15.9524, -253.917, 4.3155, -50.5431, -253.917, 4.3155, -50.5431, -250.949, 1.9054, -15.9524, -254.358, 1.9054, -50.5705, -251.765, 8.8761, -50.4097, -248.421, 8.876, -16.4552, -252.406, 7.7562, -50.4494, -248.421, 8.876, -16.4552, -250.307, 5.495, -16.0799, -252.406, 7.7562, -50.4494, -252.406, 7.7562, -50.4494, -250.307, 5.495, -16.0799, -253.7, 5.495, -50.5297, -248.665, 11.8519, -50.2175, -245.399, 11.8519, -17.0563, -249.71, 10.8492, -50.2822, -245.399, 11.8519, -17.0563, -248.421, 8.876, -16.4552, -249.71, 10.8492, -50.2822, -249.71, 10.8492, -50.2822, -248.421, 8.876, -16.4552, -251.765, 8.8761, -50.4097, -244.58, 14.2498, -49.9642, -241.417, 14.2498, -17.8483, -245.992, 13.4212, -50.0517, -241.417, 14.2498, -17.8483, -245.399, 11.8519, -17.0563, -245.992, 13.4212, -50.0517, -245.992, 13.4212, -50.0517, -245.399, 11.8519, -17.0563, -248.665, 11.8519, -50.2175, -239.748, 15.9302, -49.6646, -236.707, 15.9302, -18.7853, -241.472, 15.3308, -49.7714, -236.707, 15.9302, -18.7853, -241.417, 14.2498, -17.8483, -241.472, 15.3308, -49.7714, -241.472, 15.3308, -49.7714, -241.417, 14.2498, -17.8483, -244.58, 14.2498, -49.9642, -234.449, 16.7956, -49.336, -231.542, 16.7956, -19.8127, -236.41, 16.4754, -49.4576, -231.542, 16.7956, -19.8127, -236.707, 15.9302, -18.7853, -236.41, 16.4754, -49.4576, -236.41, 16.4754, -49.4576, -236.707, 15.9302, -18.7853, -239.748, 15.9302, -49.6646, -228.992, 16.7956, -48.9977, -226.222, 16.7956, -20.8709, -231.093, 16.7956, -49.1279, -226.222, 16.7956, -20.8709, -231.542, 16.7956, -19.8127, -231.093, 16.7956, -49.1279, -231.093, 16.7956, -49.1279, -231.542, 16.7956, -19.8127, -234.449, 16.7956, -49.336, -223.693, 15.9302, -48.6691, -221.057, 15.9302, -21.8983, -225.816, 16.2769, -48.8008, -221.057, 15.9302, -21.8983, -226.222, 16.7956, -20.8709, -225.816, 16.2769, -48.8008, -225.816, 16.2769, -48.8008, -226.222, 16.7956, -20.8709, -228.992, 16.7956, -48.9977, -218.861, 14.2498, -48.3695, -216.346, 14.2498, -22.8352, -220.873, 14.9495, -48.4943, -216.346, 14.2498, -22.8352, -221.057, 15.9302, -21.8983, -220.873, 14.9495, -48.4943, -220.873, 14.9495, -48.4943, -221.057, 15.9302, -21.8983, -223.693, 15.9302, -48.6691, -214.776, 11.8519, -48.1162, -212.364, 11.8519, -23.6273, -216.538, 12.8859, -48.2254, -212.364, 11.8519, -23.6273, -216.346, 14.2498, -22.8352, -216.538, 12.8859, -48.2254, -216.538, 12.8859, -48.2254, -216.346, 14.2498, -22.8352, -218.861, 14.2498, -48.3695, -211.676, 8.8761, -47.924, -209.342, 8.876, -24.2284, -213.052, 10.1971, -48.0094, -209.342, 8.876, -24.2284, -212.364, 11.8519, -23.6273, -213.052, 10.1971, -48.0094, -213.052, 10.1971, -48.0094, -212.364, 11.8519, -23.6273, -214.776, 11.8519, -48.1162, -209.741, 5.495, -47.804, -207.456, 5.495, -24.6036, -210.619, 7.0285, -47.8585, -207.456, 5.495, -24.6036, -209.342, 8.876, -24.2284, -210.619, 7.0285, -47.8585, -210.619, 7.0285, -47.8585, -209.342, 8.876, -24.2284, -211.676, 8.8761, -47.924, -209.083, 1.9054, -47.7632, -206.815, 1.9054, -24.7312, -209.385, 3.5542, -47.782, -206.815, 1.9054, -24.7312, -207.456, 5.495, -24.6036, -209.385, 3.5542, -47.782, -209.385, 3.5542, -47.782, -207.456, 5.495, -24.6036, -209.741, 5.495, -47.804, -209.741, -1.6842, -47.804, -207.456, -1.6842, -24.6036, -209.438, -0.0308, -47.7852, -207.456, -1.6842, -24.6036, -206.815, 1.9054, -24.7312, -209.438, -0.0308, -47.7852, -209.438, -0.0308, -47.7852, -206.815, 1.9054, -24.7312, -209.083, 1.9054, -47.7632, -211.676, -5.0652, -47.924, -209.342, -5.0652, -24.2284, -210.791, -3.5191, -47.8691, -209.342, -5.0652, -24.2284, -207.456, -1.6842, -24.6036, -210.791, -3.5191, -47.8691, -210.791, -3.5191, -47.8691, -207.456, -1.6842, -24.6036, -209.741, -1.6842, -47.804, -214.776, -8.0411, -48.1162, -212.364, -8.0411, -23.6273, -213.383, -6.7031, -48.0298, -212.364, -8.0411, -23.6273, -209.342, -5.0652, -24.2284, -213.383, -6.7031, -48.0298, -213.383, -6.7031, -48.0298, -209.342, -5.0652, -24.2284, -211.676, -5.0652, -47.924, -218.861, -10.4389, -48.3695, -216.346, -10.4389, -22.8352, -217.071, -9.3881, -48.2585, -216.346, -10.4389, -22.8352, -212.364, -8.0411, -23.6273, -217.071, -9.3881, -48.2585, -217.071, -9.3881, -48.2585, -212.364, -8.0411, -23.6273, -214.776, -8.0411, -48.1162, -223.693, -12.1193, -48.6691, -221.057, -12.1193, -21.8983, -221.644, -11.4067, -48.5421, -221.057, -12.1193, -21.8983, -216.346, -10.4389, -22.8352, -221.644, -11.4067, -48.5421, -221.644, -11.4067, -48.5421, -216.346, -10.4389, -22.8352, -218.861, -10.4389, -48.3695, -228.992, -12.9847, -48.9977, -226.222, -12.9847, -20.8709, -226.828, -12.6314, -48.8635, -226.222, -12.9847, -20.8709, -221.057, -12.1193, -21.8983, -226.828, -12.6314, -48.8635, -226.828, -12.6314, -48.8635, -221.057, -12.1193, -21.8983, -223.693, -12.1193, -48.6691, -234.449, -12.9847, -49.336, -231.542, -12.9847, -19.8127, -232.31, -12.9847, -49.2034, -231.542, -12.9847, -19.8127, -226.222, -12.9847, -20.8709, -232.31, -12.9847, -49.2034, -232.31, -12.9847, -49.2034, -226.222, -12.9847, -20.8709, -228.992, -12.9847, -48.9977, -239.748, -12.1193, -49.6646, -236.707, -12.1193, -18.7853, -237.755, -12.4449, -49.541, -236.707, -12.1193, -18.7853, -231.542, -12.9847, -19.8127, -237.755, -12.4449, -49.541, -237.755, -12.4449, -49.541, -231.542, -12.9847, -19.8127, -234.449, -12.9847, -49.336, -244.58, -10.4389, -49.9642, -241.417, -10.4389, -17.8483, -242.832, -11.0469, -49.8558, -241.417, -10.4389, -17.8483, -236.707, -12.1193, -18.7853, -242.832, -11.0469, -49.8558, -242.832, -11.0469, -49.8558, -236.707, -12.1193, -18.7853, -239.748, -12.1193, -49.6646, -248.665, -8.0411, -50.2175, -245.399, -8.0411, -17.0563, -247.237, -8.8791, -50.129, -245.399, -8.0411, -17.0563, -241.417, -10.4389, -17.8483, -247.237, -8.8791, -50.129, -247.237, -8.8791, -50.129, -241.417, -10.4389, -17.8483, -244.58, -10.4389, -49.9642, -251.765, -5.0652, -50.4097, -248.421, -5.0652, -16.4552, -250.712, -6.0762, -50.3444, -248.421, -5.0652, -16.4552, -245.399, -8.0411, -17.0563, -250.712, -6.0762, -50.3444, -250.712, -6.0762, -50.3444, -245.399, -8.0411, -17.0563, -248.665, -8.0411, -50.2175, -253.7, -1.6842, -50.5297, -250.307, -1.6842, -16.0799, -253.056, -2.8097, -50.4897, -250.307, -1.6842, -16.0799, -248.421, -5.0652, -16.4552, -253.056, -2.8097, -50.4897, -253.056, -2.8097, -50.4897, -248.421, -5.0652, -16.4552, -251.765, -5.0652, -50.4097, -254.358, 1.9054, -50.5705, -250.949, 1.9054, -15.9524, -254.142, 0.7239, -50.557, -250.949, 1.9054, -15.9524, -250.307, -1.6842, -16.0799, -254.142, 0.7239, -50.557, -254.142, 0.7239, -50.557, -250.307, -1.6842, -16.0799, -253.7, -1.6842, -50.5297, 260.638, 4.4899, -18.6388, 260.502, 4.4899, -17.2583, 260.65, 4.417, -18.6381, 260.65, 4.417, -18.6381, 260.502, 4.4899, -17.2583, 261.075, 1.8384, -18.6118, 260.502, 4.4899, -17.2583, 260.933, 1.8384, -17.1727, 261.075, 1.8384, -18.6118, 259.355, 6.9872, -18.7184, 259.236, 6.9872, -17.5103, 259.386, 6.9269, -18.7165, 259.386, 6.9269, -18.7165, 259.236, 6.9872, -17.5103, 260.638, 4.4899, -18.6388, 259.236, 6.9872, -17.5103, 260.502, 4.4899, -17.2583, 260.638, 4.4899, -18.6388, 257.298, 9.1853, -18.8459, 257.206, 9.1853, -17.9139, 257.337, 9.1441, -18.8435, 257.337, 9.1441, -18.8435, 257.206, 9.1853, -17.9139, 259.355, 6.9872, -18.7184, 257.206, 9.1853, -17.9139, 259.236, 6.9872, -17.5103, 259.355, 6.9872, -18.7184, 254.589, 10.9564, -19.014, 254.533, 10.9564, -18.4458, 254.62, 10.936, -19.012, 254.62, 10.936, -19.012, 254.533, 10.9564, -18.4458, 257.298, 9.1853, -18.8459, 254.533, 10.9564, -18.4458, 257.206, 9.1853, -17.9139, 257.298, 9.1853, -18.8459, 251.383, 12.1977, -19.2127, 251.37, 12.1977, -19.0749, 251.392, 12.1941, -19.2121, 251.392, 12.1941, -19.2121, 251.37, 12.1977, -19.0749, 254.589, 10.9564, -19.014, 251.37, 12.1977, -19.0749, 254.533, 10.9564, -18.4458, 254.589, 10.9564, -19.014, 250.357, 12.3842, -19.2763, 251.37, 12.1977, -19.0749, 251.383, 12.1977, -19.2127, 251.383, -8.5208, -19.2127, 251.37, -8.5208, -19.0749, 251.373, -8.5226, -19.2133, 251.373, -8.5226, -19.2133, 251.37, -8.5208, -19.0749, 250.357, -8.7074, -19.2763, 254.589, -7.2796, -19.0139, 254.533, -7.2796, -18.4458, 254.551, -7.294, -19.0163, 254.551, -7.294, -19.0163, 254.533, -7.2796, -18.4458, 251.383, -8.5208, -19.2127, 254.533, -7.2796, -18.4458, 251.37, -8.5208, -19.0749, 251.383, -8.5208, -19.2127, 257.298, -5.5084, -18.8459, 257.206, -5.5084, -17.9139, 257.247, -5.5419, -18.8491, 257.247, -5.5419, -18.8491, 257.206, -5.5084, -17.9139, 254.589, -7.2796, -19.0139, 257.206, -5.5084, -17.9139, 254.533, -7.2796, -18.4458, 254.589, -7.2796, -19.0139, 259.355, -3.3103, -18.7184, 259.236, -3.3103, -17.5103, 259.305, -3.3636, -18.7215, 259.305, -3.3636, -18.7215, 259.236, -3.3103, -17.5103, 257.298, -5.5084, -18.8459, 259.236, -3.3103, -17.5103, 257.206, -5.5084, -17.9139, 257.298, -5.5084, -18.8459, 260.638, -0.813, -18.6388, 260.502, -0.813, -17.2583, 260.603, -0.8818, -18.641, 260.603, -0.8818, -18.641, 260.502, -0.813, -17.2583, 259.355, -3.3103, -18.7184, 260.502, -0.813, -17.2583, 259.236, -3.3103, -17.5103, 259.355, -3.3103, -18.7184, 261.075, 1.8384, -18.6118, 260.933, 1.8384, -17.1727, 261.062, 1.7625, -18.6126, 261.062, 1.7625, -18.6126, 260.933, 1.8384, -17.1727, 260.638, -0.813, -18.6388, 260.933, 1.8384, -17.1727, 260.502, -0.813, -17.2583, 260.638, -0.813, -18.6388, 260.933, 1.8384, -17.1727, 260.502, 4.4899, -17.2583, 245.855, 4.4899, 31.026, 246.261, 1.8384, 31.194, 260.933, 1.8384, -17.1727, 245.855, 4.4899, 31.026, 260.502, 4.4899, -17.2583, 259.236, 6.9872, -17.5103, 244.662, 6.9872, 30.5317, 245.855, 4.4899, 31.026, 260.502, 4.4899, -17.2583, 244.662, 6.9872, 30.5317, 259.236, 6.9872, -17.5103, 257.206, 9.1853, -17.9139, 242.751, 9.1853, 29.74, 244.662, 6.9872, 30.5317, 259.236, 6.9872, -17.5103, 242.751, 9.1853, 29.74, 257.206, 9.1853, -17.9139, 254.533, 10.9564, -18.4458, 240.232, 10.9564, 28.6967, 242.751, 9.1853, 29.74, 257.206, 9.1853, -17.9139, 240.232, 10.9564, 28.6967, 254.533, 10.9564, -18.4458, 251.37, 12.1977, -19.0749, 237.253, 12.1977, 27.4626, 240.232, 10.9564, 28.6967, 254.533, 10.9564, -18.4458, 237.253, 12.1977, 27.4626, 247.801, 12.8368, -19.4348, 233.986, 12.8369, 26.1093, 250.357, 12.3842, -19.2763, 233.986, 12.8369, 26.1093, 251.37, 12.1977, -19.0749, 250.357, 12.3842, -19.2763, 237.253, 12.1977, 27.4626, 251.37, 12.1977, -19.0749, 233.986, 12.8369, 26.1093, 244.083, 12.8369, -19.6653, 230.621, 12.8369, 24.7155, 247.774, 12.8369, -19.4365, 247.774, 12.8369, -19.4365, 230.621, 12.8369, 24.7155, 247.801, 12.8368, -19.4348, 230.621, 12.8369, 24.7155, 233.986, 12.8369, 26.1093, 247.801, 12.8368, -19.4348, 240.474, 12.1977, -19.8891, 227.354, 12.1977, 23.3622, 244.017, 12.8251, -19.6694, 244.017, 12.8251, -19.6694, 227.354, 12.1977, 23.3622, 244.083, 12.8369, -19.6653, 227.354, 12.1977, 23.3622, 230.621, 12.8369, 24.7155, 244.083, 12.8369, -19.6653, 237.182, 10.9564, -20.0932, 224.374, 10.9564, 22.1281, 240.377, 12.1612, -19.8951, 240.377, 12.1612, -19.8951, 224.374, 10.9564, 22.1281, 240.474, 12.1977, -19.8891, 224.374, 10.9564, 22.1281, 227.354, 12.1977, 23.3622, 240.474, 12.1977, -19.8891, 234.399, 9.1853, -20.2658, 221.855, 9.1853, 21.0848, 237.072, 10.8864, -20.1, 237.072, 10.8864, -20.1, 221.855, 9.1853, 21.0848, 237.182, 10.9564, -20.0932, 221.855, 9.1853, 21.0848, 224.374, 10.9564, 22.1281, 237.182, 10.9564, -20.0932, 232.287, 6.9872, -20.3967, 219.944, 6.9872, 20.2931, 234.297, 9.0794, -20.2721, 234.297, 9.0794, -20.2721, 219.944, 6.9872, 20.2931, 234.399, 9.1853, -20.2658, 219.944, 6.9872, 20.2931, 221.855, 9.1853, 21.0848, 234.399, 9.1853, -20.2658, 230.969, 4.4899, -20.4785, 218.751, 4.4899, 19.7988, 232.215, 6.8504, -20.4012, 232.215, 6.8504, -20.4012, 218.751, 4.4899, 19.7988, 232.287, 6.9872, -20.3967, 218.751, 4.4899, 19.7988, 219.944, 6.9872, 20.2931, 232.287, 6.9872, -20.3967, 230.521, 1.8384, -20.5062, 218.345, 1.8384, 19.6308, 230.942, 4.3342, -20.4801, 230.942, 4.3342, -20.4801, 218.345, 1.8384, 19.6308, 230.969, 4.4899, -20.4785, 218.345, 1.8384, 19.6308, 218.751, 4.4899, 19.7988, 230.969, 4.4899, -20.4785, 230.969, -0.813, -20.4785, 218.751, -0.813, 19.7988, 230.547, 1.6799, -20.5046, 230.547, 1.6799, -20.5046, 218.751, -0.813, 19.7988, 230.521, 1.8384, -20.5062, 218.751, -0.813, 19.7988, 218.345, 1.8384, 19.6308, 230.521, 1.8384, -20.5062, 232.287, -3.3103, -20.3967, 219.944, -3.3103, 20.2931, 231.045, -0.9577, -20.4737, 231.045, -0.9577, -20.4737, 219.944, -3.3103, 20.2931, 230.969, -0.813, -20.4785, 219.944, -3.3103, 20.2931, 218.751, -0.813, 19.7988, 230.969, -0.813, -20.4785, 234.399, -5.5084, -20.2658, 221.855, -5.5085, 21.0848, 232.4, -3.4277, -20.3897, 232.4, -3.4277, -20.3897, 221.855, -5.5085, 21.0848, 232.287, -3.3103, -20.3967, 221.855, -5.5085, 21.0848, 219.944, -3.3103, 20.2931, 232.287, -3.3103, -20.3967, 237.182, -7.2796, -20.0932, 224.374, -7.2796, 22.1281, 234.528, -5.5908, -20.2577, 234.528, -5.5908, -20.2577, 224.374, -7.2796, 22.1281, 234.399, -5.5084, -20.2658, 224.374, -7.2796, 22.1281, 221.855, -5.5085, 21.0848, 234.399, -5.5084, -20.2658, 240.474, -8.5208, -19.8891, 227.354, -8.5208, 23.3622, 237.306, -7.3265, -20.0855, 237.306, -7.3265, -20.0855, 227.354, -8.5208, 23.3622, 237.182, -7.2796, -20.0932, 227.354, -8.5208, 23.3622, 224.374, -7.2796, 22.1281, 237.182, -7.2796, -20.0932, 244.083, -9.16, -19.6653, 230.621, -9.16, 24.7155, 240.575, -8.5387, -19.8829, 240.575, -8.5387, -19.8829, 230.621, -9.16, 24.7155, 240.474, -8.5208, -19.8891, 230.621, -9.16, 24.7155, 227.354, -8.5208, 23.3622, 240.474, -8.5208, -19.8891, 247.801, -9.16, -19.4348, 233.986, -9.16, 26.1093, 244.148, -9.16, -19.6613, 244.148, -9.16, -19.6613, 233.986, -9.16, 26.1093, 244.083, -9.16, -19.6653, 233.986, -9.16, 26.1093, 230.621, -9.16, 24.7155, 244.083, -9.16, -19.6653, 250.357, -8.7074, -19.2763, 251.37, -8.5208, -19.0749, 237.253, -8.5208, 27.4626, 250.357, -8.7074, -19.2763, 237.253, -8.5208, 27.4626, 247.827, -9.1555, -19.4332, 247.827, -9.1555, -19.4332, 237.253, -8.5208, 27.4626, 247.801, -9.16, -19.4348, 237.253, -8.5208, 27.4626, 233.986, -9.16, 26.1093, 247.801, -9.16, -19.4348, 251.37, -8.5208, -19.0749, 254.533, -7.2796, -18.4458, 240.232, -7.2796, 28.6967, 237.253, -8.5208, 27.4626, 251.37, -8.5208, -19.0749, 240.232, -7.2796, 28.6967, 254.533, -7.2796, -18.4458, 257.206, -5.5084, -17.9139, 242.751, -5.5084, 29.74, 240.232, -7.2796, 28.6967, 254.533, -7.2796, -18.4458, 242.751, -5.5084, 29.74, 257.206, -5.5084, -17.9139, 259.236, -3.3103, -17.5103, 244.662, -3.3103, 30.5317, 242.751, -5.5084, 29.74, 257.206, -5.5084, -17.9139, 244.662, -3.3103, 30.5317, 259.236, -3.3103, -17.5103, 260.502, -0.813, -17.2583, 245.855, -0.813, 31.026, 244.662, -3.3103, 30.5317, 259.236, -3.3103, -17.5103, 245.855, -0.813, 31.026, 260.502, -0.813, -17.2583, 260.933, 1.8384, -17.1727, 246.261, 1.8384, 31.194, 245.855, -0.813, 31.026, 260.502, -0.813, -17.2583, 246.261, 1.8384, 31.194, 246.261, 1.8384, 31.194, 245.855, 4.4899, 31.026, 222.07, 4.4899, 75.5251, 222.435, 1.8384, 75.769, 246.261, 1.8384, 31.194, 222.07, 4.4899, 75.5251, 245.855, 4.4899, 31.026, 244.662, 6.9872, 30.5317, 220.996, 6.9872, 74.8075, 222.07, 4.4899, 75.5251, 245.855, 4.4899, 31.026, 220.996, 6.9872, 74.8075, 244.662, 6.9872, 30.5317, 242.751, 9.1853, 29.74, 219.276, 9.1853, 73.6581, 220.996, 6.9872, 74.8075, 244.662, 6.9872, 30.5317, 219.276, 9.1853, 73.6581, 242.751, 9.1853, 29.74, 240.232, 10.9564, 28.6967, 217.009, 10.9564, 72.1435, 219.276, 9.1853, 73.6581, 242.751, 9.1853, 29.74, 217.009, 10.9564, 72.1435, 240.232, 10.9564, 28.6967, 237.253, 12.1977, 27.4626, 214.328, 12.1977, 70.3518, 217.009, 10.9564, 72.1435, 240.232, 10.9564, 28.6967, 214.328, 12.1977, 70.3518, 237.253, 12.1977, 27.4626, 233.986, 12.8369, 26.1093, 211.388, 12.8369, 68.3871, 214.328, 12.1977, 70.3518, 237.253, 12.1977, 27.4626, 211.388, 12.8369, 68.3871, 233.986, 12.8369, 26.1093, 230.621, 12.8369, 24.7155, 208.359, 12.8369, 66.3637, 211.388, 12.8369, 68.3871, 233.986, 12.8369, 26.1093, 208.359, 12.8369, 66.3637, 230.621, 12.8369, 24.7155, 227.354, 12.1977, 23.3622, 205.419, 12.1977, 64.399, 208.359, 12.8369, 66.3637, 230.621, 12.8369, 24.7155, 205.419, 12.1977, 64.399, 227.354, 12.1977, 23.3622, 224.374, 10.9564, 22.1281, 202.737, 10.9564, 62.6073, 205.419, 12.1977, 64.399, 227.354, 12.1977, 23.3622, 202.737, 10.9564, 62.6073, 224.374, 10.9564, 22.1281, 221.855, 9.1853, 21.0848, 200.471, 9.1853, 61.0927, 202.737, 10.9564, 62.6073, 224.374, 10.9564, 22.1281, 200.471, 9.1853, 61.0927, 221.855, 9.1853, 21.0848, 219.944, 6.9872, 20.2931, 198.75, 6.9872, 59.9433, 200.471, 9.1853, 61.0927, 221.855, 9.1853, 21.0848, 198.75, 6.9872, 59.9433, 219.944, 6.9872, 20.2931, 218.751, 4.4899, 19.7988, 197.677, 4.4899, 59.2257, 198.75, 6.9872, 59.9433, 219.944, 6.9872, 20.2931, 197.677, 4.4899, 59.2257, 218.751, 4.4899, 19.7988, 218.345, 1.8384, 19.6308, 197.312, 1.8384, 58.9819, 197.677, 4.4899, 59.2257, 218.751, 4.4899, 19.7988, 197.312, 1.8384, 58.9819, 218.345, 1.8384, 19.6308, 218.751, -0.813, 19.7988, 197.677, -0.813, 59.2257, 197.312, 1.8384, 58.9819, 218.345, 1.8384, 19.6308, 197.677, -0.813, 59.2257, 218.751, -0.813, 19.7988, 219.944, -3.3103, 20.2931, 198.75, -3.3103, 59.9433, 197.677, -0.813, 59.2257, 218.751, -0.813, 19.7988, 198.75, -3.3103, 59.9433, 219.944, -3.3103, 20.2931, 221.855, -5.5085, 21.0848, 200.471, -5.5084, 61.0927, 198.75, -3.3103, 59.9433, 219.944, -3.3103, 20.2931, 200.471, -5.5084, 61.0927, 221.855, -5.5085, 21.0848, 224.374, -7.2796, 22.1281, 202.737, -7.2796, 62.6073, 200.471, -5.5084, 61.0927, 221.855, -5.5085, 21.0848, 202.737, -7.2796, 62.6073, 224.374, -7.2796, 22.1281, 227.354, -8.5208, 23.3622, 205.419, -8.5208, 64.399, 202.737, -7.2796, 62.6073, 224.374, -7.2796, 22.1281, 205.419, -8.5208, 64.399, 227.354, -8.5208, 23.3622, 230.621, -9.16, 24.7155, 208.359, -9.16, 66.3637, 205.419, -8.5208, 64.399, 227.354, -8.5208, 23.3622, 208.359, -9.16, 66.3637, 230.621, -9.16, 24.7155, 233.986, -9.16, 26.1093, 211.388, -9.16, 68.3871, 208.359, -9.16, 66.3637, 230.621, -9.16, 24.7155, 211.388, -9.16, 68.3871, 233.986, -9.16, 26.1093, 237.253, -8.5208, 27.4626, 214.328, -8.5208, 70.3518, 211.388, -9.16, 68.3871, 233.986, -9.16, 26.1093, 214.328, -8.5208, 70.3518, 237.253, -8.5208, 27.4626, 240.232, -7.2796, 28.6967, 217.009, -7.2796, 72.1435, 214.328, -8.5208, 70.3518, 237.253, -8.5208, 27.4626, 217.009, -7.2796, 72.1435, 240.232, -7.2796, 28.6967, 242.751, -5.5084, 29.74, 219.276, -5.5084, 73.6581, 217.009, -7.2796, 72.1435, 240.232, -7.2796, 28.6967, 219.276, -5.5084, 73.6581, 242.751, -5.5084, 29.74, 244.662, -3.3103, 30.5317, 220.996, -3.3103, 74.8075, 219.276, -5.5084, 73.6581, 242.751, -5.5084, 29.74, 220.996, -3.3103, 74.8075, 244.662, -3.3103, 30.5317, 245.855, -0.813, 31.026, 222.07, -0.813, 75.5251, 220.996, -3.3103, 74.8075, 244.662, -3.3103, 30.5317, 222.07, -0.813, 75.5251, 245.855, -0.813, 31.026, 246.261, 1.8384, 31.194, 222.435, 1.8384, 75.769, 222.07, -0.813, 75.5251, 245.855, -0.813, 31.026, 222.435, 1.8384, 75.769, 222.435, 1.8384, 75.769, 222.07, 4.4899, 75.5251, 190.061, 4.4899, 114.529, 190.371, 1.8384, 114.839, 222.435, 1.8384, 75.769, 190.061, 4.4899, 114.529, 222.07, 4.4899, 75.5251, 220.996, 6.9872, 74.8075, 189.147, 6.9872, 113.616, 190.061, 4.4899, 114.529, 222.07, 4.4899, 75.5251, 189.147, 6.9872, 113.616, 220.996, 6.9872, 74.8075, 219.276, 9.1853, 73.6581, 187.684, 9.1853, 112.153, 189.147, 6.9872, 113.616, 220.996, 6.9872, 74.8075, 187.684, 9.1853, 112.153, 219.276, 9.1853, 73.6581, 217.009, 10.9564, 72.1435, 185.757, 10.9564, 110.225, 187.684, 9.1853, 112.153, 219.276, 9.1853, 73.6581, 185.757, 10.9564, 110.225, 217.009, 10.9564, 72.1435, 214.328, 12.1977, 70.3518, 183.476, 12.1977, 107.944, 185.757, 10.9564, 110.225, 217.009, 10.9564, 72.1435, 183.476, 12.1977, 107.944, 214.328, 12.1977, 70.3518, 211.388, 12.8369, 68.3871, 180.976, 12.8369, 105.444, 183.476, 12.1977, 107.944, 214.328, 12.1977, 70.3518, 180.976, 12.8369, 105.444, 211.388, 12.8369, 68.3871, 208.359, 12.8369, 66.3637, 178.4, 12.8369, 102.869, 180.976, 12.8369, 105.444, 211.388, 12.8369, 68.3871, 178.4, 12.8369, 102.869, 208.359, 12.8369, 66.3637, 205.419, 12.1977, 64.399, 175.9, 12.1977, 100.368, 178.4, 12.8369, 102.869, 208.359, 12.8369, 66.3637, 175.9, 12.1977, 100.368, 205.419, 12.1977, 64.399, 202.737, 10.9564, 62.6073, 173.62, 10.9564, 98.0877, 175.9, 12.1977, 100.368, 205.419, 12.1977, 64.399, 173.62, 10.9564, 98.0877, 202.737, 10.9564, 62.6073, 200.471, 9.1853, 61.0927, 171.692, 9.1853, 96.1599, 173.62, 10.9564, 98.0877, 202.737, 10.9564, 62.6073, 171.692, 9.1853, 96.1599, 200.471, 9.1853, 61.0927, 198.75, 6.9872, 59.9433, 170.229, 6.9872, 94.697, 171.692, 9.1853, 96.1599, 200.471, 9.1853, 61.0927, 170.229, 6.9872, 94.697, 198.75, 6.9872, 59.9433, 197.677, 4.4899, 59.2257, 169.316, 4.4899, 93.7837, 170.229, 6.9872, 94.697, 198.75, 6.9872, 59.9433, 169.316, 4.4899, 93.7837, 197.677, 4.4899, 59.2257, 197.312, 1.8384, 58.9819, 169.005, 1.8384, 93.4733, 169.316, 4.4899, 93.7837, 197.677, 4.4899, 59.2257, 169.005, 1.8384, 93.4733, 197.312, 1.8384, 58.9819, 197.677, -0.813, 59.2257, 169.316, -0.813, 93.7837, 169.005, 1.8384, 93.4733, 197.312, 1.8384, 58.9819, 169.316, -0.813, 93.7837, 197.677, -0.813, 59.2257, 198.75, -3.3103, 59.9433, 170.229, -3.3103, 94.697, 169.316, -0.813, 93.7837, 197.677, -0.813, 59.2257, 170.229, -3.3103, 94.697, 198.75, -3.3103, 59.9433, 200.471, -5.5084, 61.0927, 171.692, -5.5084, 96.1599, 170.229, -3.3103, 94.697, 198.75, -3.3103, 59.9433, 171.692, -5.5084, 96.1599, 200.471, -5.5084, 61.0927, 202.737, -7.2796, 62.6073, 173.62, -7.2796, 98.0877, 171.692, -5.5084, 96.1599, 200.471, -5.5084, 61.0927, 173.62, -7.2796, 98.0877, 202.737, -7.2796, 62.6073, 205.419, -8.5208, 64.399, 175.9, -8.5208, 100.368, 173.62, -7.2796, 98.0877, 202.737, -7.2796, 62.6073, 175.9, -8.5208, 100.368, 205.419, -8.5208, 64.399, 208.359, -9.16, 66.3637, 178.4, -9.16, 102.869, 175.9, -8.5208, 100.368, 205.419, -8.5208, 64.399, 178.4, -9.16, 102.869, 208.359, -9.16, 66.3637, 211.388, -9.16, 68.3871, 180.976, -9.16, 105.444, 178.4, -9.16, 102.869, 208.359, -9.16, 66.3637, 180.976, -9.16, 105.444, 211.388, -9.16, 68.3871, 214.328, -8.5208, 70.3518, 183.476, -8.5208, 107.944, 180.976, -9.16, 105.444, 211.388, -9.16, 68.3871, 183.476, -8.5208, 107.944, 214.328, -8.5208, 70.3518, 217.009, -7.2796, 72.1435, 185.757, -7.2796, 110.225, 183.476, -8.5208, 107.944, 214.328, -8.5208, 70.3518, 185.757, -7.2796, 110.225, 217.009, -7.2796, 72.1435, 219.276, -5.5084, 73.6581, 187.684, -5.5084, 112.153, 185.757, -7.2796, 110.225, 217.009, -7.2796, 72.1435, 187.684, -5.5084, 112.153, 219.276, -5.5084, 73.6581, 220.996, -3.3103, 74.8075, 189.147, -3.3103, 113.616, 187.684, -5.5084, 112.153, 219.276, -5.5084, 73.6581, 189.147, -3.3103, 113.616, 220.996, -3.3103, 74.8075, 222.07, -0.813, 75.5251, 190.061, -0.813, 114.529, 189.147, -3.3103, 113.616, 220.996, -3.3103, 74.8075, 190.061, -0.813, 114.529, 222.07, -0.813, 75.5251, 222.435, 1.8384, 75.769, 190.371, 1.8384, 114.839, 190.061, -0.813, 114.529, 222.07, -0.813, 75.5251, 190.371, 1.8384, 114.839, 190.371, 1.8384, 114.839, 190.061, 4.4899, 114.529, 151.057, 4.4899, 146.538, 151.301, 1.8384, 146.903, 190.371, 1.8384, 114.839, 151.057, 4.4899, 146.538, 190.061, 4.4899, 114.529, 189.147, 6.9872, 113.616, 150.339, 6.9872, 145.464, 151.057, 4.4899, 146.538, 190.061, 4.4899, 114.529, 150.339, 6.9872, 145.464, 189.147, 6.9872, 113.616, 187.684, 9.1853, 112.153, 149.19, 9.1853, 143.744, 150.339, 6.9872, 145.464, 189.147, 6.9872, 113.616, 149.19, 9.1853, 143.744, 187.684, 9.1853, 112.153, 185.757, 10.9564, 110.225, 147.675, 10.9564, 141.477, 149.19, 9.1853, 143.744, 187.684, 9.1853, 112.153, 147.675, 10.9564, 141.477, 185.757, 10.9564, 110.225, 183.476, 12.1977, 107.944, 145.884, 12.1977, 138.796, 147.675, 10.9564, 141.477, 185.757, 10.9564, 110.225, 145.884, 12.1977, 138.796, 183.476, 12.1977, 107.944, 180.976, 12.8369, 105.444, 143.919, 12.8369, 135.856, 145.884, 12.1977, 138.796, 183.476, 12.1977, 107.944, 143.919, 12.8369, 135.856, 180.976, 12.8369, 105.444, 178.4, 12.8369, 102.869, 141.896, 12.8369, 132.827, 143.919, 12.8369, 135.856, 180.976, 12.8369, 105.444, 141.896, 12.8369, 132.827, 178.4, 12.8369, 102.869, 175.9, 12.1977, 100.368, 139.931, 12.1977, 129.887, 141.896, 12.8369, 132.827, 178.4, 12.8369, 102.869, 139.931, 12.1977, 129.887, 175.9, 12.1977, 100.368, 173.62, 10.9564, 98.0877, 138.139, 10.9564, 127.206, 139.931, 12.1977, 129.887, 175.9, 12.1977, 100.368, 138.139, 10.9564, 127.206, 173.62, 10.9564, 98.0877, 171.692, 9.1853, 96.1599, 136.625, 9.1853, 124.939, 138.139, 10.9564, 127.206, 173.62, 10.9564, 98.0877, 136.625, 9.1853, 124.939, 171.692, 9.1853, 96.1599, 170.229, 6.9872, 94.697, 135.475, 6.9872, 123.219, 136.625, 9.1853, 124.939, 171.692, 9.1853, 96.1599, 135.475, 6.9872, 123.219, 170.229, 6.9872, 94.697, 169.316, 4.4899, 93.7837, 134.758, 4.4899, 122.145, 135.475, 6.9872, 123.219, 170.229, 6.9872, 94.697, 134.758, 4.4899, 122.145, 169.316, 4.4899, 93.7837, 169.005, 1.8384, 93.4733, 134.514, 1.8384, 121.78, 134.758, 4.4899, 122.145, 169.316, 4.4899, 93.7837, 134.514, 1.8384, 121.78, 169.005, 1.8384, 93.4733, 169.316, -0.813, 93.7837, 134.758, -0.813, 122.145, 134.514, 1.8384, 121.78, 169.005, 1.8384, 93.4733, 134.758, -0.813, 122.145, 169.316, -0.813, 93.7837, 170.229, -3.3103, 94.697, 135.475, -3.3103, 123.219, 134.758, -0.813, 122.145, 169.316, -0.813, 93.7837, 135.475, -3.3103, 123.219, 170.229, -3.3103, 94.697, 171.692, -5.5084, 96.1599, 136.625, -5.5084, 124.939, 135.475, -3.3103, 123.219, 170.229, -3.3103, 94.697, 136.625, -5.5084, 124.939, 171.692, -5.5084, 96.1599, 173.62, -7.2796, 98.0877, 138.139, -7.2796, 127.206, 136.625, -5.5084, 124.939, 171.692, -5.5084, 96.1599, 138.139, -7.2796, 127.206, 173.62, -7.2796, 98.0877, 175.9, -8.5208, 100.368, 139.931, -8.5208, 129.887, 138.139, -7.2796, 127.206, 173.62, -7.2796, 98.0877, 139.931, -8.5208, 129.887, 175.9, -8.5208, 100.368, 178.4, -9.16, 102.869, 141.896, -9.16, 132.827, 139.931, -8.5208, 129.887, 175.9, -8.5208, 100.368, 141.896, -9.16, 132.827, 178.4, -9.16, 102.869, 180.976, -9.16, 105.444, 143.919, -9.16, 135.856, 141.896, -9.16, 132.827, 178.4, -9.16, 102.869, 143.919, -9.16, 135.856, 180.976, -9.16, 105.444, 183.476, -8.5208, 107.944, 145.884, -8.5208, 138.796, 143.919, -9.16, 135.856, 180.976, -9.16, 105.444, 145.884, -8.5208, 138.796, 183.476, -8.5208, 107.944, 185.757, -7.2796, 110.225, 147.675, -7.2796, 141.477, 145.884, -8.5208, 138.796, 183.476, -8.5208, 107.944, 147.675, -7.2796, 141.477, 185.757, -7.2796, 110.225, 187.684, -5.5084, 112.153, 149.19, -5.5084, 143.744, 147.675, -7.2796, 141.477, 185.757, -7.2796, 110.225, 149.19, -5.5084, 143.744, 187.684, -5.5084, 112.153, 189.147, -3.3103, 113.616, 150.339, -3.3103, 145.464, 149.19, -5.5084, 143.744, 187.684, -5.5084, 112.153, 150.339, -3.3103, 145.464, 189.147, -3.3103, 113.616, 190.061, -0.813, 114.529, 151.057, -0.813, 146.538, 150.339, -3.3103, 145.464, 189.147, -3.3103, 113.616, 151.057, -0.813, 146.538, 190.061, -0.813, 114.529, 190.371, 1.8384, 114.839, 151.301, 1.8384, 146.903, 151.057, -0.813, 146.538, 190.061, -0.813, 114.529, 151.301, 1.8384, 146.903, 151.301, 1.8384, 146.903, 151.057, 4.4899, 146.538, 106.558, 4.4899, 170.324, 106.726, 1.8384, 170.729, 151.301, 1.8384, 146.903, 106.558, 4.4899, 170.324, 151.057, 4.4899, 146.538, 150.339, 6.9872, 145.464, 106.064, 6.9872, 169.13, 106.558, 4.4899, 170.324, 151.057, 4.4899, 146.538, 106.064, 6.9872, 169.13, 150.339, 6.9872, 145.464, 149.19, 9.1853, 143.744, 105.272, 9.1853, 167.219, 106.064, 6.9872, 169.13, 150.339, 6.9872, 145.464, 105.272, 9.1853, 167.219, 149.19, 9.1853, 143.744, 147.675, 10.9564, 141.477, 104.229, 10.9564, 164.7, 105.272, 9.1853, 167.219, 149.19, 9.1853, 143.744, 104.229, 10.9564, 164.7, 147.675, 10.9564, 141.477, 145.884, 12.1977, 138.796, 102.994, 12.1977, 161.721, 104.229, 10.9564, 164.7, 147.675, 10.9564, 141.477, 102.994, 12.1977, 161.721, 145.884, 12.1977, 138.796, 143.919, 12.8369, 135.856, 101.641, 12.8369, 158.454, 102.994, 12.1977, 161.721, 145.884, 12.1977, 138.796, 101.641, 12.8369, 158.454, 143.919, 12.8369, 135.856, 141.896, 12.8369, 132.827, 100.247, 12.8369, 155.089, 101.641, 12.8369, 158.454, 143.919, 12.8369, 135.856, 100.247, 12.8369, 155.089, 141.896, 12.8369, 132.827, 139.931, 12.1977, 129.887, 98.8941, 12.1977, 151.822, 100.247, 12.8369, 155.089, 141.896, 12.8369, 132.827, 98.8941, 12.1977, 151.822, 139.931, 12.1977, 129.887, 138.139, 10.9564, 127.206, 97.66, 10.9564, 148.842, 98.8941, 12.1977, 151.822, 139.931, 12.1977, 129.887, 97.66, 10.9564, 148.842, 138.139, 10.9564, 127.206, 136.625, 9.1853, 124.939, 96.6167, 9.1853, 146.324, 97.66, 10.9564, 148.842, 138.139, 10.9564, 127.206, 96.6167, 9.1853, 146.324, 136.625, 9.1853, 124.939, 135.475, 6.9872, 123.219, 95.825, 6.9872, 144.412, 96.6167, 9.1853, 146.324, 136.625, 9.1853, 124.939, 95.825, 6.9872, 144.412, 135.475, 6.9872, 123.219, 134.758, 4.4899, 122.145, 95.3307, 4.4899, 143.219, 95.825, 6.9872, 144.412, 135.475, 6.9872, 123.219, 95.3307, 4.4899, 143.219, 134.758, 4.4899, 122.145, 134.514, 1.8384, 121.78, 95.1627, 1.8384, 142.813, 95.3307, 4.4899, 143.219, 134.758, 4.4899, 122.145, 95.1627, 1.8384, 142.813, 134.514, 1.8384, 121.78, 134.758, -0.813, 122.145, 95.3307, -0.813, 143.219, 95.1627, 1.8384, 142.813, 134.514, 1.8384, 121.78, 95.3307, -0.813, 143.219, 134.758, -0.813, 122.145, 135.475, -3.3103, 123.219, 95.825, -3.3103, 144.412, 95.3307, -0.813, 143.219, 134.758, -0.813, 122.145, 95.825, -3.3103, 144.412, 135.475, -3.3103, 123.219, 136.625, -5.5084, 124.939, 96.6167, -5.5084, 146.324, 95.825, -3.3103, 144.412, 135.475, -3.3103, 123.219, 96.6167, -5.5084, 146.324, 136.625, -5.5084, 124.939, 138.139, -7.2796, 127.206, 97.66, -7.2796, 148.842, 96.6167, -5.5084, 146.324, 136.625, -5.5084, 124.939, 97.66, -7.2796, 148.842, 138.139, -7.2796, 127.206, 139.931, -8.5208, 129.887, 98.8941, -8.5208, 151.822, 97.66, -7.2796, 148.842, 138.139, -7.2796, 127.206, 98.8941, -8.5208, 151.822, 139.931, -8.5208, 129.887, 141.896, -9.16, 132.827, 100.247, -9.16, 155.089, 98.8941, -8.5208, 151.822, 139.931, -8.5208, 129.887, 100.247, -9.16, 155.089, 141.896, -9.16, 132.827, 143.919, -9.16, 135.856, 101.641, -9.16, 158.454, 100.247, -9.16, 155.089, 141.896, -9.16, 132.827, 101.641, -9.16, 158.454, 143.919, -9.16, 135.856, 145.884, -8.5208, 138.796, 102.994, -8.5208, 161.721, 101.641, -9.16, 158.454, 143.919, -9.16, 135.856, 102.994, -8.5208, 161.721, 145.884, -8.5208, 138.796, 147.675, -7.2796, 141.477, 104.229, -7.2796, 164.7, 102.994, -8.5208, 161.721, 145.884, -8.5208, 138.796, 104.229, -7.2796, 164.7, 147.675, -7.2796, 141.477, 149.19, -5.5084, 143.744, 105.272, -5.5084, 167.219, 104.229, -7.2796, 164.7, 147.675, -7.2796, 141.477, 105.272, -5.5084, 167.219, 149.19, -5.5084, 143.744, 150.339, -3.3103, 145.464, 106.064, -3.3103, 169.13, 105.272, -5.5084, 167.219, 149.19, -5.5084, 143.744, 106.064, -3.3103, 169.13, 150.339, -3.3103, 145.464, 151.057, -0.813, 146.538, 106.558, -0.813, 170.324, 106.064, -3.3103, 169.13, 150.339, -3.3103, 145.464, 106.558, -0.813, 170.324, 151.057, -0.813, 146.538, 151.301, 1.8384, 146.903, 106.726, 1.8384, 170.729, 106.558, -0.813, 170.324, 151.057, -0.813, 146.538, 106.726, 1.8384, 170.729, 106.726, 1.8384, 170.729, 106.558, 4.4899, 170.324, 58.2736, 4.4899, 184.97, 58.3592, 1.8384, 185.401, 106.726, 1.8384, 170.729, 58.2736, 4.4899, 184.97, 106.558, 4.4899, 170.324, 106.064, 6.9872, 169.13, 58.0216, 6.9872, 183.704, 58.2736, 4.4899, 184.97, 106.558, 4.4899, 170.324, 58.0216, 6.9872, 183.704, 106.064, 6.9872, 169.13, 105.272, 9.1853, 167.219, 57.618, 9.1853, 181.675, 58.0216, 6.9872, 183.704, 106.064, 6.9872, 169.13, 57.618, 9.1853, 181.675, 105.272, 9.1853, 167.219, 104.229, 10.9564, 164.7, 57.0861, 10.9564, 179.001, 57.618, 9.1853, 181.675, 105.272, 9.1853, 167.219, 57.0861, 10.9564, 179.001, 104.229, 10.9564, 164.7, 102.994, 12.1977, 161.721, 56.457, 12.1977, 175.838, 57.0861, 10.9564, 179.001, 104.229, 10.9564, 164.7, 56.457, 12.1977, 175.838, 102.994, 12.1977, 161.721, 101.641, 12.8369, 158.454, 55.7671, 12.8369, 172.369, 56.457, 12.1977, 175.838, 102.994, 12.1977, 161.721, 55.7671, 12.8369, 172.369, 101.641, 12.8369, 158.454, 100.247, 12.8369, 155.089, 55.0565, 12.8369, 168.797, 55.7671, 12.8369, 172.369, 101.641, 12.8369, 158.454, 55.0565, 12.8369, 168.797, 100.247, 12.8369, 155.089, 98.8941, 12.1977, 151.822, 54.3666, 12.1977, 165.329, 55.0565, 12.8369, 168.797, 100.247, 12.8369, 155.089, 54.3666, 12.1977, 165.329, 98.8941, 12.1977, 151.822, 97.66, 10.9564, 148.842, 53.7375, 10.9564, 162.166, 54.3666, 12.1977, 165.329, 98.8941, 12.1977, 151.822, 53.7375, 10.9564, 162.166, 97.66, 10.9564, 148.842, 96.6167, 9.1853, 146.324, 53.2056, 9.1853, 159.492, 53.7375, 10.9564, 162.166, 97.66, 10.9564, 148.842, 53.2056, 9.1853, 159.492, 96.6167, 9.1853, 146.324, 95.825, 6.9872, 144.412, 52.802, 6.9872, 157.463, 53.2056, 9.1853, 159.492, 96.6167, 9.1853, 146.324, 52.802, 6.9872, 157.463, 95.825, 6.9872, 144.412, 95.3307, 4.4899, 143.219, 52.55, 4.4899, 156.196, 52.802, 6.9872, 157.463, 95.825, 6.9872, 144.412, 52.55, 4.4899, 156.196, 95.3307, 4.4899, 143.219, 95.1627, 1.8384, 142.813, 52.4644, 1.8384, 155.766, 52.55, 4.4899, 156.196, 95.3307, 4.4899, 143.219, 52.4644, 1.8384, 155.766, 95.1627, 1.8384, 142.813, 95.3307, -0.813, 143.219, 52.55, -0.813, 156.196, 52.4644, 1.8384, 155.766, 95.1627, 1.8384, 142.813, 52.55, -0.813, 156.196, 95.3307, -0.813, 143.219, 95.825, -3.3103, 144.412, 52.802, -3.3103, 157.463, 52.55, -0.813, 156.196, 95.3307, -0.813, 143.219, 52.802, -3.3103, 157.463, 95.825, -3.3103, 144.412, 96.6167, -5.5084, 146.324, 53.2056, -5.5084, 159.492, 52.802, -3.3103, 157.463, 95.825, -3.3103, 144.412, 53.2056, -5.5084, 159.492, 96.6167, -5.5084, 146.324, 97.66, -7.2796, 148.842, 53.7375, -7.2796, 162.166, 53.2056, -5.5084, 159.492, 96.6167, -5.5084, 146.324, 53.7375, -7.2796, 162.166, 97.66, -7.2796, 148.842, 98.8941, -8.5208, 151.822, 54.3666, -8.5208, 165.329, 53.7375, -7.2796, 162.166, 97.66, -7.2796, 148.842, 54.3666, -8.5208, 165.329, 98.8941, -8.5208, 151.822, 100.247, -9.16, 155.089, 55.0565, -9.16, 168.797, 54.3666, -8.5208, 165.329, 98.8941, -8.5208, 151.822, 55.0565, -9.16, 168.797, 100.247, -9.16, 155.089, 101.641, -9.16, 158.454, 55.7671, -9.16, 172.369, 55.0565, -9.16, 168.797, 100.247, -9.16, 155.089, 55.7671, -9.16, 172.369, 101.641, -9.16, 158.454, 102.994, -8.5208, 161.721, 56.457, -8.5208, 175.838, 55.7671, -9.16, 172.369, 101.641, -9.16, 158.454, 56.457, -8.5208, 175.838, 102.994, -8.5208, 161.721, 104.229, -7.2796, 164.7, 57.0861, -7.2796, 179.001, 56.457, -8.5208, 175.838, 102.994, -8.5208, 161.721, 57.0861, -7.2796, 179.001, 104.229, -7.2796, 164.7, 105.272, -5.5084, 167.219, 57.618, -5.5084, 181.675, 57.0861, -7.2796, 179.001, 104.229, -7.2796, 164.7, 57.618, -5.5084, 181.675, 105.272, -5.5084, 167.219, 106.064, -3.3103, 169.13, 58.0216, -3.3103, 183.704, 57.618, -5.5084, 181.675, 105.272, -5.5084, 167.219, 58.0216, -3.3103, 183.704, 106.064, -3.3103, 169.13, 106.558, -0.813, 170.324, 58.2736, -0.813, 184.97, 58.0216, -3.3103, 183.704, 106.064, -3.3103, 169.13, 58.2736, -0.813, 184.97, 106.558, -0.813, 170.324, 106.726, 1.8384, 170.729, 58.3592, 1.8384, 185.401, 58.2736, -0.813, 184.97, 106.558, -0.813, 170.324, 58.3592, 1.8384, 185.401, 58.3592, 1.8384, 185.401, 58.2736, 4.4899, 184.97, 8.0596, 4.4899, 189.916, 8.0596, 1.8384, 190.355, 58.3592, 1.8384, 185.401, 8.0596, 4.4899, 189.916, 58.2736, 4.4899, 184.97, 58.0216, 6.9872, 183.704, 8.0596, 6.9872, 188.625, 8.0596, 4.4899, 189.916, 58.2736, 4.4899, 184.97, 8.0596, 6.9872, 188.625, 58.0216, 6.9872, 183.704, 57.618, 9.1853, 181.675, 8.0596, 9.1853, 186.556, 8.0596, 6.9872, 188.625, 58.0216, 6.9872, 183.704, 8.0596, 9.1853, 186.556, 57.618, 9.1853, 181.675, 57.0861, 10.9564, 179.001, 8.0596, 10.9564, 183.829, 8.0596, 9.1853, 186.556, 57.618, 9.1853, 181.675, 8.0596, 10.9564, 183.829, 57.0861, 10.9564, 179.001, 56.457, 12.1977, 175.838, 8.0596, 12.1977, 180.604, 8.0596, 10.9564, 183.829, 57.0861, 10.9564, 179.001, 8.0596, 12.1977, 180.604, 56.457, 12.1977, 175.838, 55.7671, 12.8369, 172.369, 8.0596, 12.8369, 177.068, 8.0596, 12.1977, 180.604, 56.457, 12.1977, 175.838, 8.0596, 12.8369, 177.068, 55.7671, 12.8369, 172.369, 55.0565, 12.8369, 168.797, 8.0596, 12.8369, 173.426, 8.0596, 12.8369, 177.068, 55.7671, 12.8369, 172.369, 8.0596, 12.8369, 173.426, 55.0565, 12.8369, 168.797, 54.3666, 12.1977, 165.329, 8.0596, 12.1977, 169.89, 8.0596, 12.8369, 173.426, 55.0565, 12.8369, 168.797, 8.0596, 12.1977, 169.89, 54.3666, 12.1977, 165.329, 53.7375, 10.9564, 162.166, 8.0596, 10.9564, 166.665, 8.0596, 12.1977, 169.89, 54.3666, 12.1977, 165.329, 8.0596, 10.9564, 166.665, 53.7375, 10.9564, 162.166, 53.2056, 9.1853, 159.492, 8.0596, 9.1853, 163.939, 8.0596, 10.9564, 166.665, 53.7375, 10.9564, 162.166, 8.0596, 9.1853, 163.939, 53.2056, 9.1853, 159.492, 52.802, 6.9872, 157.463, 8.0596, 6.9872, 161.87, 8.0596, 9.1853, 163.939, 53.2056, 9.1853, 159.492, 8.0596, 6.9872, 161.87, 52.802, 6.9872, 157.463, 52.55, 4.4899, 156.196, 8.0596, 4.4899, 160.578, 8.0596, 6.9872, 161.87, 52.802, 6.9872, 157.463, 8.0596, 4.4899, 160.578, 52.55, 4.4899, 156.196, 52.4644, 1.8384, 155.766, 8.0596, 1.8384, 160.139, 8.0596, 4.4899, 160.578, 52.55, 4.4899, 156.196, 8.0596, 1.8384, 160.139, 52.4644, 1.8384, 155.766, 52.55, -0.813, 156.196, 8.0596, -0.813, 160.578, 8.0596, 1.8384, 160.139, 52.4644, 1.8384, 155.766, 8.0596, -0.813, 160.578, 52.55, -0.813, 156.196, 52.802, -3.3103, 157.463, 8.0596, -3.3103, 161.87, 8.0596, -0.813, 160.578, 52.55, -0.813, 156.196, 8.0596, -3.3103, 161.87, 52.802, -3.3103, 157.463, 53.2056, -5.5084, 159.492, 8.0596, -5.5084, 163.939, 8.0596, -3.3103, 161.87, 52.802, -3.3103, 157.463, 8.0596, -5.5084, 163.939, 53.2056, -5.5084, 159.492, 53.7375, -7.2796, 162.166, 8.0596, -7.2796, 166.665, 8.0596, -5.5084, 163.939, 53.2056, -5.5084, 159.492, 8.0596, -7.2796, 166.665, 53.7375, -7.2796, 162.166, 54.3666, -8.5208, 165.329, 8.0596, -8.5208, 169.89, 8.0596, -7.2796, 166.665, 53.7375, -7.2796, 162.166, 8.0596, -8.5208, 169.89, 54.3666, -8.5208, 165.329, 55.0565, -9.16, 168.797, 8.0596, -9.16, 173.426, 8.0596, -8.5208, 169.89, 54.3666, -8.5208, 165.329, 8.0596, -9.16, 173.426, 55.0565, -9.16, 168.797, 55.7671, -9.16, 172.369, 8.0596, -9.16, 177.068, 8.0596, -9.16, 173.426, 55.0565, -9.16, 168.797, 8.0596, -9.16, 177.068, 55.7671, -9.16, 172.369, 56.457, -8.5208, 175.838, 8.0596, -8.5208, 180.604, 8.0596, -9.16, 177.068, 55.7671, -9.16, 172.369, 8.0596, -8.5208, 180.604, 56.457, -8.5208, 175.838, 57.0861, -7.2796, 179.001, 8.0596, -7.2796, 183.829, 8.0596, -8.5208, 180.604, 56.457, -8.5208, 175.838, 8.0596, -7.2796, 183.829, 57.0861, -7.2796, 179.001, 57.618, -5.5084, 181.675, 8.0596, -5.5084, 186.556, 8.0596, -7.2796, 183.829, 57.0861, -7.2796, 179.001, 8.0596, -5.5084, 186.556, 57.618, -5.5084, 181.675, 58.0216, -3.3103, 183.704, 8.0596, -3.3103, 188.625, 8.0596, -5.5084, 186.556, 57.618, -5.5084, 181.675, 8.0596, -3.3103, 188.625, 58.0216, -3.3103, 183.704, 58.2736, -0.813, 184.97, 8.0596, -0.813, 189.916, 8.0596, -3.3103, 188.625, 58.0216, -3.3103, 183.704, 8.0596, -0.813, 189.916, 58.2736, -0.813, 184.97, 58.3592, 1.8384, 185.401, 8.0596, 1.8384, 190.355, 8.0596, -0.813, 189.916, 58.2736, -0.813, 184.97, 8.0596, 1.8384, 190.355, 8.0596, 1.8384, 190.355, 8.0596, 4.4899, 189.916, -42.1544, 4.4899, 184.97, -42.2401, 1.8384, 185.401, 8.0596, 1.8384, 190.355, -42.1544, 4.4899, 184.97, 8.0596, 4.4899, 189.916, 8.0596, 6.9872, 188.625, -41.9025, 6.9872, 183.704, -42.1544, 4.4899, 184.97, 8.0596, 4.4899, 189.916, -41.9025, 6.9872, 183.704, 8.0596, 6.9872, 188.625, 8.0596, 9.1853, 186.556, -41.4988, 9.1853, 181.675, -41.9025, 6.9872, 183.704, 8.0596, 6.9872, 188.625, -41.4988, 9.1853, 181.675, 8.0596, 9.1853, 186.556, 8.0596, 10.9564, 183.829, -40.967, 10.9564, 179.001, -41.4988, 9.1853, 181.675, 8.0596, 9.1853, 186.556, -40.967, 10.9564, 179.001, 8.0596, 10.9564, 183.829, 8.0596, 12.1977, 180.604, -40.3378, 12.1977, 175.838, -40.967, 10.9564, 179.001, 8.0596, 10.9564, 183.829, -40.3378, 12.1977, 175.838, 8.0596, 12.1977, 180.604, 8.0596, 12.8369, 177.068, -39.6479, 12.8369, 172.369, -40.3378, 12.1977, 175.838, 8.0596, 12.1977, 180.604, -39.6479, 12.8369, 172.369, 8.0596, 12.8369, 177.068, 8.0596, 12.8369, 173.426, -38.9374, 12.8369, 168.797, -39.6479, 12.8369, 172.369, 8.0596, 12.8369, 177.068, -38.9374, 12.8369, 168.797, 8.0596, 12.8369, 173.426, 8.0596, 12.1977, 169.89, -38.2475, 12.1977, 165.329, -38.9374, 12.8369, 168.797, 8.0596, 12.8369, 173.426, -38.2475, 12.1977, 165.329, 8.0596, 12.1977, 169.89, 8.0596, 10.9564, 166.665, -37.6183, 10.9564, 162.166, -38.2475, 12.1977, 165.329, 8.0596, 12.1977, 169.89, -37.6183, 10.9564, 162.166, 8.0596, 10.9564, 166.665, 8.0596, 9.1853, 163.939, -37.0865, 9.1853, 159.492, -37.6183, 10.9564, 162.166, 8.0596, 10.9564, 166.665, -37.0865, 9.1853, 159.492, 8.0596, 9.1853, 163.939, 8.0596, 6.9872, 161.87, -36.6828, 6.9872, 157.463, -37.0865, 9.1853, 159.492, 8.0596, 9.1853, 163.939, -36.6828, 6.9872, 157.463, 8.0596, 6.9872, 161.87, 8.0596, 4.4899, 160.578, -36.4309, 4.4899, 156.196, -36.6828, 6.9872, 157.463, 8.0596, 6.9872, 161.87, -36.4309, 4.4899, 156.196, 8.0596, 4.4899, 160.578, 8.0596, 1.8384, 160.139, -36.3452, 1.8384, 155.766, -36.4309, 4.4899, 156.196, 8.0596, 4.4899, 160.578, -36.3452, 1.8384, 155.766, 8.0596, 1.8384, 160.139, 8.0596, -0.813, 160.578, -36.4309, -0.813, 156.196, -36.3452, 1.8384, 155.766, 8.0596, 1.8384, 160.139, -36.4309, -0.813, 156.196, 8.0596, -0.813, 160.578, 8.0596, -3.3103, 161.87, -36.6828, -3.3103, 157.463, -36.4309, -0.813, 156.196, 8.0596, -0.813, 160.578, -36.6828, -3.3103, 157.463, 8.0596, -3.3103, 161.87, 8.0596, -5.5084, 163.939, -37.0865, -5.5084, 159.492, -36.6828, -3.3103, 157.463, 8.0596, -3.3103, 161.87, -37.0865, -5.5084, 159.492, 8.0596, -5.5084, 163.939, 8.0596, -7.2796, 166.665, -37.6183, -7.2796, 162.166, -37.0865, -5.5084, 159.492, 8.0596, -5.5084, 163.939, -37.6183, -7.2796, 162.166, 8.0596, -7.2796, 166.665, 8.0596, -8.5208, 169.89, -38.2475, -8.5208, 165.329, -37.6183, -7.2796, 162.166, 8.0596, -7.2796, 166.665, -38.2475, -8.5208, 165.329, 8.0596, -8.5208, 169.89, 8.0596, -9.16, 173.426, -38.9374, -9.16, 168.797, -38.2475, -8.5208, 165.329, 8.0596, -8.5208, 169.89, -38.9374, -9.16, 168.797, 8.0596, -9.16, 173.426, 8.0596, -9.16, 177.068, -39.6479, -9.16, 172.369, -38.9374, -9.16, 168.797, 8.0596, -9.16, 173.426, -39.6479, -9.16, 172.369, 8.0596, -9.16, 177.068, 8.0596, -8.5208, 180.604, -40.3378, -8.5208, 175.838, -39.6479, -9.16, 172.369, 8.0596, -9.16, 177.068, -40.3378, -8.5208, 175.838, 8.0596, -8.5208, 180.604, 8.0596, -7.2796, 183.829, -40.967, -7.2796, 179.001, -40.3378, -8.5208, 175.838, 8.0596, -8.5208, 180.604, -40.967, -7.2796, 179.001, 8.0596, -7.2796, 183.829, 8.0596, -5.5084, 186.556, -41.4988, -5.5084, 181.675, -40.967, -7.2796, 179.001, 8.0596, -7.2796, 183.829, -41.4988, -5.5084, 181.675, 8.0596, -5.5084, 186.556, 8.0596, -3.3103, 188.625, -41.9025, -3.3103, 183.704, -41.4988, -5.5084, 181.675, 8.0596, -5.5084, 186.556, -41.9025, -3.3103, 183.704, 8.0596, -3.3103, 188.625, 8.0596, -0.813, 189.916, -42.1544, -0.813, 184.97, -41.9025, -3.3103, 183.704, 8.0596, -3.3103, 188.625, -42.1544, -0.813, 184.97, 8.0596, -0.813, 189.916, 8.0596, 1.8384, 190.355, -42.2401, 1.8384, 185.401, -42.1544, -0.813, 184.97, 8.0596, -0.813, 189.916, -42.2401, 1.8384, 185.401, -42.2401, 1.8384, 185.401, -42.1544, 4.4899, 184.97, -90.4387, 4.4899, 170.324, -90.6067, 1.8384, 170.729, -42.2401, 1.8384, 185.401, -90.4387, 4.4899, 170.324, -42.1544, 4.4899, 184.97, -41.9025, 6.9872, 183.704, -89.9445, 6.9872, 169.13, -90.4387, 4.4899, 170.324, -42.1544, 4.4899, 184.97, -89.9445, 6.9872, 169.13, -41.9025, 6.9872, 183.704, -41.4988, 9.1853, 181.675, -89.1527, 9.1853, 167.219, -89.9445, 6.9872, 169.13, -41.9025, 6.9872, 183.704, -89.1527, 9.1853, 167.219, -41.4988, 9.1853, 181.675, -40.967, 10.9564, 179.001, -88.1095, 10.9564, 164.7, -89.1527, 9.1853, 167.219, -41.4988, 9.1853, 181.675, -88.1095, 10.9564, 164.7, -40.967, 10.9564, 179.001, -40.3378, 12.1977, 175.838, -86.8753, 12.1977, 161.721, -88.1095, 10.9564, 164.7, -40.967, 10.9564, 179.001, -86.8753, 12.1977, 161.721, -40.3378, 12.1977, 175.838, -39.6479, 12.8369, 172.369, -85.522, 12.8369, 158.454, -86.8753, 12.1977, 161.721, -40.3378, 12.1977, 175.838, -85.522, 12.8369, 158.454, -39.6479, 12.8369, 172.369, -38.9374, 12.8369, 168.797, -84.1283, 12.8369, 155.089, -85.522, 12.8369, 158.454, -39.6479, 12.8369, 172.369, -84.1283, 12.8369, 155.089, -38.9374, 12.8369, 168.797, -38.2475, 12.1977, 165.329, -82.775, 12.1977, 151.822, -84.1283, 12.8369, 155.089, -38.9374, 12.8369, 168.797, -82.775, 12.1977, 151.822, -38.2475, 12.1977, 165.329, -37.6183, 10.9564, 162.166, -81.5408, 10.9564, 148.842, -82.775, 12.1977, 151.822, -38.2475, 12.1977, 165.329, -81.5408, 10.9564, 148.842, -37.6183, 10.9564, 162.166, -37.0865, 9.1853, 159.492, -80.4976, 9.1853, 146.324, -81.5408, 10.9564, 148.842, -37.6183, 10.9564, 162.166, -80.4976, 9.1853, 146.324, -37.0865, 9.1853, 159.492, -36.6828, 6.9872, 157.463, -79.7058, 6.9872, 144.412, -80.4976, 9.1853, 146.324, -37.0865, 9.1853, 159.492, -79.7058, 6.9872, 144.412, -36.6828, 6.9872, 157.463, -36.4309, 4.4899, 156.196, -79.2116, 4.4899, 143.219, -79.7058, 6.9872, 144.412, -36.6828, 6.9872, 157.463, -79.2116, 4.4899, 143.219, -36.4309, 4.4899, 156.196, -36.3452, 1.8384, 155.766, -79.0436, 1.8384, 142.813, -79.2116, 4.4899, 143.219, -36.4309, 4.4899, 156.196, -79.0436, 1.8384, 142.813, -36.3452, 1.8384, 155.766, -36.4309, -0.813, 156.196, -79.2116, -0.813, 143.219, -79.0436, 1.8384, 142.813, -36.3452, 1.8384, 155.766, -79.2116, -0.813, 143.219, -36.4309, -0.813, 156.196, -36.6828, -3.3103, 157.463, -79.7058, -3.3103, 144.412, -79.2116, -0.813, 143.219, -36.4309, -0.813, 156.196, -79.7058, -3.3103, 144.412, -36.6828, -3.3103, 157.463, -37.0865, -5.5084, 159.492, -80.4976, -5.5084, 146.324, -79.7058, -3.3103, 144.412, -36.6828, -3.3103, 157.463, -80.4976, -5.5084, 146.324, -37.0865, -5.5084, 159.492, -37.6183, -7.2796, 162.166, -81.5408, -7.2796, 148.842, -80.4976, -5.5084, 146.324, -37.0865, -5.5084, 159.492, -81.5408, -7.2796, 148.842, -37.6183, -7.2796, 162.166, -38.2475, -8.5208, 165.329, -82.775, -8.5208, 151.822, -81.5408, -7.2796, 148.842, -37.6183, -7.2796, 162.166, -82.775, -8.5208, 151.822, -38.2475, -8.5208, 165.329, -38.9374, -9.16, 168.797, -84.1283, -9.16, 155.089, -82.775, -8.5208, 151.822, -38.2475, -8.5208, 165.329, -84.1283, -9.16, 155.089, -38.9374, -9.16, 168.797, -39.6479, -9.16, 172.369, -85.522, -9.16, 158.454, -84.1283, -9.16, 155.089, -38.9374, -9.16, 168.797, -85.522, -9.16, 158.454, -39.6479, -9.16, 172.369, -40.3378, -8.5208, 175.838, -86.8753, -8.5208, 161.721, -85.522, -9.16, 158.454, -39.6479, -9.16, 172.369, -86.8753, -8.5208, 161.721, -40.3378, -8.5208, 175.838, -40.967, -7.2796, 179.001, -88.1095, -7.2796, 164.7, -86.8753, -8.5208, 161.721, -40.3378, -8.5208, 175.838, -88.1095, -7.2796, 164.7, -40.967, -7.2796, 179.001, -41.4988, -5.5084, 181.675, -89.1527, -5.5084, 167.219, -88.1095, -7.2796, 164.7, -40.967, -7.2796, 179.001, -89.1527, -5.5084, 167.219, -41.4988, -5.5084, 181.675, -41.9025, -3.3103, 183.704, -89.9445, -3.3103, 169.13, -89.1527, -5.5084, 167.219, -41.4988, -5.5084, 181.675, -89.9445, -3.3103, 169.13, -41.9025, -3.3103, 183.704, -42.1544, -0.813, 184.97, -90.4387, -0.813, 170.324, -89.9445, -3.3103, 169.13, -41.9025, -3.3103, 183.704, -90.4387, -0.813, 170.324, -42.1544, -0.813, 184.97, -42.2401, 1.8384, 185.401, -90.6067, 1.8384, 170.729, -90.4387, -0.813, 170.324, -42.1544, -0.813, 184.97, -90.6067, 1.8384, 170.729, -90.6067, 1.8384, 170.729, -90.4387, 4.4899, 170.324, -134.938, 4.4899, 146.538, -135.182, 1.8384, 146.903, -90.6067, 1.8384, 170.729, -134.938, 4.4899, 146.538, -90.4387, 4.4899, 170.324, -89.9445, 6.9872, 169.13, -134.22, 6.9872, 145.464, -134.938, 4.4899, 146.538, -90.4387, 4.4899, 170.324, -134.22, 6.9872, 145.464, -89.9445, 6.9872, 169.13, -89.1527, 9.1853, 167.219, -133.071, 9.1853, 143.744, -134.22, 6.9872, 145.464, -89.9445, 6.9872, 169.13, -133.071, 9.1853, 143.744, -89.1527, 9.1853, 167.219, -88.1095, 10.9564, 164.7, -131.556, 10.9564, 141.477, -133.071, 9.1853, 143.744, -89.1527, 9.1853, 167.219, -131.556, 10.9564, 141.477, -88.1095, 10.9564, 164.7, -86.8753, 12.1977, 161.721, -129.764, 12.1977, 138.796, -131.556, 10.9564, 141.477, -88.1095, 10.9564, 164.7, -129.764, 12.1977, 138.796, -86.8753, 12.1977, 161.721, -85.522, 12.8369, 158.454, -127.8, 12.8369, 135.856, -129.764, 12.1977, 138.796, -86.8753, 12.1977, 161.721, -127.8, 12.8369, 135.856, -85.522, 12.8369, 158.454, -84.1283, 12.8369, 155.089, -125.776, 12.8369, 132.827, -127.8, 12.8369, 135.856, -85.522, 12.8369, 158.454, -125.776, 12.8369, 132.827, -84.1283, 12.8369, 155.089, -82.775, 12.1977, 151.822, -123.812, 12.1977, 129.887, -125.776, 12.8369, 132.827, -84.1283, 12.8369, 155.089, -123.812, 12.1977, 129.887, -82.775, 12.1977, 151.822, -81.5408, 10.9564, 148.842, -122.02, 10.9564, 127.206, -123.812, 12.1977, 129.887, -82.775, 12.1977, 151.822, -122.02, 10.9564, 127.206, -81.5408, 10.9564, 148.842, -80.4976, 9.1853, 146.324, -120.505, 9.1853, 124.939, -122.02, 10.9564, 127.206, -81.5408, 10.9564, 148.842, -120.505, 9.1853, 124.939, -80.4976, 9.1853, 146.324, -79.7058, 6.9872, 144.412, -119.356, 6.9872, 123.219, -120.505, 9.1853, 124.939, -80.4976, 9.1853, 146.324, -119.356, 6.9872, 123.219, -79.7058, 6.9872, 144.412, -79.2116, 4.4899, 143.219, -118.638, 4.4899, 122.145, -119.356, 6.9872, 123.219, -79.7058, 6.9872, 144.412, -118.638, 4.4899, 122.145, -79.2116, 4.4899, 143.219, -79.0436, 1.8384, 142.813, -118.395, 1.8384, 121.78, -118.638, 4.4899, 122.145, -79.2116, 4.4899, 143.219, -118.395, 1.8384, 121.78, -79.0436, 1.8384, 142.813, -79.2116, -0.813, 143.219, -118.638, -0.813, 122.145, -118.395, 1.8384, 121.78, -79.0436, 1.8384, 142.813, -118.638, -0.813, 122.145, -79.2116, -0.813, 143.219, -79.7058, -3.3103, 144.412, -119.356, -3.3103, 123.219, -118.638, -0.813, 122.145, -79.2116, -0.813, 143.219, -119.356, -3.3103, 123.219, -79.7058, -3.3103, 144.412, -80.4976, -5.5084, 146.324, -120.505, -5.5084, 124.939, -119.356, -3.3103, 123.219, -79.7058, -3.3103, 144.412, -120.505, -5.5084, 124.939, -80.4976, -5.5084, 146.324, -81.5408, -7.2796, 148.842, -122.02, -7.2796, 127.206, -120.505, -5.5084, 124.939, -80.4976, -5.5084, 146.324, -122.02, -7.2796, 127.206, -81.5408, -7.2796, 148.842, -82.775, -8.5208, 151.822, -123.812, -8.5208, 129.887, -122.02, -7.2796, 127.206, -81.5408, -7.2796, 148.842, -123.812, -8.5208, 129.887, -82.775, -8.5208, 151.822, -84.1283, -9.16, 155.089, -125.776, -9.16, 132.827, -123.812, -8.5208, 129.887, -82.775, -8.5208, 151.822, -125.776, -9.16, 132.827, -84.1283, -9.16, 155.089, -85.522, -9.16, 158.454, -127.8, -9.16, 135.856, -125.776, -9.16, 132.827, -84.1283, -9.16, 155.089, -127.8, -9.16, 135.856, -85.522, -9.16, 158.454, -86.8753, -8.5208, 161.721, -129.764, -8.5208, 138.796, -127.8, -9.16, 135.856, -85.522, -9.16, 158.454, -129.764, -8.5208, 138.796, -86.8753, -8.5208, 161.721, -88.1095, -7.2796, 164.7, -131.556, -7.2796, 141.477, -129.764, -8.5208, 138.796, -86.8753, -8.5208, 161.721, -131.556, -7.2796, 141.477, -88.1095, -7.2796, 164.7, -89.1527, -5.5084, 167.219, -133.071, -5.5084, 143.744, -131.556, -7.2796, 141.477, -88.1095, -7.2796, 164.7, -133.071, -5.5084, 143.744, -89.1527, -5.5084, 167.219, -89.9445, -3.3103, 169.13, -134.22, -3.3103, 145.464, -133.071, -5.5084, 143.744, -89.1527, -5.5084, 167.219, -134.22, -3.3103, 145.464, -89.9445, -3.3103, 169.13, -90.4387, -0.813, 170.324, -134.938, -0.813, 146.538, -134.22, -3.3103, 145.464, -89.9445, -3.3103, 169.13, -134.938, -0.813, 146.538, -90.4387, -0.813, 170.324, -90.6067, 1.8384, 170.729, -135.182, 1.8384, 146.903, -134.938, -0.813, 146.538, -90.4387, -0.813, 170.324, -135.182, 1.8384, 146.903, -135.182, 1.8384, 146.903, -134.938, 4.4899, 146.538, -173.942, 4.4899, 114.529, -174.252, 1.8384, 114.839, -135.182, 1.8384, 146.903, -173.942, 4.4899, 114.529, -134.938, 4.4899, 146.538, -134.22, 6.9872, 145.464, -173.028, 6.9872, 113.616, -173.942, 4.4899, 114.529, -134.938, 4.4899, 146.538, -173.028, 6.9872, 113.616, -134.22, 6.9872, 145.464, -133.071, 9.1853, 143.744, -171.565, 9.1853, 112.153, -173.028, 6.9872, 113.616, -134.22, 6.9872, 145.464, -171.565, 9.1853, 112.153, -133.071, 9.1853, 143.744, -131.556, 10.9564, 141.477, -169.638, 10.9564, 110.225, -171.565, 9.1853, 112.153, -133.071, 9.1853, 143.744, -169.638, 10.9564, 110.225, -131.556, 10.9564, 141.477, -129.764, 12.1977, 138.796, -167.357, 12.1977, 107.944, -169.638, 10.9564, 110.225, -131.556, 10.9564, 141.477, -167.357, 12.1977, 107.944, -129.764, 12.1977, 138.796, -127.8, 12.8369, 135.856, -164.857, 12.8369, 105.444, -167.357, 12.1977, 107.944, -129.764, 12.1977, 138.796, -164.857, 12.8369, 105.444, -127.8, 12.8369, 135.856, -125.776, 12.8369, 132.827, -162.281, 12.8369, 102.869, -164.857, 12.8369, 105.444, -127.8, 12.8369, 135.856, -162.281, 12.8369, 102.869, -125.776, 12.8369, 132.827, -123.812, 12.1977, 129.887, -159.781, 12.1977, 100.368, -162.281, 12.8369, 102.869, -125.776, 12.8369, 132.827, -159.781, 12.1977, 100.368, -123.812, 12.1977, 129.887, -122.02, 10.9564, 127.206, -157.5, 10.9564, 98.0877, -159.781, 12.1977, 100.368, -123.812, 12.1977, 129.887, -157.5, 10.9564, 98.0877, -122.02, 10.9564, 127.206, -120.505, 9.1853, 124.939, -155.573, 9.1853, 96.1599, -157.5, 10.9564, 98.0877, -122.02, 10.9564, 127.206, -155.573, 9.1853, 96.1599, -120.505, 9.1853, 124.939, -119.356, 6.9872, 123.219, -154.11, 6.9872, 94.697, -155.573, 9.1853, 96.1599, -120.505, 9.1853, 124.939, -154.11, 6.9872, 94.697, -119.356, 6.9872, 123.219, -118.638, 4.4899, 122.145, -153.197, 4.4899, 93.7837, -154.11, 6.9872, 94.697, -119.356, 6.9872, 123.219, -153.197, 4.4899, 93.7837, -118.638, 4.4899, 122.145, -118.395, 1.8384, 121.78, -152.886, 1.8384, 93.4733, -153.197, 4.4899, 93.7837, -118.638, 4.4899, 122.145, -152.886, 1.8384, 93.4733, -118.395, 1.8384, 121.78, -118.638, -0.813, 122.145, -153.197, -0.813, 93.7837, -152.886, 1.8384, 93.4733, -118.395, 1.8384, 121.78, -153.197, -0.813, 93.7837, -118.638, -0.813, 122.145, -119.356, -3.3103, 123.219, -154.11, -3.3103, 94.697, -153.197, -0.813, 93.7837, -118.638, -0.813, 122.145, -154.11, -3.3103, 94.697, -119.356, -3.3103, 123.219, -120.505, -5.5084, 124.939, -155.573, -5.5084, 96.1599, -154.11, -3.3103, 94.697, -119.356, -3.3103, 123.219, -155.573, -5.5084, 96.1599, -120.505, -5.5084, 124.939, -122.02, -7.2796, 127.206, -157.5, -7.2796, 98.0877, -155.573, -5.5084, 96.1599, -120.505, -5.5084, 124.939, -157.5, -7.2796, 98.0877, -122.02, -7.2796, 127.206, -123.812, -8.5208, 129.887, -159.781, -8.5208, 100.368, -157.5, -7.2796, 98.0877, -122.02, -7.2796, 127.206, -159.781, -8.5208, 100.368, -123.812, -8.5208, 129.887, -125.776, -9.16, 132.827, -162.281, -9.16, 102.869, -159.781, -8.5208, 100.368, -123.812, -8.5208, 129.887, -162.281, -9.16, 102.869, -125.776, -9.16, 132.827, -127.8, -9.16, 135.856, -164.857, -9.16, 105.444, -162.281, -9.16, 102.869, -125.776, -9.16, 132.827, -164.857, -9.16, 105.444, -127.8, -9.16, 135.856, -129.764, -8.5208, 138.796, -167.357, -8.5208, 107.944, -164.857, -9.16, 105.444, -127.8, -9.16, 135.856, -167.357, -8.5208, 107.944, -129.764, -8.5208, 138.796, -131.556, -7.2796, 141.477, -169.638, -7.2796, 110.225, -167.357, -8.5208, 107.944, -129.764, -8.5208, 138.796, -169.638, -7.2796, 110.225, -131.556, -7.2796, 141.477, -133.071, -5.5084, 143.744, -171.565, -5.5084, 112.153, -169.638, -7.2796, 110.225, -131.556, -7.2796, 141.477, -171.565, -5.5084, 112.153, -133.071, -5.5084, 143.744, -134.22, -3.3103, 145.464, -173.028, -3.3103, 113.616, -171.565, -5.5084, 112.153, -133.071, -5.5084, 143.744, -173.028, -3.3103, 113.616, -134.22, -3.3103, 145.464, -134.938, -0.813, 146.538, -173.942, -0.813, 114.529, -173.028, -3.3103, 113.616, -134.22, -3.3103, 145.464, -173.942, -0.813, 114.529, -134.938, -0.813, 146.538, -135.182, 1.8384, 146.903, -174.252, 1.8384, 114.839, -173.942, -0.813, 114.529, -134.938, -0.813, 146.538, -174.252, 1.8384, 114.839, -174.252, 1.8384, 114.839, -173.942, 4.4899, 114.529, -205.951, 4.4899, 75.525, -206.316, 1.8384, 75.7689, -174.252, 1.8384, 114.839, -205.951, 4.4899, 75.525, -173.942, 4.4899, 114.529, -173.028, 6.9872, 113.616, -204.877, 6.9872, 74.8075, -205.951, 4.4899, 75.525, -173.942, 4.4899, 114.529, -204.877, 6.9872, 74.8075, -173.028, 6.9872, 113.616, -171.565, 9.1853, 112.153, -203.157, 9.1853, 73.6581, -204.877, 6.9872, 74.8075, -173.028, 6.9872, 113.616, -203.157, 9.1853, 73.6581, -171.565, 9.1853, 112.153, -169.638, 10.9564, 110.225, -200.89, 10.9564, 72.1435, -203.157, 9.1853, 73.6581, -171.565, 9.1853, 112.153, -200.89, 10.9564, 72.1435, -169.638, 10.9564, 110.225, -167.357, 12.1977, 107.944, -198.209, 12.1977, 70.3518, -200.89, 10.9564, 72.1435, -169.638, 10.9564, 110.225, -198.209, 12.1977, 70.3518, -167.357, 12.1977, 107.944, -164.857, 12.8369, 105.444, -195.268, 12.8369, 68.3871, -198.209, 12.1977, 70.3518, -167.357, 12.1977, 107.944, -195.268, 12.8369, 68.3871, -164.857, 12.8369, 105.444, -162.281, 12.8369, 102.869, -192.24, 12.8369, 66.3636, -195.268, 12.8369, 68.3871, -164.857, 12.8369, 105.444, -192.24, 12.8369, 66.3636, -162.281, 12.8369, 102.869, -159.781, 12.1977, 100.368, -189.3, 12.1977, 64.399, -192.24, 12.8369, 66.3636, -162.281, 12.8369, 102.869, -189.3, 12.1977, 64.399, -159.781, 12.1977, 100.368, -157.5, 10.9564, 98.0877, -186.618, 10.9564, 62.6073, -189.3, 12.1977, 64.399, -159.781, 12.1977, 100.368, -186.618, 10.9564, 62.6073, -157.5, 10.9564, 98.0877, -155.573, 9.1853, 96.1599, -184.352, 9.1853, 61.0927, -186.618, 10.9564, 62.6073, -157.5, 10.9564, 98.0877, -184.352, 9.1853, 61.0927, -155.573, 9.1853, 96.1599, -154.11, 6.9872, 94.697, -182.631, 6.9872, 59.9433, -184.352, 9.1853, 61.0927, -155.573, 9.1853, 96.1599, -182.631, 6.9872, 59.9433, -154.11, 6.9872, 94.697, -153.197, 4.4899, 93.7837, -181.557, 4.4899, 59.2257, -182.631, 6.9872, 59.9433, -154.11, 6.9872, 94.697, -181.557, 4.4899, 59.2257, -153.197, 4.4899, 93.7837, -152.886, 1.8384, 93.4733, -181.192, 1.8384, 58.9818, -181.557, 4.4899, 59.2257, -153.197, 4.4899, 93.7837, -181.192, 1.8384, 58.9818, -152.886, 1.8384, 93.4733, -153.197, -0.813, 93.7837, -181.557, -0.813, 59.2257, -181.192, 1.8384, 58.9818, -152.886, 1.8384, 93.4733, -181.557, -0.813, 59.2257, -153.197, -0.813, 93.7837, -154.11, -3.3103, 94.697, -182.631, -3.3103, 59.9433, -181.557, -0.813, 59.2257, -153.197, -0.813, 93.7837, -182.631, -3.3103, 59.9433, -154.11, -3.3103, 94.697, -155.573, -5.5084, 96.1599, -184.352, -5.5084, 61.0927, -182.631, -3.3103, 59.9433, -154.11, -3.3103, 94.697, -184.352, -5.5084, 61.0927, -155.573, -5.5084, 96.1599, -157.5, -7.2796, 98.0877, -186.618, -7.2796, 62.6073, -184.352, -5.5084, 61.0927, -155.573, -5.5084, 96.1599, -186.618, -7.2796, 62.6073, -157.5, -7.2796, 98.0877, -159.781, -8.5208, 100.368, -189.3, -8.5208, 64.399, -186.618, -7.2796, 62.6073, -157.5, -7.2796, 98.0877, -189.3, -8.5208, 64.399, -159.781, -8.5208, 100.368, -162.281, -9.16, 102.869, -192.24, -9.16, 66.3636, -189.3, -8.5208, 64.399, -159.781, -8.5208, 100.368, -192.24, -9.16, 66.3636, -162.281, -9.16, 102.869, -164.857, -9.16, 105.444, -195.268, -9.16, 68.3871, -192.24, -9.16, 66.3636, -162.281, -9.16, 102.869, -195.268, -9.16, 68.3871, -164.857, -9.16, 105.444, -167.357, -8.5208, 107.944, -198.209, -8.5208, 70.3518, -195.268, -9.16, 68.3871, -164.857, -9.16, 105.444, -198.209, -8.5208, 70.3518, -167.357, -8.5208, 107.944, -169.638, -7.2796, 110.225, -200.89, -7.2796, 72.1435, -198.209, -8.5208, 70.3518, -167.357, -8.5208, 107.944, -200.89, -7.2796, 72.1435, -169.638, -7.2796, 110.225, -171.565, -5.5084, 112.153, -203.157, -5.5084, 73.6581, -200.89, -7.2796, 72.1435, -169.638, -7.2796, 110.225, -203.157, -5.5084, 73.6581, -171.565, -5.5084, 112.153, -173.028, -3.3103, 113.616, -204.877, -3.3103, 74.8075, -203.157, -5.5084, 73.6581, -171.565, -5.5084, 112.153, -204.877, -3.3103, 74.8075, -173.028, -3.3103, 113.616, -173.942, -0.813, 114.529, -205.951, -0.813, 75.525, -204.877, -3.3103, 74.8075, -173.028, -3.3103, 113.616, -205.951, -0.813, 75.525, -173.942, -0.813, 114.529, -174.252, 1.8384, 114.839, -206.316, 1.8384, 75.7689, -205.951, -0.813, 75.525, -173.942, -0.813, 114.529, -206.316, 1.8384, 75.7689, -206.316, 1.8384, 75.7689, -205.951, 4.4899, 75.525, -229.736, 4.4899, 31.026, -230.142, 1.8384, 31.194, -206.316, 1.8384, 75.7689, -229.736, 4.4899, 31.026, -205.951, 4.4899, 75.525, -204.877, 6.9872, 74.8075, -228.543, 6.9872, 30.5317, -229.736, 4.4899, 31.026, -205.951, 4.4899, 75.525, -228.543, 6.9872, 30.5317, -204.877, 6.9872, 74.8075, -203.157, 9.1853, 73.6581, -226.632, 9.1853, 29.74, -228.543, 6.9872, 30.5317, -204.877, 6.9872, 74.8075, -226.632, 9.1853, 29.74, -203.157, 9.1853, 73.6581, -200.89, 10.9564, 72.1435, -224.113, 10.9564, 28.6967, -226.632, 9.1853, 29.74, -203.157, 9.1853, 73.6581, -224.113, 10.9564, 28.6967, -200.89, 10.9564, 72.1435, -198.209, 12.1977, 70.3518, -221.134, 12.1977, 27.4626, -224.113, 10.9564, 28.6967, -200.89, 10.9564, 72.1435, -221.134, 12.1977, 27.4626, -198.209, 12.1977, 70.3518, -195.268, 12.8369, 68.3871, -217.866, 12.8369, 26.1093, -221.134, 12.1977, 27.4626, -198.209, 12.1977, 70.3518, -217.866, 12.8369, 26.1093, -195.268, 12.8369, 68.3871, -192.24, 12.8369, 66.3636, -214.501, 12.8369, 24.7155, -217.866, 12.8369, 26.1093, -195.268, 12.8369, 68.3871, -214.501, 12.8369, 24.7155, -192.24, 12.8369, 66.3636, -189.3, 12.1977, 64.399, -211.234, 12.1977, 23.3622, -214.501, 12.8369, 24.7155, -192.24, 12.8369, 66.3636, -211.234, 12.1977, 23.3622, -189.3, 12.1977, 64.399, -186.618, 10.9564, 62.6073, -208.255, 10.9564, 22.1281, -211.234, 12.1977, 23.3622, -189.3, 12.1977, 64.399, -208.255, 10.9564, 22.1281, -186.618, 10.9564, 62.6073, -184.352, 9.1853, 61.0927, -205.736, 9.1853, 21.0848, -208.255, 10.9564, 22.1281, -186.618, 10.9564, 62.6073, -205.736, 9.1853, 21.0848, -184.352, 9.1853, 61.0927, -182.631, 6.9872, 59.9433, -203.825, 6.9872, 20.2931, -205.736, 9.1853, 21.0848, -184.352, 9.1853, 61.0927, -203.825, 6.9872, 20.2931, -182.631, 6.9872, 59.9433, -181.557, 4.4899, 59.2257, -202.632, 4.4899, 19.7988, -203.825, 6.9872, 20.2931, -182.631, 6.9872, 59.9433, -202.632, 4.4899, 19.7988, -181.557, 4.4899, 59.2257, -181.192, 1.8384, 58.9818, -202.226, 1.8384, 19.6308, -202.632, 4.4899, 19.7988, -181.557, 4.4899, 59.2257, -202.226, 1.8384, 19.6308, -181.192, 1.8384, 58.9818, -181.557, -0.813, 59.2257, -202.632, -0.813, 19.7988, -202.226, 1.8384, 19.6308, -181.192, 1.8384, 58.9818, -202.632, -0.813, 19.7988, -181.557, -0.813, 59.2257, -182.631, -3.3103, 59.9433, -203.825, -3.3103, 20.2931, -202.632, -0.813, 19.7988, -181.557, -0.813, 59.2257, -203.825, -3.3103, 20.2931, -182.631, -3.3103, 59.9433, -184.352, -5.5084, 61.0927, -205.736, -5.5084, 21.0848, -203.825, -3.3103, 20.2931, -182.631, -3.3103, 59.9433, -205.736, -5.5084, 21.0848, -184.352, -5.5084, 61.0927, -186.618, -7.2796, 62.6073, -208.255, -7.2796, 22.1281, -205.736, -5.5084, 21.0848, -184.352, -5.5084, 61.0927, -208.255, -7.2796, 22.1281, -186.618, -7.2796, 62.6073, -189.3, -8.5208, 64.399, -211.234, -8.5208, 23.3622, -208.255, -7.2796, 22.1281, -186.618, -7.2796, 62.6073, -211.234, -8.5208, 23.3622, -189.3, -8.5208, 64.399, -192.24, -9.16, 66.3636, -214.501, -9.16, 24.7155, -211.234, -8.5208, 23.3622, -189.3, -8.5208, 64.399, -214.501, -9.16, 24.7155, -192.24, -9.16, 66.3636, -195.268, -9.16, 68.3871, -217.866, -9.16, 26.1093, -214.501, -9.16, 24.7155, -192.24, -9.16, 66.3636, -217.866, -9.16, 26.1093, -195.268, -9.16, 68.3871, -198.209, -8.5208, 70.3518, -221.134, -8.5208, 27.4626, -217.866, -9.16, 26.1093, -195.268, -9.16, 68.3871, -221.134, -8.5208, 27.4626, -198.209, -8.5208, 70.3518, -200.89, -7.2796, 72.1435, -224.113, -7.2796, 28.6967, -221.134, -8.5208, 27.4626, -198.209, -8.5208, 70.3518, -224.113, -7.2796, 28.6967, -200.89, -7.2796, 72.1435, -203.157, -5.5084, 73.6581, -226.632, -5.5084, 29.74, -224.113, -7.2796, 28.6967, -200.89, -7.2796, 72.1435, -226.632, -5.5084, 29.74, -203.157, -5.5084, 73.6581, -204.877, -3.3103, 74.8075, -228.543, -3.3103, 30.5317, -226.632, -5.5084, 29.74, -203.157, -5.5084, 73.6581, -228.543, -3.3103, 30.5317, -204.877, -3.3103, 74.8075, -205.951, -0.813, 75.525, -229.736, -0.813, 31.026, -228.543, -3.3103, 30.5317, -204.877, -3.3103, 74.8075, -229.736, -0.813, 31.026, -205.951, -0.813, 75.525, -206.316, 1.8384, 75.7689, -230.142, 1.8384, 31.194, -229.736, -0.813, 31.026, -205.951, -0.813, 75.525, -230.142, 1.8384, 31.194, -230.142, 1.8384, 31.194, -229.736, 4.4899, 31.026, -244.383, 4.4899, -17.2583, -244.814, 1.8384, -17.1727, -230.142, 1.8384, 31.194, -244.383, 4.4899, -17.2583, -229.736, 4.4899, 31.026, -228.543, 6.9872, 30.5317, -243.117, 6.9872, -17.5103, -244.383, 4.4899, -17.2583, -229.736, 4.4899, 31.026, -243.117, 6.9872, -17.5103, -228.543, 6.9872, 30.5317, -226.632, 9.1853, 29.74, -241.087, 9.1853, -17.9139, -243.117, 6.9872, -17.5103, -228.543, 6.9872, 30.5317, -241.087, 9.1853, -17.9139, -226.632, 9.1853, 29.74, -224.113, 10.9564, 28.6967, -238.413, 10.9564, -18.4458, -241.087, 9.1853, -17.9139, -226.632, 9.1853, 29.74, -238.413, 10.9564, -18.4458, -224.113, 10.9564, 28.6967, -221.134, 12.1977, 27.4626, -235.251, 12.1977, -19.0749, -238.413, 10.9564, -18.4458, -224.113, 10.9564, 28.6967, -235.251, 12.1977, -19.0749, -221.134, 12.1977, 27.4626, -217.866, 12.8369, 26.1093, -231.782, 12.8369, -19.7648, -235.251, 12.1977, -19.0749, -221.134, 12.1977, 27.4626, -231.782, 12.8369, -19.7648, -217.866, 12.8369, 26.1093, -214.501, 12.8369, 24.7155, -228.21, 12.8369, -20.4754, -231.782, 12.8369, -19.7648, -217.866, 12.8369, 26.1093, -228.21, 12.8369, -20.4754, -214.501, 12.8369, 24.7155, -211.234, 12.1977, 23.3622, -224.742, 12.1977, -21.1653, -228.21, 12.8369, -20.4754, -214.501, 12.8369, 24.7155, -224.742, 12.1977, -21.1653, -211.234, 12.1977, 23.3622, -208.255, 10.9564, 22.1281, -221.579, 10.9564, -21.7944, -224.742, 12.1977, -21.1653, -211.234, 12.1977, 23.3622, -221.579, 10.9564, -21.7944, -208.255, 10.9564, 22.1281, -205.736, 9.1853, 21.0848, -218.905, 9.1853, -22.3263, -221.579, 10.9564, -21.7944, -208.255, 10.9564, 22.1281, -218.905, 9.1853, -22.3263, -205.736, 9.1853, 21.0848, -203.825, 6.9872, 20.2931, -216.876, 6.9872, -22.7299, -218.905, 9.1853, -22.3263, -205.736, 9.1853, 21.0848, -216.876, 6.9872, -22.7299, -203.825, 6.9872, 20.2931, -202.632, 4.4899, 19.7988, -215.609, 4.4899, -22.9819, -216.876, 6.9872, -22.7299, -203.825, 6.9872, 20.2931, -215.609, 4.4899, -22.9819, -202.632, 4.4899, 19.7988, -202.226, 1.8384, 19.6308, -215.178, 1.8384, -23.0675, -215.609, 4.4899, -22.9819, -202.632, 4.4899, 19.7988, -215.178, 1.8384, -23.0675, -202.226, 1.8384, 19.6308, -202.632, -0.813, 19.7988, -215.609, -0.813, -22.9819, -215.178, 1.8384, -23.0675, -202.226, 1.8384, 19.6308, -215.609, -0.813, -22.9819, -202.632, -0.813, 19.7988, -203.825, -3.3103, 20.2931, -216.876, -3.3103, -22.7299, -215.609, -0.813, -22.9819, -202.632, -0.813, 19.7988, -216.876, -3.3103, -22.7299, -203.825, -3.3103, 20.2931, -205.736, -5.5084, 21.0848, -218.905, -5.5084, -22.3263, -216.876, -3.3103, -22.7299, -203.825, -3.3103, 20.2931, -218.905, -5.5084, -22.3263, -205.736, -5.5084, 21.0848, -208.255, -7.2796, 22.1281, -221.579, -7.2796, -21.7944, -218.905, -5.5084, -22.3263, -205.736, -5.5084, 21.0848, -221.579, -7.2796, -21.7944, -208.255, -7.2796, 22.1281, -211.234, -8.5208, 23.3622, -224.742, -8.5208, -21.1653, -221.579, -7.2796, -21.7944, -208.255, -7.2796, 22.1281, -224.742, -8.5208, -21.1653, -211.234, -8.5208, 23.3622, -214.501, -9.16, 24.7155, -228.21, -9.16, -20.4754, -224.742, -8.5208, -21.1653, -211.234, -8.5208, 23.3622, -228.21, -9.16, -20.4754, -214.501, -9.16, 24.7155, -217.866, -9.16, 26.1093, -231.782, -9.16, -19.7648, -228.21, -9.16, -20.4754, -214.501, -9.16, 24.7155, -231.782, -9.16, -19.7648, -217.866, -9.16, 26.1093, -221.134, -8.5208, 27.4626, -235.251, -8.5208, -19.0749, -231.782, -9.16, -19.7648, -217.866, -9.16, 26.1093, -235.251, -8.5208, -19.0749, -221.134, -8.5208, 27.4626, -224.113, -7.2796, 28.6967, -238.413, -7.2796, -18.4458, -235.251, -8.5208, -19.0749, -221.134, -8.5208, 27.4626, -238.413, -7.2796, -18.4458, -224.113, -7.2796, 28.6967, -226.632, -5.5084, 29.74, -241.087, -5.5084, -17.9139, -238.413, -7.2796, -18.4458, -224.113, -7.2796, 28.6967, -241.087, -5.5084, -17.9139, -226.632, -5.5084, 29.74, -228.543, -3.3103, 30.5317, -243.117, -3.3103, -17.5103, -241.087, -5.5084, -17.9139, -226.632, -5.5084, 29.74, -243.117, -3.3103, -17.5103, -228.543, -3.3103, 30.5317, -229.736, -0.813, 31.026, -244.383, -0.813, -17.2583, -243.117, -3.3103, -17.5103, -228.543, -3.3103, 30.5317, -244.383, -0.813, -17.2583, -229.736, -0.813, 31.026, -230.142, 1.8384, 31.194, -244.814, 1.8384, -17.1727, -244.383, -0.813, -17.2583, -229.736, -0.813, 31.026, -244.814, 1.8384, -17.1727, -247.775, 3.5774, -50.1623, -244.814, 1.8384, -17.1727, -247.623, 4.4899, -50.1529, -244.814, 1.8384, -17.1727, -244.383, 4.4899, -17.2583, -247.623, 4.4899, -50.1529, -248.065, 1.8384, -50.1802, -244.814, 1.8384, -17.1727, -247.775, 3.5774, -50.1623, -246.773, 6.1232, -50.1002, -244.383, 4.4899, -17.2583, -246.324, 6.9872, -50.0723, -244.383, 4.4899, -17.2583, -243.117, 6.9872, -17.5103, -246.324, 6.9872, -50.0723, -247.623, 4.4899, -50.1529, -244.383, 4.4899, -17.2583, -246.773, 6.1232, -50.1002, -244.97, 8.4161, -49.9884, -243.117, 6.9872, -17.5103, -244.242, 9.1853, -49.9432, -243.117, 6.9872, -17.5103, -241.087, 9.1853, -17.9139, -244.242, 9.1853, -49.9432, -246.324, 6.9872, -50.0723, -243.117, 6.9872, -17.5103, -244.97, 8.4161, -49.9884, -242.475, 10.3261, -49.8337, -241.087, 9.1853, -17.9139, -241.499, 10.9564, -49.7731, -241.087, 9.1853, -17.9139, -238.413, 10.9564, -18.4458, -241.499, 10.9564, -49.7731, -244.242, 9.1853, -49.9432, -241.087, 9.1853, -17.9139, -242.475, 10.3261, -49.8337, -239.434, 11.7463, -49.6451, -238.413, 10.9564, -18.4458, -238.254, 12.1977, -49.572, -238.413, 10.9564, -18.4458, -235.251, 12.1977, -19.0749, -238.254, 12.1977, -49.572, -241.499, 10.9564, -49.7731, -238.413, 10.9564, -18.4458, -239.434, 11.7463, -49.6451, -236.022, 12.5986, -49.4336, -235.251, 12.1977, -19.0749, -234.696, 12.8369, -49.3513, -235.251, 12.1977, -19.0749, -231.782, 12.8369, -19.7648, -234.696, 12.8369, -49.3513, -238.254, 12.1977, -49.572, -235.251, 12.1977, -19.0749, -236.022, 12.5986, -49.4336, -232.434, 12.8369, -49.2111, -231.782, 12.8369, -19.7648, -231.032, 12.8369, -49.1241, -231.782, 12.8369, -19.7648, -228.21, 12.8369, -20.4754, -231.032, 12.8369, -49.1241, -234.696, 12.8369, -49.3513, -231.782, 12.8369, -19.7648, -232.434, 12.8369, -49.2111, -228.873, 12.449, -48.9903, -228.21, 12.8369, -20.4754, -227.474, 12.1977, -48.9035, -228.21, 12.8369, -20.4754, -224.742, 12.1977, -21.1653, -227.474, 12.1977, -48.9035, -231.032, 12.8369, -49.1241, -228.21, 12.8369, -20.4754, -228.873, 12.449, -48.9903, -225.538, 11.4574, -48.7835, -224.742, 12.1977, -21.1653, -224.229, 10.9564, -48.7023, -224.742, 12.1977, -21.1653, -221.579, 10.9564, -21.7944, -224.229, 10.9564, -48.7023, -227.474, 12.1977, -48.9035, -224.742, 12.1977, -21.1653, -225.538, 11.4574, -48.7835, -222.619, 9.917, -48.6025, -221.579, 10.9564, -21.7944, -221.486, 9.1853, -48.5323, -221.579, 10.9564, -21.7944, -218.905, 9.1853, -22.3263, -221.486, 9.1853, -48.5323, -224.229, 10.9564, -48.7023, -221.579, 10.9564, -21.7944, -222.619, 9.917, -48.6025, -220.281, 7.913, -48.4576, -218.905, 9.1853, -22.3263, -219.404, 6.9872, -48.4032, -218.905, 9.1853, -22.3263, -216.876, 6.9872, -22.7299, -219.404, 6.9872, -48.4032, -221.486, 9.1853, -48.5323, -218.905, 9.1853, -22.3263, -220.281, 7.913, -48.4576, -218.66, 5.5568, -48.357, -216.876, 6.9872, -22.7299, -218.105, 4.4899, -48.3226, -216.876, 6.9872, -22.7299, -215.609, 4.4899, -22.9819, -218.105, 4.4899, -48.3226, -219.404, 6.9872, -48.4032, -216.876, 6.9872, -22.7299, -218.66, 5.5568, -48.357, -217.853, 2.9806, -48.307, -215.609, 4.4899, -22.9819, -217.663, 1.8384, -48.2952, -215.609, 4.4899, -22.9819, -215.178, 1.8384, -23.0675, -217.663, 1.8384, -48.2952, -218.105, 4.4899, -48.3226, -215.609, 4.4899, -22.9819, -217.853, 2.9806, -48.307, -217.914, 0.3311, -48.3108, -215.178, 1.8384, -23.0675, -218.105, -0.813, -48.3226, -215.178, 1.8384, -23.0675, -215.609, -0.813, -22.9819, -218.105, -0.813, -48.3226, -217.663, 1.8384, -48.2952, -215.178, 1.8384, -23.0675, -217.914, 0.3311, -48.3108, -218.846, -2.238, -48.3686, -215.609, -0.813, -22.9819, -219.404, -3.3103, -48.4032, -215.609, -0.813, -22.9819, -216.876, -3.3103, -22.7299, -219.404, -3.3103, -48.4032, -218.105, -0.813, -48.3226, -215.609, -0.813, -22.9819, -218.846, -2.238, -48.3686, -220.602, -4.5753, -48.4775, -216.876, -3.3103, -22.7299, -221.486, -5.5084, -48.5323, -216.876, -3.3103, -22.7299, -218.905, -5.5084, -22.3263, -221.486, -5.5084, -48.5323, -219.404, -3.3103, -48.4032, -216.876, -3.3103, -22.7299, -220.602, -4.5753, -48.4775, -223.084, -6.5404, -48.6314, -218.905, -5.5084, -22.3263, -224.229, -7.2796, -48.7023, -218.905, -5.5084, -22.3263, -221.579, -7.2796, -21.7944, -224.229, -7.2796, -48.7023, -221.486, -5.5084, -48.5323, -218.905, -5.5084, -22.3263, -223.084, -6.5404, -48.6314, -226.149, -8.014, -48.8214, -221.579, -7.2796, -21.7944, -227.474, -8.5208, -48.9035, -221.579, -7.2796, -21.7944, -224.742, -8.5208, -21.1653, -227.474, -8.5208, -48.9035, -224.229, -7.2796, -48.7023, -221.579, -7.2796, -21.7944, -226.149, -8.014, -48.8214, -229.615, -8.9055, -49.0363, -224.742, -8.5208, -21.1653, -231.032, -9.16, -49.1241, -224.742, -8.5208, -21.1653, -228.21, -9.16, -20.4754, -231.032, -9.16, -49.1241, -227.474, -8.5208, -48.9035, -224.742, -8.5208, -21.1653, -229.615, -8.9055, -49.0363, -233.276, -9.16, -49.2633, -228.21, -9.16, -20.4754, -234.696, -9.16, -49.3514, -228.21, -9.16, -20.4754, -231.782, -9.16, -19.7648, -234.696, -9.16, -49.3514, -231.032, -9.16, -49.1241, -228.21, -9.16, -20.4754, -233.276, -9.16, -49.2633, -236.913, -8.7617, -49.4888, -231.782, -9.16, -19.7648, -238.254, -8.5208, -49.572, -231.782, -9.16, -19.7648, -235.251, -8.5208, -19.0749, -238.254, -8.5208, -49.572, -234.696, -9.16, -49.3514, -231.782, -9.16, -19.7648, -236.913, -8.7617, -49.4888, -240.307, -7.7354, -49.6993, -235.251, -8.5208, -19.0749, -241.499, -7.2796, -49.7731, -235.251, -8.5208, -19.0749, -238.413, -7.2796, -18.4458, -241.499, -7.2796, -49.7731, -238.254, -8.5208, -49.572, -235.251, -8.5208, -19.0749, -240.307, -7.7354, -49.6993, -243.258, -6.1439, -49.8822, -238.413, -7.2796, -18.4458, -244.242, -5.5084, -49.9432, -238.413, -7.2796, -18.4458, -241.087, -5.5084, -17.9139, -244.242, -5.5084, -49.9432, -241.499, -7.2796, -49.7731, -238.413, -7.2796, -18.4458, -243.258, -6.1439, -49.8822, -245.591, -4.0841, -50.0268, -241.087, -5.5084, -17.9139, -246.324, -3.3103, -50.0723, -241.087, -5.5084, -17.9139, -243.117, -3.3103, -17.5103, -246.324, -3.3103, -50.0723, -244.242, -5.5084, -49.9432, -241.087, -5.5084, -17.9139, -245.591, -4.0841, -50.0268, -247.172, -1.6801, -50.1249, -243.117, -3.3103, -17.5103, -247.623, -0.813, -50.1528, -243.117, -3.3103, -17.5103, -244.383, -0.813, -17.2583, -247.623, -0.813, -50.1528, -246.324, -3.3103, -50.0723, -243.117, -3.3103, -17.5103, -247.172, -1.6801, -50.1249, -247.913, 0.9249, -50.1708, -244.383, -0.813, -17.2583, -248.065, 1.8384, -50.1802, -244.383, -0.813, -17.2583, -244.814, 1.8384, -17.1727, -248.065, 1.8384, -50.1802, -247.623, -0.813, -50.1528, -244.383, -0.813, -17.2583, -247.913, 0.9249, -50.1708, 252.823, -12.1253, -19.1234, 252.859, -12.1193, -19.1212, 267.292, 1.9054, -18.2263, 252.859, -12.1193, -19.1212, 257.538, -10.4722, -18.8311, 267.292, 1.9054, -18.2263, 257.538, -10.4722, -18.8311, 257.633, -10.4389, -18.8252, 267.292, 1.9054, -18.2263, 257.633, -10.4389, -18.8252, 261.546, -8.1137, -18.5826, 267.292, 1.9054, -18.2263, 261.546, -8.1137, -18.5826, 261.668, -8.0411, -18.575, 267.292, 1.9054, -18.2263, 261.668, -8.0411, -18.575, 264.614, -5.1782, -18.3923, 267.292, 1.9054, -18.2263, 264.614, -5.1782, -18.3923, 264.73, -5.0652, -18.3851, 267.292, 1.9054, -18.2263, 264.73, -5.0652, -18.3851, 266.56, -1.8284, -18.2717, 267.292, 1.9054, -18.2263, 267.263, 1.7469, -18.2281, 266.56, -1.8284, -18.2717, 266.642, -1.6842, -18.2666, 266.56, -1.8284, -18.2717, 267.263, 1.7469, -18.2281, 267.292, 1.9054, -18.2263, 236.638, 15.9302, -20.1269, 236.433, 15.8598, -20.1396, 241.88, 16.774, -19.8019, 242.014, 16.7956, -19.7936, 231.736, 14.2498, -20.4309, 247.505, 16.7956, -19.4531, 231.736, 14.2498, -20.4309, 242.014, 16.7956, -19.7936, 241.88, 16.774, -19.8019, 236.433, 15.8598, -20.1396, 231.736, 14.2498, -20.4309, 241.88, 16.774, -19.8019, 231.736, 14.2498, -20.4309, 231.497, 14.1113, -20.4457, 247.505, 16.7956, -19.4531, 247.551, 16.7956, -19.4503, 227.592, 11.8519, -20.6878, 250.357, 16.3438, -19.2763, 227.592, 11.8519, -20.6878, 247.551, 16.7956, -19.4503, 247.505, 16.7956, -19.4531, 231.497, 14.1113, -20.4457, 227.592, 11.8519, -20.6878, 247.505, 16.7956, -19.4531, 227.592, 11.8519, -20.6878, 227.367, 11.6395, -20.7018, 250.357, 16.3438, -19.2763, 224.447, 8.876, -20.8828, 252.892, 15.9187, -19.1192, 252.859, 15.9302, -19.1212, 224.447, 8.876, -20.8828, 252.859, 15.9302, -19.1212, 250.357, 16.3438, -19.2763, 227.367, 11.6395, -20.7018, 224.447, 8.876, -20.8828, 250.357, 16.3438, -19.2763, 257.633, 14.2498, -18.8252, 250.357, 12.3842, -19.2763, 257.712, 14.2028, -18.8203, 227.592, -8.0411, -20.6878, 227.872, -8.2033, -20.6705, 252.823, -12.1253, -19.1234, 227.872, -8.2033, -20.6705, 231.736, -10.4389, -20.4309, 252.823, -12.1253, -19.1234, 231.736, -10.4389, -20.4309, 232.001, -10.5298, -20.4144, 252.823, -12.1253, -19.1234, 232.001, -10.5298, -20.4144, 236.638, -12.1193, -20.1269, 252.823, -12.1253, -19.1234, 236.638, -12.1193, -20.1269, 236.848, -12.153, -20.1139, 252.823, -12.1253, -19.1234, 236.848, -12.153, -20.1139, 242.014, -12.9847, -19.7936, 252.823, -12.1253, -19.1234, 242.014, -12.9847, -19.7936, 242.142, -12.9847, -19.7857, 252.823, -12.1253, -19.1234, 242.142, -12.9847, -19.7857, 250.357, -12.5329, -19.2763, 252.823, -12.1253, -19.1234, 247.592, -12.9781, -19.4478, 242.142, -12.9847, -19.7857, 247.551, -12.9847, -19.4503, 242.142, -12.9847, -19.7857, 247.592, -12.9781, -19.4478, 250.357, -12.5329, -19.2763, 260.638, 4.4899, -18.6388, 260.65, 4.417, -18.6381, 266.642, 5.495, -18.2666, 266.67, 5.3424, -18.2649, 261.075, 1.8384, -18.6118, 267.292, 1.9054, -18.2263, 260.65, 4.417, -18.6381, 266.67, 5.3424, -18.2649, 266.642, 5.495, -18.2666, 261.075, 1.8384, -18.6118, 266.67, 5.3424, -18.2649, 260.65, 4.417, -18.6381, 264.802, 8.7484, -18.3807, 259.355, 6.9872, -18.7184, 266.642, 5.495, -18.2666, 259.355, 6.9872, -18.7184, 259.386, 6.9269, -18.7165, 266.642, 5.495, -18.2666, 259.386, 6.9269, -18.7165, 260.638, 4.4899, -18.6388, 266.642, 5.495, -18.2666, 261.76, 11.7626, -18.5693, 257.298, 9.1853, -18.8459, 264.73, 8.8761, -18.3851, 257.298, 9.1853, -18.8459, 257.337, 9.1441, -18.8435, 264.73, 8.8761, -18.3851, 259.355, 6.9872, -18.7184, 264.802, 8.7484, -18.3807, 264.73, 8.8761, -18.3851, 259.355, 6.9872, -18.7184, 264.73, 8.8761, -18.3851, 257.337, 9.1441, -18.8435, 257.712, 14.2028, -18.8203, 254.589, 10.9564, -19.014, 261.668, 11.852, -18.575, 254.589, 10.9564, -19.014, 254.62, 10.936, -19.012, 261.668, 11.852, -18.575, 257.298, 9.1853, -18.8459, 261.76, 11.7626, -18.5693, 261.668, 11.852, -18.575, 257.298, 9.1853, -18.8459, 261.668, 11.852, -18.575, 254.62, 10.936, -19.012, 250.357, 12.3842, -19.2763, 251.383, 12.1977, -19.2127, 257.712, 14.2028, -18.8203, 251.392, 12.1941, -19.2121, 257.712, 14.2028, -18.8203, 251.383, 12.1977, -19.2127, 257.712, 14.2028, -18.8203, 251.392, 12.1941, -19.2121, 254.589, 10.9564, -19.014, 251.383, -8.5208, -19.2127, 251.373, -8.5226, -19.2133, 252.823, -12.1253, -19.1234, 251.373, -8.5226, -19.2133, 250.357, -8.7074, -19.2763, 252.823, -12.1253, -19.1234, 254.551, -7.294, -19.0163, 252.823, -12.1253, -19.1234, 254.589, -7.2796, -19.0139, 252.823, -12.1253, -19.1234, 254.551, -7.294, -19.0163, 251.383, -8.5208, -19.2127, 267.292, 1.9054, -18.2263, 257.298, -5.5084, -18.8459, 252.823, -12.1253, -19.1234, 257.247, -5.5419, -18.8491, 252.823, -12.1253, -19.1234, 257.298, -5.5084, -18.8459, 252.823, -12.1253, -19.1234, 257.247, -5.5419, -18.8491, 254.589, -7.2796, -19.0139, 259.355, -3.3103, -18.7184, 259.305, -3.3636, -18.7215, 267.292, 1.9054, -18.2263, 257.298, -5.5084, -18.8459, 267.292, 1.9054, -18.2263, 259.305, -3.3636, -18.7215, 260.638, -0.813, -18.6388, 260.603, -0.8818, -18.641, 267.292, 1.9054, -18.2263, 260.603, -0.8818, -18.641, 259.355, -3.3103, -18.7184, 267.292, 1.9054, -18.2263, 261.075, 1.8384, -18.6118, 261.062, 1.7625, -18.6126, 267.292, 1.9054, -18.2263, 260.638, -0.813, -18.6388, 267.292, 1.9054, -18.2263, 261.062, 1.7625, -18.6126, 252.892, 15.9187, -19.1192, 247.801, 12.8368, -19.4348, 257.633, 14.2498, -18.8252, 250.357, 12.3842, -19.2763, 257.633, 14.2498, -18.8252, 247.801, 12.8368, -19.4348, 247.774, 12.8369, -19.4365, 252.892, 15.9187, -19.1192, 244.083, 12.8369, -19.6653, 252.892, 15.9187, -19.1192, 247.774, 12.8369, -19.4365, 247.801, 12.8368, -19.4348, 224.447, 8.876, -20.8828, 240.474, 12.1977, -19.8891, 252.892, 15.9187, -19.1192, 244.017, 12.8251, -19.6694, 252.892, 15.9187, -19.1192, 240.474, 12.1977, -19.8891, 252.892, 15.9187, -19.1192, 244.017, 12.8251, -19.6694, 244.083, 12.8369, -19.6653, 224.286, 8.6, -20.8928, 237.182, 10.9564, -20.0932, 224.447, 8.876, -20.8828, 224.447, 8.876, -20.8828, 240.377, 12.1612, -19.8951, 240.474, 12.1977, -19.8891, 240.377, 12.1612, -19.8951, 224.447, 8.876, -20.8828, 237.182, 10.9564, -20.0932, 222.483, 5.4951, -21.0046, 234.399, 9.1853, -20.2658, 224.286, 8.6, -20.8928, 234.399, 9.1853, -20.2658, 237.072, 10.8864, -20.1, 224.286, 8.6, -20.8928, 237.072, 10.8864, -20.1, 237.182, 10.9564, -20.0932, 224.286, 8.6, -20.8928, 222.425, 5.18, -21.0082, 232.287, 6.9872, -20.3967, 222.483, 5.4951, -21.0046, 222.483, 5.4951, -21.0046, 234.297, 9.0794, -20.2721, 234.399, 9.1853, -20.2658, 232.287, 6.9872, -20.3967, 234.297, 9.0794, -20.2721, 222.483, 5.4951, -21.0046, 221.816, 1.9054, -21.046, 230.969, 4.4899, -20.4785, 222.425, 5.18, -21.0082, 230.969, 4.4899, -20.4785, 232.215, 6.8504, -20.4012, 222.425, 5.18, -21.0082, 232.287, 6.9872, -20.3967, 222.425, 5.18, -21.0082, 232.215, 6.8504, -20.4012, 222.483, -1.6842, -21.0046, 230.521, 1.8384, -20.5062, 221.876, 1.5852, -21.0423, 230.521, 1.8384, -20.5062, 221.816, 1.9054, -21.046, 221.876, 1.5852, -21.0423, 230.521, 1.8384, -20.5062, 230.942, 4.3342, -20.4801, 221.816, 1.9054, -21.046, 230.969, 4.4899, -20.4785, 221.816, 1.9054, -21.046, 230.942, 4.3342, -20.4801, 224.447, -5.0652, -20.8828, 230.969, -0.813, -20.4785, 222.652, -1.975, -20.9941, 222.483, -1.6842, -21.0046, 230.547, 1.6799, -20.5046, 230.521, 1.8384, -20.5062, 230.969, -0.813, -20.4785, 222.483, -1.6842, -21.0046, 222.652, -1.975, -20.9941, 230.969, -0.813, -20.4785, 230.547, 1.6799, -20.5046, 222.483, -1.6842, -21.0046, 224.447, -5.0652, -20.8828, 231.045, -0.9577, -20.4737, 230.969, -0.813, -20.4785, 231.045, -0.9577, -20.4737, 224.447, -5.0652, -20.8828, 232.287, -3.3103, -20.3967, 227.592, -8.0411, -20.6878, 234.399, -5.5084, -20.2658, 224.694, -5.2991, -20.8675, 224.447, -5.0652, -20.8828, 232.4, -3.4277, -20.3897, 232.287, -3.3103, -20.3967, 234.399, -5.5084, -20.2658, 224.447, -5.0652, -20.8828, 224.694, -5.2991, -20.8675, 234.399, -5.5084, -20.2658, 232.4, -3.4277, -20.3897, 224.447, -5.0652, -20.8828, 227.592, -8.0411, -20.6878, 234.528, -5.5908, -20.2577, 234.399, -5.5084, -20.2658, 237.182, -7.2796, -20.0932, 234.528, -5.5908, -20.2577, 227.592, -8.0411, -20.6878, 252.823, -12.1253, -19.1234, 240.474, -8.5208, -19.8891, 227.592, -8.0411, -20.6878, 227.592, -8.0411, -20.6878, 237.306, -7.3265, -20.0855, 237.182, -7.2796, -20.0932, 240.474, -8.5208, -19.8891, 237.306, -7.3265, -20.0855, 227.592, -8.0411, -20.6878, 240.575, -8.5387, -19.8829, 252.823, -12.1253, -19.1234, 244.083, -9.16, -19.6653, 252.823, -12.1253, -19.1234, 240.575, -8.5387, -19.8829, 240.474, -8.5208, -19.8891, 247.827, -9.1555, -19.4332, 252.823, -12.1253, -19.1234, 250.357, -8.7074, -19.2763, 252.823, -12.1253, -19.1234, 247.827, -9.1555, -19.4332, 247.801, -9.16, -19.4348, 244.148, -9.16, -19.6613, 252.823, -12.1253, -19.1234, 247.801, -9.16, -19.4348, 252.823, -12.1253, -19.1234, 244.148, -9.16, -19.6613, 244.083, -9.16, -19.6653, -244.58, 14.2498, -49.9642, -231.093, 16.7956, -49.1279, -241.472, 15.3308, -49.7714, -244.58, 14.2498, -49.9642, -228.992, 16.7956, -48.9977, -231.093, 16.7956, -49.1279, -231.093, 16.7956, -49.1279, -239.748, 15.9302, -49.6646, -241.472, 15.3308, -49.7714, -231.093, 16.7956, -49.1279, -236.41, 16.4754, -49.4576, -239.748, 15.9302, -49.6646, -234.449, 16.7956, -49.336, -236.41, 16.4754, -49.4576, -231.093, 16.7956, -49.1279, -248.665, 11.8519, -50.2175, -225.816, 16.2769, -48.8008, -245.992, 13.4212, -50.0517, -248.665, 11.8519, -50.2175, -223.693, 15.9302, -48.6691, -225.816, 16.2769, -48.8008, -225.816, 16.2769, -48.8008, -244.58, 14.2498, -49.9642, -245.992, 13.4212, -50.0517, -228.992, 16.7956, -48.9977, -244.58, 14.2498, -49.9642, -225.816, 16.2769, -48.8008, -220.873, 14.9495, -48.4943, -248.665, 11.8519, -50.2175, -249.71, 10.8492, -50.2822, -223.693, 15.9302, -48.6691, -248.665, 11.8519, -50.2175, -220.873, 14.9495, -48.4943, -210.791, -3.5191, -47.8691, -213.383, -6.7031, -48.0298, -211.676, -5.0652, -47.924, -210.791, -3.5191, -47.8691, -214.776, -8.0411, -48.1162, -213.383, -6.7031, -48.0298, -209.741, -1.6842, -47.804, -217.071, -9.3881, -48.2585, -210.791, -3.5191, -47.8691, -209.438, -0.0308, -47.7852, -218.861, -10.4389, -48.3695, -209.741, -1.6842, -47.804, -217.071, -9.3881, -48.2585, -209.741, -1.6842, -47.804, -218.861, -10.4389, -48.3695, -214.776, -8.0411, -48.1162, -210.791, -3.5191, -47.8691, -217.071, -9.3881, -48.2585, -209.083, 1.9054, -47.7632, -221.644, -11.4067, -48.5421, -209.438, -0.0308, -47.7852, -209.385, 3.5542, -47.782, -223.693, -12.1193, -48.6691, -209.083, 1.9054, -47.7632, -221.644, -11.4067, -48.5421, -209.083, 1.9054, -47.7632, -223.693, -12.1193, -48.6691, -218.861, -10.4389, -48.3695, -209.438, -0.0308, -47.7852, -221.644, -11.4067, -48.5421, -210.619, 7.0285, -47.8585, -226.828, -12.6314, -48.8635, -209.741, 5.495, -47.804, -226.828, -12.6314, -48.8635, -209.385, 3.5542, -47.782, -209.741, 5.495, -47.804, -226.828, -12.6314, -48.8635, -223.693, -12.1193, -48.6691, -209.385, 3.5542, -47.782, -254.358, 1.9054, -50.5705, -237.755, -12.4449, -49.541, -234.449, -12.9847, -49.336, -254.358, 1.9054, -50.5705, -239.748, -12.1193, -49.6646, -237.755, -12.4449, -49.541, -254.358, 1.9054, -50.5705, -242.832, -11.0469, -49.8558, -239.748, -12.1193, -49.6646, -254.358, 1.9054, -50.5705, -244.58, -10.4389, -49.9642, -242.832, -11.0469, -49.8558, -254.358, 1.9054, -50.5705, -247.237, -8.8791, -50.129, -244.58, -10.4389, -49.9642, -254.358, 1.9054, -50.5705, -248.665, -8.0411, -50.2175, -247.237, -8.8791, -50.129, -254.358, 1.9054, -50.5705, -250.712, -6.0762, -50.3444, -248.665, -8.0411, -50.2175, -254.358, 1.9054, -50.5705, -251.765, -5.0652, -50.4097, -250.712, -6.0762, -50.3444, -254.358, 1.9054, -50.5705, -253.056, -2.8097, -50.4897, -251.765, -5.0652, -50.4097, -254.142, 0.7239, -50.557, -253.056, -2.8097, -50.4897, -254.358, 1.9054, -50.5705, -253.056, -2.8097, -50.4897, -254.142, 0.7239, -50.557, -253.7, -1.6842, -50.5297, -254.358, 1.9054, -50.5705, -247.623, 4.4899, -50.1529, -253.917, 4.3155, -50.5431, -254.358, 1.9054, -50.5705, -247.775, 3.5774, -50.1623, -247.623, 4.4899, -50.1529, -247.775, 3.5774, -50.1623, -254.358, 1.9054, -50.5705, -248.065, 1.8384, -50.1802, -253.7, 5.495, -50.5297, -246.324, 6.9872, -50.0723, -252.406, 7.7562, -50.4494, -253.917, 4.3155, -50.5431, -246.773, 6.1232, -50.1002, -253.7, 5.495, -50.5297, -246.324, 6.9872, -50.0723, -253.7, 5.495, -50.5297, -246.773, 6.1232, -50.1002, -247.623, 4.4899, -50.1529, -246.773, 6.1232, -50.1002, -253.917, 4.3155, -50.5431, -252.406, 7.7562, -50.4494, -244.242, 9.1853, -49.9432, -251.765, 8.8761, -50.4097, -246.324, 6.9872, -50.0723, -244.97, 8.4161, -49.9884, -252.406, 7.7562, -50.4494, -244.97, 8.4161, -49.9884, -244.242, 9.1853, -49.9432, -252.406, 7.7562, -50.4494, -251.765, 8.8761, -50.4097, -241.499, 10.9564, -49.7731, -249.71, 10.8492, -50.2822, -242.475, 10.3261, -49.8337, -241.499, 10.9564, -49.7731, -251.765, 8.8761, -50.4097, -242.475, 10.3261, -49.8337, -251.765, 8.8761, -50.4097, -244.242, 9.1853, -49.9432, -239.434, 11.7463, -49.6451, -249.71, 10.8492, -50.2822, -241.499, 10.9564, -49.7731, -249.71, 10.8492, -50.2822, -239.434, 11.7463, -49.6451, -238.254, 12.1977, -49.572, -249.71, 10.8492, -50.2822, -234.696, 12.8369, -49.3513, -220.873, 14.9495, -48.4943, -236.022, 12.5986, -49.4336, -249.71, 10.8492, -50.2822, -238.254, 12.1977, -49.572, -249.71, 10.8492, -50.2822, -236.022, 12.5986, -49.4336, -234.696, 12.8369, -49.3513, -220.873, 14.9495, -48.4943, -231.032, 12.8369, -49.1241, -218.861, 14.2498, -48.3695, -231.032, 12.8369, -49.1241, -220.873, 14.9495, -48.4943, -232.434, 12.8369, -49.2111, -234.696, 12.8369, -49.3513, -232.434, 12.8369, -49.2111, -220.873, 14.9495, -48.4943, -218.861, 14.2498, -48.3695, -227.474, 12.1977, -48.9035, -216.538, 12.8859, -48.2254, -218.861, 14.2498, -48.3695, -228.873, 12.449, -48.9903, -227.474, 12.1977, -48.9035, -231.032, 12.8369, -49.1241, -228.873, 12.449, -48.9903, -218.861, 14.2498, -48.3695, -216.538, 12.8859, -48.2254, -224.229, 10.9564, -48.7023, -214.776, 11.8519, -48.1162, -224.229, 10.9564, -48.7023, -216.538, 12.8859, -48.2254, -225.538, 11.4574, -48.7835, -227.474, 12.1977, -48.9035, -225.538, 11.4574, -48.7835, -216.538, 12.8859, -48.2254, -214.776, 11.8519, -48.1162, -221.486, 9.1853, -48.5323, -213.052, 10.1971, -48.0094, -214.776, 11.8519, -48.1162, -222.619, 9.917, -48.6025, -221.486, 9.1853, -48.5323, -224.229, 10.9564, -48.7023, -222.619, 9.917, -48.6025, -214.776, 11.8519, -48.1162, -211.676, 8.8761, -47.924, -219.404, 6.9872, -48.4032, -210.619, 7.0285, -47.8585, -213.052, 10.1971, -48.0094, -220.281, 7.913, -48.4576, -211.676, 8.8761, -47.924, -220.281, 7.913, -48.4576, -219.404, 6.9872, -48.4032, -211.676, 8.8761, -47.924, -221.486, 9.1853, -48.5323, -220.281, 7.913, -48.4576, -213.052, 10.1971, -48.0094, -210.619, 7.0285, -47.8585, -218.66, 5.5568, -48.357, -218.105, 4.4899, -48.3226, -218.66, 5.5568, -48.357, -210.619, 7.0285, -47.8585, -219.404, 6.9872, -48.4032, -217.853, 2.9806, -48.307, -210.619, 7.0285, -47.8585, -218.105, 4.4899, -48.3226, -210.619, 7.0285, -47.8585, -217.853, 2.9806, -48.307, -217.663, 1.8384, -48.2952, -217.914, 0.3311, -48.3108, -210.619, 7.0285, -47.8585, -217.663, 1.8384, -48.2952, -210.619, 7.0285, -47.8585, -217.914, 0.3311, -48.3108, -218.105, -0.813, -48.3226, -210.619, 7.0285, -47.8585, -219.404, -3.3103, -48.4032, -226.828, -12.6314, -48.8635, -210.619, 7.0285, -47.8585, -218.846, -2.238, -48.3686, -219.404, -3.3103, -48.4032, -218.846, -2.238, -48.3686, -210.619, 7.0285, -47.8585, -218.105, -0.813, -48.3226, -226.828, -12.6314, -48.8635, -221.486, -5.5084, -48.5323, -228.992, -12.9847, -48.9977, -220.602, -4.5753, -48.4775, -226.828, -12.6314, -48.8635, -219.404, -3.3103, -48.4032, -226.828, -12.6314, -48.8635, -220.602, -4.5753, -48.4775, -221.486, -5.5084, -48.5323, -223.084, -6.5404, -48.6314, -224.229, -7.2796, -48.7023, -228.992, -12.9847, -48.9977, -223.084, -6.5404, -48.6314, -228.992, -12.9847, -48.9977, -221.486, -5.5084, -48.5323, -228.992, -12.9847, -48.9977, -226.149, -8.014, -48.8214, -227.474, -8.5208, -48.9035, -226.149, -8.014, -48.8214, -228.992, -12.9847, -48.9977, -224.229, -7.2796, -48.7023, -229.615, -8.9055, -49.0363, -228.992, -12.9847, -48.9977, -227.474, -8.5208, -48.9035, -228.992, -12.9847, -48.9977, -229.615, -8.9055, -49.0363, -231.032, -9.16, -49.1241, -231.032, -9.16, -49.1241, -233.276, -9.16, -49.2633, -228.992, -12.9847, -48.9977, -233.276, -9.16, -49.2633, -234.696, -9.16, -49.3514, -228.992, -12.9847, -48.9977, -228.992, -12.9847, -48.9977, -238.254, -8.5208, -49.572, -232.31, -12.9847, -49.2034, -228.992, -12.9847, -48.9977, -236.913, -8.7617, -49.4888, -238.254, -8.5208, -49.572, -234.696, -9.16, -49.3514, -236.913, -8.7617, -49.4888, -228.992, -12.9847, -48.9977, -232.31, -12.9847, -49.2034, -241.499, -7.2796, -49.7731, -234.449, -12.9847, -49.336, -232.31, -12.9847, -49.2034, -240.307, -7.7354, -49.6993, -241.499, -7.2796, -49.7731, -238.254, -8.5208, -49.572, -240.307, -7.7354, -49.6993, -232.31, -12.9847, -49.2034, -234.449, -12.9847, -49.336, -244.242, -5.5084, -49.9432, -254.358, 1.9054, -50.5705, -243.258, -6.1439, -49.8822, -234.449, -12.9847, -49.336, -241.499, -7.2796, -49.7731, -234.449, -12.9847, -49.336, -243.258, -6.1439, -49.8822, -244.242, -5.5084, -49.9432, -254.358, 1.9054, -50.5705, -245.591, -4.0841, -50.0268, -246.324, -3.3103, -50.0723, -245.591, -4.0841, -50.0268, -254.358, 1.9054, -50.5705, -244.242, -5.5084, -49.9432, -247.913, 0.9249, -50.1708, -254.358, 1.9054, -50.5705, -247.623, -0.813, -50.1528, -254.358, 1.9054, -50.5705, -247.913, 0.9249, -50.1708, -248.065, 1.8384, -50.1802, -254.358, 1.9054, -50.5705, -247.172, -1.6801, -50.1249, -247.623, -0.813, -50.1528, -247.172, -1.6801, -50.1249, -254.358, 1.9054, -50.5705, -246.324, -3.3103, -50.0723) + +[node name="Tunnel" instance=ExtResource("1_1sr0i")] +collision_mask = 3 + +[node name="Tunnel2" parent="." index="0"] +surface_material_override/0 = ExtResource("2_lkb1r") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." index="1"] +shape = SubResource("ConcavePolygonShape3D_bh6xx") diff --git a/demo/assets/textures/asset_licenses.txt b/demo/assets/textures/asset_licenses.txt new file mode 100644 index 0000000..bcab6b6 --- /dev/null +++ b/demo/assets/textures/asset_licenses.txt @@ -0,0 +1,12 @@ +All ambientCG assets are provided under the +Creative Commons CC0 1.0 Universal License. +https://docs.ambientcg.com/license/ + +Grass: +https://ambientcg.com/view?id=Ground037 + +Rock: +https://ambientcg.com/view?id=Rock030 + +Cliff: +https://ambientcg.com/view?id=Rock023 diff --git a/demo/assets/textures/ground037_alb_ht.png b/demo/assets/textures/ground037_alb_ht.png new file mode 100644 index 0000000..d7628fa Binary files /dev/null and b/demo/assets/textures/ground037_alb_ht.png differ diff --git a/demo/assets/textures/ground037_alb_ht.png.import b/demo/assets/textures/ground037_alb_ht.png.import new file mode 100644 index 0000000..eab222b --- /dev/null +++ b/demo/assets/textures/ground037_alb_ht.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ddprscrpsofah" +path.bptc="res://.godot/imported/ground037_alb_ht.png-d854c3c88beba9927351b95063edffa2.bptc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://demo/assets/textures/ground037_alb_ht.png" +dest_files=["res://.godot/imported/ground037_alb_ht.png-d854c3c88beba9927351b95063edffa2.bptc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=true +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/demo/assets/textures/ground037_nrm_rgh.png b/demo/assets/textures/ground037_nrm_rgh.png new file mode 100644 index 0000000..d370866 Binary files /dev/null and b/demo/assets/textures/ground037_nrm_rgh.png differ diff --git a/demo/assets/textures/ground037_nrm_rgh.png.import b/demo/assets/textures/ground037_nrm_rgh.png.import new file mode 100644 index 0000000..f766f44 --- /dev/null +++ b/demo/assets/textures/ground037_nrm_rgh.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c1ots7w6i0i1q" +path.bptc="res://.godot/imported/ground037_nrm_rgh.png-02372c72ee87f1844ee708d952e43e96.bptc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://demo/assets/textures/ground037_nrm_rgh.png" +dest_files=["res://.godot/imported/ground037_nrm_rgh.png-02372c72ee87f1844ee708d952e43e96.bptc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=true +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/demo/assets/textures/rock023_alb_ht.png b/demo/assets/textures/rock023_alb_ht.png new file mode 100644 index 0000000..b80135c Binary files /dev/null and b/demo/assets/textures/rock023_alb_ht.png differ diff --git a/demo/assets/textures/rock023_alb_ht.png.import b/demo/assets/textures/rock023_alb_ht.png.import new file mode 100644 index 0000000..a0fadc4 --- /dev/null +++ b/demo/assets/textures/rock023_alb_ht.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c88j3oj0lf6om" +path.bptc="res://.godot/imported/rock023_alb_ht.png-9c06b8a5f11d940d1c46d8928f6d6a5c.bptc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://demo/assets/textures/rock023_alb_ht.png" +dest_files=["res://.godot/imported/rock023_alb_ht.png-9c06b8a5f11d940d1c46d8928f6d6a5c.bptc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=true +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/demo/assets/textures/rock023_nrm_rgh.png b/demo/assets/textures/rock023_nrm_rgh.png new file mode 100644 index 0000000..8b30450 Binary files /dev/null and b/demo/assets/textures/rock023_nrm_rgh.png differ diff --git a/demo/assets/textures/rock023_nrm_rgh.png.import b/demo/assets/textures/rock023_nrm_rgh.png.import new file mode 100644 index 0000000..3f48b1c --- /dev/null +++ b/demo/assets/textures/rock023_nrm_rgh.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c307hdmos4gtm" +path.bptc="res://.godot/imported/rock023_nrm_rgh.png-dd524905a15817dac8149681cddc8975.bptc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://demo/assets/textures/rock023_nrm_rgh.png" +dest_files=["res://.godot/imported/rock023_nrm_rgh.png-dd524905a15817dac8149681cddc8975.bptc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=true +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/demo/components/Borders.tscn b/demo/components/Borders.tscn new file mode 100644 index 0000000..ae00fb3 --- /dev/null +++ b/demo/components/Borders.tscn @@ -0,0 +1,57 @@ +[gd_scene load_steps=6 format=3 uid="uid://dwnhqfjq7v1pq"] + +[ext_resource type="Material" uid="uid://d0hyi5n6ng25w" path="res://demo/assets/materials/M_rock23_black_tp.tres" id="1_goand"] + +[sub_resource type="BoxMesh" id="BoxMesh_1kfaq"] +size = Vector3(1025.01, 4, 1) + +[sub_resource type="BoxShape3D" id="BoxShape3D_s0c8u"] +size = Vector3(1025, 100, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_kfxc8"] +size = Vector3(3072, 4, 1) + +[sub_resource type="BoxShape3D" id="BoxShape3D_pyqb2"] +size = Vector3(1, 100, 3072) + +[node name="Borders" type="StaticBody3D"] + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 512) +mesh = SubResource("BoxMesh_1kfaq") +skeleton = NodePath("../..") +surface_material_override/0 = ExtResource("1_goand") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 50, 512) +shape = SubResource("BoxShape3D_s0c8u") + +[node name="MeshInstance3D2" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, -2560) +mesh = SubResource("BoxMesh_1kfaq") +skeleton = NodePath("../..") +surface_material_override/0 = ExtResource("1_goand") + +[node name="CollisionShape3D2" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 50, -2560) +shape = SubResource("BoxShape3D_s0c8u") + +[node name="MeshInstance3D3" type="MeshInstance3D" parent="."] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 512, 2, -1024) +mesh = SubResource("BoxMesh_kfxc8") +skeleton = NodePath("../..") +surface_material_override/0 = ExtResource("1_goand") + +[node name="CollisionShape3D3" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 512, 50, -1024) +shape = SubResource("BoxShape3D_pyqb2") + +[node name="MeshInstance3D4" type="MeshInstance3D" parent="."] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -512, 2, -1024) +mesh = SubResource("BoxMesh_kfxc8") +skeleton = NodePath("../..") +surface_material_override/0 = ExtResource("1_goand") + +[node name="CollisionShape3D4" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -512, 50, -1024) +shape = SubResource("BoxShape3D_pyqb2") diff --git a/demo/components/DemoBenchmark.tscn b/demo/components/DemoBenchmark.tscn new file mode 100644 index 0000000..4561e9d --- /dev/null +++ b/demo/components/DemoBenchmark.tscn @@ -0,0 +1,84 @@ +[gd_scene load_steps=11 format=3 uid="uid://dyt8c2xqmddo2"] + +[ext_resource type="Script" uid="uid://chstoagn42gbr" path="res://demo/src/DemoScene.gd" id="1_2gjn4"] +[ext_resource type="PackedScene" uid="uid://d2jihfohphuue" path="res://demo/components/UI.tscn" id="2_3obxr"] +[ext_resource type="PackedScene" uid="uid://bb2lp50sjndus" path="res://demo/components/Environment.tscn" id="3_b7ioy"] +[ext_resource type="PackedScene" uid="uid://dwnhqfjq7v1pq" path="res://demo/components/Borders.tscn" id="4_nn6wp"] +[ext_resource type="PackedScene" uid="uid://domhm87hbhbg1" path="res://demo/components/Player.tscn" id="5_bwggt"] +[ext_resource type="Terrain3DAssets" uid="uid://dal3jhw6241qg" path="res://demo/data/assets.tres" id="6_3r2au"] + +[sub_resource type="Gradient" id="Gradient_f1plm"] +offsets = PackedFloat32Array(0.2, 1) +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_bfcw0"] +noise_type = 2 +frequency = 0.03 +cellular_jitter = 3.0 +cellular_return_type = 0 +domain_warp_enabled = true +domain_warp_type = 1 +domain_warp_amplitude = 50.0 +domain_warp_fractal_type = 2 +domain_warp_fractal_lacunarity = 1.5 +domain_warp_fractal_gain = 1.0 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_quxx0"] +seamless = true +color_ramp = SubResource("Gradient_f1plm") +noise = SubResource("FastNoiseLite_bfcw0") + +[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_klrp5"] +_shader_parameters = { +"auto_base_texture": 0, +"auto_height_reduction": 0.1, +"auto_overlay_texture": 1, +"auto_slope": 1.0, +"bias_distance": 512.0, +"blend_sharpness": 0.87, +"depth_blur": 0.0, +"dual_scale_far": 170.0, +"dual_scale_near": 100.0, +"dual_scale_reduction": 0.3, +"dual_scale_texture": 0, +"enable_macro_variation": true, +"enable_projection": true, +"height_blending": true, +"macro_variation1": Color(1, 1, 1, 1), +"macro_variation2": Color(1, 1, 1, 1), +"macro_variation_slope": 0.333, +"mipmap_bias": 1.0, +"noise1_angle": 0.0, +"noise1_offset": Vector2(0.5, 0.5), +"noise1_scale": 0.04, +"noise2_scale": 0.076, +"noise3_scale": 0.225, +"noise_texture": SubResource("NoiseTexture2D_quxx0"), +"projection_angular_division": 1.436, +"projection_threshold": 0.8, +"tri_scale_reduction": 0.3, +&"world_space_normal_blend": true +} +auto_shader = true +dual_scaling = true + +[node name="Demo" type="Node"] +script = ExtResource("1_2gjn4") + +[node name="UI" parent="." instance=ExtResource("2_3obxr")] + +[node name="World" parent="." instance=ExtResource("3_b7ioy")] + +[node name="Borders" parent="." instance=ExtResource("4_nn6wp")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 512, 0, 512) + +[node name="Player" parent="." instance=ExtResource("5_bwggt")] +transform = Transform3D(0.134125, 0, -0.990965, 0, 1, 0, 0.990965, 0, 0.134125, 216.455, 103.968, -1835.34) + +[node name="Terrain3D" type="Terrain3D" parent="."] +data_directory = "res://demo/data" +material = SubResource("Terrain3DMaterial_klrp5") +assets = ExtResource("6_3r2au") +collision_mask = 3 +top_level = true +metadata/_edit_lock_ = true diff --git a/demo/components/Enemy.tscn b/demo/components/Enemy.tscn new file mode 100644 index 0000000..0f64e1f --- /dev/null +++ b/demo/components/Enemy.tscn @@ -0,0 +1,34 @@ +[gd_scene load_steps=6 format=3 uid="uid://di5fovhcyd7re"] + +[ext_resource type="Script" path="res://demo/src/Enemy.gd" id="1_yudyn"] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_lwhhq"] +height = 1.5 + +[sub_resource type="SeparationRayShape3D" id="SeparationRayShape3D_i8f01"] + +[sub_resource type="CapsuleMesh" id="CapsuleMesh_lsqiy"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_d4cor"] +albedo_color = Color(1, 0, 0, 1) + +[node name="Enemy" type="CharacterBody3D"] +collision_layer = 2 +script = ExtResource("1_yudyn") + +[node name="CollisionShapeBody" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.25, 0) +shape = SubResource("CapsuleShape3D_lwhhq") + +[node name="CollisionShapeRay" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 1, 0) +shape = SubResource("SeparationRayShape3D_i8f01") + +[node name="Body" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +mesh = SubResource("CapsuleMesh_lsqiy") +surface_material_override/0 = SubResource("StandardMaterial3D_d4cor") + +[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."] +path_desired_distance = 2.0 +debug_enabled = true diff --git a/demo/components/Environment.tscn b/demo/components/Environment.tscn new file mode 100644 index 0000000..06cd358 --- /dev/null +++ b/demo/components/Environment.tscn @@ -0,0 +1,34 @@ +[gd_scene load_steps=5 format=3 uid="uid://bb2lp50sjndus"] + +[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_vibap"] +sky_top_color = Color(0.192157, 0.282353, 0.509804, 1) +sky_horizon_color = Color(0.505882, 0.615686, 0.709804, 1) +ground_bottom_color = Color(0.211765, 0.313726, 0.552941, 1) +ground_horizon_color = Color(0.505882, 0.615686, 0.709804, 1) +ground_curve = 0.13 + +[sub_resource type="Sky" id="Sky_srg7c"] +sky_material = SubResource("ProceduralSkyMaterial_vibap") + +[sub_resource type="Environment" id="Environment_8jcgm"] +background_mode = 2 +sky = SubResource("Sky_srg7c") +ambient_light_source = 3 +ambient_light_color = Color(0.55, 0.55, 0.55, 1) +ambient_light_sky_contribution = 0.3 +tonemap_mode = 3 + +[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_0gcl0"] + +[node name="Environment" type="Node3D"] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_8jcgm") +camera_attributes = SubResource("CameraAttributesPractical_0gcl0") + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +transform = Transform3D(-0.866024, -0.433016, 0.250001, 0, 0.499998, 0.866026, -0.500003, 0.749999, -0.43301, 0, 0, 0) +shadow_enabled = true +shadow_blur = 2.0 +directional_shadow_blend_splits = true +directional_shadow_max_distance = 256.0 diff --git a/demo/components/Player.tscn b/demo/components/Player.tscn new file mode 100644 index 0000000..b8e81c7 --- /dev/null +++ b/demo/components/Player.tscn @@ -0,0 +1,44 @@ +[gd_scene load_steps=7 format=3 uid="uid://domhm87hbhbg1"] + +[ext_resource type="Script" path="res://demo/src/Player.gd" id="1_nm1yx"] +[ext_resource type="Script" path="res://demo/src/CameraManager.gd" id="2_loos7"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_smq6u"] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_lwhhq"] +height = 1.5 + +[sub_resource type="SeparationRayShape3D" id="SeparationRayShape3D_twc2s"] + +[sub_resource type="CapsuleMesh" id="CapsuleMesh_lsqiy"] + +[node name="Player" type="CharacterBody3D"] +collision_layer = 2 +script = ExtResource("1_nm1yx") + +[node name="CameraManager" type="Node3D" parent="."] +script = ExtResource("2_loos7") + +[node name="Arm" type="SpringArm3D" parent="CameraManager"] +unique_name_in_owner = true +transform = Transform3D(1, 0, 0, 0, 0.906308, 0.422618, 0, -0.422618, 0.906308, 0, 2.32515, -0.0321627) +shape = SubResource("SphereShape3D_smq6u") +spring_length = 6.0 +margin = 0.5 + +[node name="Camera3D" type="Camera3D" parent="CameraManager/Arm"] +unique_name_in_owner = true +near = 0.25 +far = 16384.0 + +[node name="CollisionShapeBody" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.25, 0) +shape = SubResource("CapsuleShape3D_lwhhq") + +[node name="CollisionShapeRay" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 1, 0) +shape = SubResource("SeparationRayShape3D_twc2s") + +[node name="Body" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +mesh = SubResource("CapsuleMesh_lsqiy") diff --git a/demo/components/Tunnel.tscn b/demo/components/Tunnel.tscn new file mode 100644 index 0000000..7c6c6e7 --- /dev/null +++ b/demo/components/Tunnel.tscn @@ -0,0 +1,167 @@ +[gd_scene load_steps=10 format=3 uid="uid://djhl3foqkj4e2"] + +[ext_resource type="PackedScene" uid="uid://be6nrf0b8j4l0" path="res://demo/assets/models/RockA.tscn" id="1_m1xck"] +[ext_resource type="PackedScene" uid="uid://bwvtgwartxt0g" path="res://demo/assets/models/RockB.tscn" id="2_hybky"] +[ext_resource type="PackedScene" uid="uid://lsvs8a7urkca" path="res://demo/assets/models/RockC.tscn" id="3_nbn1a"] +[ext_resource type="PackedScene" uid="uid://vvayjv3rbx1d" path="res://demo/assets/models/Tunnel.tscn" id="4_klbpo"] +[ext_resource type="PackedScene" uid="uid://cribhhvg03u8g" path="res://demo/assets/models/CrystalC.tscn" id="5_bb2w0"] +[ext_resource type="Material" uid="uid://cso4f2iyuxpmc" path="res://demo/assets/materials/M_crystal_purple.tres" id="6_s6twx"] +[ext_resource type="Material" uid="uid://ickkffutwcvo" path="res://demo/assets/materials/M_crystal_red.tres" id="7_7fkm2"] +[ext_resource type="Script" uid="uid://c444j1ucmv5ti" path="res://demo/src/CaveEntrance.gd" id="9_fn2ke"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_goiy4"] +size = Vector3(530.482, 38.6343, 235.603) + +[node name="Tunnel" type="Node3D"] + +[node name="EntranceL" type="Node3D" parent="."] + +[node name="RockA1" parent="EntranceL" instance=ExtResource("1_m1xck")] +transform = Transform3D(5.82988, -5.4374, -4.00004, 6.04396, 6.55839, -0.106264, 3.00604, -2.64109, 7.9713, 807.937, 137.298, 467.411) + +[node name="RockA2" parent="EntranceL" instance=ExtResource("1_m1xck")] +transform = Transform3D(4.67905, 4.22076, -5.5926, 6.98724, -3.31022, 3.34764, -0.52024, -6.49718, -5.3387, 766.019, 104.95, 452.605) + +[node name="RockA3" parent="EntranceL" instance=ExtResource("1_m1xck")] +transform = Transform3D(1.19782, 11.0889, 4.42738, -11.9291, 0.921057, 0.9205, 0.510788, -4.49312, 11.1153, 793.166, 76.9378, 454.834) + +[node name="RockB1" parent="EntranceL" instance=ExtResource("2_hybky")] +transform = Transform3D(-2.10522, -4.25988, 3.15298, 3.05166, -3.74811, -3.02637, 4.33304, 0.570028, 3.66329, 824.574, 112.54, 446.946) + +[node name="RockB3" parent="EntranceL" instance=ExtResource("2_hybky")] +transform = Transform3D(4.29222, 4.57142, 1.24961, -2.49948, 3.61605, -4.6432, -4.02641, 2.62846, 4.21447, 773.937, 140.911, 469.972) + +[node name="RockC1" parent="EntranceL" instance=ExtResource("3_nbn1a")] +transform = Transform3D(-1.86839, -3.85072, -1.99813, -0.0474326, -2.1573, 4.20181, -4.33801, 1.6821, 0.814656, 786.081, 135.376, 453.531) + +[node name="RockC2" parent="EntranceL" instance=ExtResource("3_nbn1a")] +transform = Transform3D(-3.90856, -4.56077, 3.35866, 3.81036, 0.902037, 5.65911, -4.19074, 5.07383, 2.01294, 791.859, 164.408, 508.107) + +[node name="EntranceR" type="Node3D" parent="."] + +[node name="RockA1" parent="EntranceR" instance=ExtResource("1_m1xck")] +transform = Transform3D(-0.271255, 1.28607, -2.97471, -1.25761, 2.70942, 1.28605, 2.98685, 1.25759, 0.271335, 299.644, 127.203, 424.309) + +[node name="RockA2" parent="EntranceR" instance=ExtResource("1_m1xck")] +transform = Transform3D(2.29164, -2.44454, 3.0731, 3.84134, 0.657286, -2.34167, 0.814771, 3.77671, 2.39666, 318.179, 95.8599, 421.731) + +[node name="RockA5" parent="EntranceR" instance=ExtResource("1_m1xck")] +transform = Transform3D(1.09929, -4.37397, 0.575562, 3.84134, 0.657286, -2.34167, 2.16957, 1.05247, 3.85443, 321.814, 95.8599, 436.931) + +[node name="RockA3" parent="EntranceR" instance=ExtResource("1_m1xck")] +transform = Transform3D(3.70822, 1.86229, 1.85804, 2.19079, -0.408409, -3.96295, -1.45634, 4.12752, -1.23046, 338.177, 116.66, 430.367) + +[node name="RockA4" parent="EntranceR" instance=ExtResource("1_m1xck")] +transform = Transform3D(1.9779, 0.270409, 4.08487, -4.00125, 1.0869, 1.86547, -0.865577, -4.40646, 0.710812, 320.977, 134.583, 441.012) + +[node name="RockB1" parent="EntranceR" instance=ExtResource("2_hybky")] +transform = Transform3D(-1.64956, -1.63286, 1.75857, 0.196316, 2.03499, 2.07367, -2.39171, 1.29322, -1.04267, 295.848, 109.828, 419.45) + +[node name="RockB3" parent="EntranceR" instance=ExtResource("2_hybky")] +transform = Transform3D(-2.03718, 1.29729, 2.88404, -2.82928, 0.784888, -2.35156, -1.41272, -3.44263, 0.550663, 306.288, 128.712, 434.042) + +[node name="RockB4" parent="EntranceR" instance=ExtResource("2_hybky")] +transform = Transform3D(1.97436, 2.87133, -1.41708, -2.82928, 0.784888, -2.35156, -1.49926, 2.30004, 2.57153, 328.686, 129.709, 427.63) + +[node name="RockB2" parent="EntranceR" instance=ExtResource("2_hybky")] +transform = Transform3D(-2.17746, 0.476253, -1.87396, -1.61495, 1.104, 2.15708, 1.06324, 2.65221, -0.561397, 303.461, 107.797, 428.826) + +[node name="RockC1" parent="EntranceR" instance=ExtResource("3_nbn1a")] +transform = Transform3D(1.74949, 1.15588, 0.576742, -1.01213, 1.82987, -0.597152, -0.802676, 0.21197, 2.01002, 335.27, 110.419, 418.362) + +[node name="RockC2" parent="EntranceR" instance=ExtResource("3_nbn1a")] +transform = Transform3D(4.31956, 5.88829, -1.29353, -3.67086, 1.30662, -6.31041, -4.78226, 4.31561, 3.67549, 345.465, 146.581, 480.747) + +[node name="TunnelMesh" parent="." instance=ExtResource("4_klbpo")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 546.733, 112.043, 468.686) + +[node name="CrystalGroup1" type="Node3D" parent="."] +transform = Transform3D(0.567756, 0.0788585, -0.00345403, 0.0729824, -0.514888, 0.241124, 0.0300693, -0.239266, -0.520024, 415.722, 122.719, 611.385) + +[node name="CrystalC" parent="CrystalGroup1" instance=ExtResource("5_bb2w0")] +transform = Transform3D(0.990472, -0.134216, 0.0307963, 0.132893, 0.873058, -0.469155, 0.0360812, 0.468779, 0.882577, 0.050354, 1.72128, 4.54956) + +[node name="CrystalC3" parent="CrystalGroup1" instance=ExtResource("5_bb2w0")] +transform = Transform3D(0.999999, 2.98023e-08, 0, 1.40402e-08, 0.999999, 1.19209e-07, 6.89635e-09, -1.49012e-07, 0.999999, 4.00897, 3.69431, -0.617554) + +[node name="CrystalC2" parent="CrystalGroup1" instance=ExtResource("5_bb2w0")] +transform = Transform3D(-0.513116, -0.374576, 0.95887, -0.130632, 1.08641, 0.354495, -1.02111, 0.0492404, -0.527189, -1.70374, 4.03528, -0.568237) + +[node name="OmniLight3D" type="OmniLight3D" parent="CrystalGroup1"] +transform = Transform3D(1, 3.21278e-08, -1.96807e-08, -3.21278e-08, 1, 1.02499e-07, 1.96807e-08, -1.02499e-07, 1, 1.11737, 4.79865, 1.8949) +light_color = Color(0.4, 0.760784, 1, 1) +light_energy = 16.0 +shadow_enabled = true +omni_range = 83.054 + +[node name="CrystalGroup2" type="Node3D" parent="."] +transform = Transform3D(-0.536793, -0.0213862, -0.199931, -0.116106, 0.498308, 0.25843, 0.164163, 0.282504, -0.470976, 553.318, 103.571, 647.425) + +[node name="CrystalC" parent="CrystalGroup2" instance=ExtResource("5_bb2w0")] +transform = Transform3D(0.704558, -0.579782, 0.130258, 0.554941, 0.56972, -0.465804, 0.212495, 0.434496, 0.784585, 0.815979, 1.24854, 2.5437) + +[node name="Rock3" parent="CrystalGroup2/CrystalC" index="0"] +surface_material_override/0 = ExtResource("6_s6twx") + +[node name="CrystalC3" parent="CrystalGroup2" instance=ExtResource("5_bb2w0")] +transform = Transform3D(0.127208, -0.0568556, -1.06836, -0.317718, 1.02534, -0.0923969, 1.02161, 0.32596, 0.104294, 4.00861, 3.69458, -0.617188) + +[node name="Rock3" parent="CrystalGroup2/CrystalC3" index="0"] +surface_material_override/0 = ExtResource("6_s6twx") + +[node name="CrystalC2" parent="CrystalGroup2" instance=ExtResource("5_bb2w0")] +transform = Transform3D(-0.642172, -0.213226, 0.774009, 0.484154, 0.687794, 0.591163, -0.640428, 0.733767, -0.329203, 7.28876, 1.71277, 4.52783) + +[node name="Rock3" parent="CrystalGroup2/CrystalC2" index="0"] +surface_material_override/0 = ExtResource("6_s6twx") + +[node name="OmniLight3D" type="OmniLight3D" parent="CrystalGroup2"] +transform = Transform3D(1.74454, 2.98023e-08, -2.98023e-08, -5.60482e-08, 1.74454, 1.49012e-07, 3.43338e-08, -1.78814e-07, 1.74454, 1.11737, 4.79865, 1.8949) +light_color = Color(0.396078, 0.333333, 0.878431, 1) +light_energy = 16.0 +shadow_enabled = true +omni_range = 83.054 + +[node name="CrystalGroup3" type="Node3D" parent="."] +transform = Transform3D(-0.536793, -0.0213862, -0.199931, 0.0789312, -0.546626, -0.153451, -0.184932, -0.17123, 0.514837, 711.291, 124.136, 579.252) + +[node name="CrystalC" parent="CrystalGroup3" instance=ExtResource("5_bb2w0")] +transform = Transform3D(0.898105, -0.188271, 0.0864646, 0.196692, 0.654036, -0.618921, 0.0650697, 0.621535, 0.677476, 0.589844, 2.22089, 3.04785) + +[node name="Rock3" parent="CrystalGroup3/CrystalC" index="0"] +surface_material_override/0 = ExtResource("7_7fkm2") + +[node name="CrystalC3" parent="CrystalGroup3" instance=ExtResource("5_bb2w0")] +transform = Transform3D(0.15544, 0.0752453, -1.06348, -0.370935, 1.01139, 0.0173435, 0.999527, 0.363637, 0.171821, 4.00867, 3.69458, -0.617432) + +[node name="Rock3" parent="CrystalGroup3/CrystalC3" index="0"] +surface_material_override/0 = ExtResource("7_7fkm2") + +[node name="CrystalC2" parent="CrystalGroup3" instance=ExtResource("5_bb2w0")] +transform = Transform3D(-0.573134, -0.100696, 0.847536, 0.285048, 0.939695, 0.304405, -0.804489, 0.404691, -0.495942, 7.2887, 1.71283, 4.52771) + +[node name="Rock3" parent="CrystalGroup3/CrystalC2" index="0"] +surface_material_override/0 = ExtResource("7_7fkm2") + +[node name="OmniLight3D" type="OmniLight3D" parent="CrystalGroup3"] +transform = Transform3D(1.74454, 2.98023e-08, -2.98023e-08, -5.60482e-08, 1.74454, 1.49012e-07, 3.43338e-08, -1.78814e-07, 1.74454, 1.11737, 4.79865, 1.8949) +light_color = Color(0.388235, 0.101961, 0.2, 1) +light_energy = 16.0 +shadow_enabled = true +omni_range = 83.054 + +[node name="CaveArea3D" type="Area3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 549.961, 110.763, 526.656) +collision_mask = 2 +script = ExtResource("9_fn2ke") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="CaveArea3D"] +transform = Transform3D(0.998441, 0, -0.0558215, 0, 1, 0, 0.0558215, 0, 0.998441, -8.36676, 3.78637, 30.7709) +shape = SubResource("BoxShape3D_goiy4") + +[editable path="CrystalGroup2/CrystalC"] +[editable path="CrystalGroup2/CrystalC3"] +[editable path="CrystalGroup2/CrystalC2"] +[editable path="CrystalGroup3/CrystalC"] +[editable path="CrystalGroup3/CrystalC3"] +[editable path="CrystalGroup3/CrystalC2"] diff --git a/demo/components/UI.tscn b/demo/components/UI.tscn new file mode 100644 index 0000000..e36d604 --- /dev/null +++ b/demo/components/UI.tscn @@ -0,0 +1,66 @@ +[gd_scene load_steps=2 format=3 uid="uid://d2jihfohphuue"] + +[ext_resource type="Script" path="res://demo/src/UI.gd" id="1_why5e"] + +[node name="UI" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_why5e") + +[node name="Label" type="Label" parent="."] +unique_name_in_owner = true +layout_mode = 1 +offset_left = 5.0 +offset_top = 5.0 +offset_right = 275.0 +offset_bottom = 340.0 +theme_override_colors/font_shadow_color = Color(0, 0, 0, 0.662745) +theme_override_constants/shadow_offset_x = 1 +theme_override_constants/shadow_offset_y = 1 +text = "FPS: 100 +Position: (100, 100, 100) +Move Speed: 10 + +Player +Move: WASDEQ,Space,Mouse +Move speed: Wheel,+/-,Shift +Camera view: V +Gravity toggle: G +Collision toggle: C + +Window +Quit: F8 +UI toggle: F9 +Render mode: F10 +Full screen: F11 +Mouse toggle: Escape +" + +[node name="Panel" type="Panel" parent="Label"] +modulate = Color(1, 1, 1, 0.392157) +show_behind_parent = true +layout_mode = 0 +offset_left = -5.0 +offset_top = -5.0 +offset_right = 248.0 +offset_bottom = 444.0 + +[node name="HSeparator" type="HSeparator" parent="Label/Panel"] +top_level = true +layout_mode = 0 +offset_left = 6.0 +offset_top = 129.0 +offset_right = 246.0 +offset_bottom = 138.0 + +[node name="HSeparator2" type="HSeparator" parent="Label/Panel"] +top_level = true +layout_mode = 0 +offset_left = 6.0 +offset_top = 310.0 +offset_right = 246.0 +offset_bottom = 319.0 diff --git a/demo/data/assets.tres b/demo/data/assets.tres new file mode 100644 index 0000000..2dfa5f6 --- /dev/null +++ b/demo/data/assets.tres @@ -0,0 +1,57 @@ +[gd_resource type="Terrain3DAssets" load_steps=11 format=3 uid="uid://dal3jhw6241qg"] + +[ext_resource type="PackedScene" uid="uid://bn5nf4esciwex" path="res://demo/assets/models/LODExample.tscn" id="1_4jrdu"] +[ext_resource type="Texture2D" uid="uid://c88j3oj0lf6om" path="res://demo/assets/textures/rock023_alb_ht.png" id="2_pog6b"] +[ext_resource type="Texture2D" uid="uid://ddprscrpsofah" path="res://demo/assets/textures/ground037_alb_ht.png" id="3_g8f2m"] +[ext_resource type="Texture2D" uid="uid://c307hdmos4gtm" path="res://demo/assets/textures/rock023_nrm_rgh.png" id="3_wncaf"] +[ext_resource type="Texture2D" uid="uid://c1ots7w6i0i1q" path="res://demo/assets/textures/ground037_nrm_rgh.png" id="4_aw5y1"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_b2vqk"] +transparency = 4 +cull_mode = 2 +vertex_color_use_as_albedo = true +backlight_enabled = true +backlight = Color(0.5, 0.5, 0.5, 1) +distance_fade_mode = 1 +distance_fade_min_distance = 128.0 +distance_fade_max_distance = 96.0 + +[sub_resource type="Terrain3DMeshAsset" id="Terrain3DMeshAsset_2qf8x"] +name = "TextureCard" +generated_type = 1 +height_offset = 0.5 +material_override = SubResource("StandardMaterial3D_b2vqk") +last_lod = 0 +last_shadow_lod = 0 +lod0_range = 128.0 + +[sub_resource type="Terrain3DMeshAsset" id="Terrain3DMeshAsset_or12t"] +name = "LODExample" +id = 1 +scene_file = ExtResource("1_4jrdu") +height_offset = 0.5 +last_lod = 3 +last_shadow_lod = 3 + +[sub_resource type="Terrain3DTextureAsset" id="Terrain3DTextureAsset_lha57"] +name = "Cliff" +albedo_texture = ExtResource("2_pog6b") +normal_texture = ExtResource("3_wncaf") +normal_depth = 1.0 +ao_strength = 2.0 +roughness = -0.05 + +[sub_resource type="Terrain3DTextureAsset" id="Terrain3DTextureAsset_od0q7"] +name = "Grass" +id = 1 +albedo_color = Color(0.67451, 0.74902, 0.686275, 1) +albedo_texture = ExtResource("3_g8f2m") +normal_texture = ExtResource("4_aw5y1") +normal_depth = 1.0 +ao_strength = 2.0 +uv_scale = 0.2 +detiling_rotation = 0.161 + +[resource] +mesh_list = Array[Terrain3DMeshAsset]([SubResource("Terrain3DMeshAsset_2qf8x"), SubResource("Terrain3DMeshAsset_or12t")]) +texture_list = Array[Terrain3DTextureAsset]([SubResource("Terrain3DTextureAsset_lha57"), SubResource("Terrain3DTextureAsset_od0q7")]) diff --git a/demo/data/nav_mesh.res b/demo/data/nav_mesh.res new file mode 100644 index 0000000..c949983 Binary files /dev/null and b/demo/data/nav_mesh.res differ diff --git a/demo/data/terrain3d_00-01.res b/demo/data/terrain3d_00-01.res new file mode 100644 index 0000000..d6019c9 Binary files /dev/null and b/demo/data/terrain3d_00-01.res differ diff --git a/demo/data/terrain3d_00-02.res b/demo/data/terrain3d_00-02.res new file mode 100644 index 0000000..eb9cd4c Binary files /dev/null and b/demo/data/terrain3d_00-02.res differ diff --git a/demo/data/terrain3d_00_00.res b/demo/data/terrain3d_00_00.res new file mode 100644 index 0000000..12d0868 Binary files /dev/null and b/demo/data/terrain3d_00_00.res differ diff --git a/demo/src/CameraManager.gd b/demo/src/CameraManager.gd new file mode 100644 index 0000000..9c40488 --- /dev/null +++ b/demo/src/CameraManager.gd @@ -0,0 +1,29 @@ +extends Node3D + +const CAMERA_MAX_PITCH: float = deg_to_rad(70) +const CAMERA_MIN_PITCH: float = deg_to_rad(-89.9) +const CAMERA_RATIO: float = .625 + +@export var mouse_sensitivity: float = .002 +@export var mouse_y_inversion: float = -1.0 + +@onready var _camera_yaw: Node3D = self +@onready var _camera_pitch: Node3D = %Arm + + +func _ready() -> void: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + + +func _input(p_event: InputEvent) -> void: + if p_event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: + rotate_camera(p_event.relative) + get_viewport().set_input_as_handled() + return + + +func rotate_camera(p_relative:Vector2) -> void: + _camera_yaw.rotation.y -= p_relative.x * mouse_sensitivity + _camera_yaw.orthonormalize() + _camera_pitch.rotation.x += p_relative.y * mouse_sensitivity * CAMERA_RATIO * mouse_y_inversion + _camera_pitch.rotation.x = clamp(_camera_pitch.rotation.x, CAMERA_MIN_PITCH, CAMERA_MAX_PITCH) diff --git a/demo/src/CameraManager.gd.uid b/demo/src/CameraManager.gd.uid new file mode 100644 index 0000000..aa06bd2 --- /dev/null +++ b/demo/src/CameraManager.gd.uid @@ -0,0 +1 @@ +uid://b62ppvc03a6b1 diff --git a/demo/src/CaveEntrance.gd b/demo/src/CaveEntrance.gd new file mode 100644 index 0000000..70e7948 --- /dev/null +++ b/demo/src/CaveEntrance.gd @@ -0,0 +1,22 @@ +extends Area3D + + +func _ready() -> void: + body_entered.connect(_on_body_entered) + body_exited.connect(_on_body_exited) + + +func _on_body_entered(body: Node3D) -> void: + if body.name == "Player": + var env: WorldEnvironment = get_node_or_null("../../Environment/WorldEnvironment") + if env: + var tween: Tween = get_tree().create_tween() + tween.tween_property(env.environment, "ambient_light_energy", .1, .33) + + +func _on_body_exited(body: Node3D) -> void: + if body.name == "Player": + var env: WorldEnvironment = get_node_or_null("../../Environment/WorldEnvironment") + if env: + var tween: Tween = get_tree().create_tween() + tween.tween_property(env.environment, "ambient_light_energy", 1., .33) diff --git a/demo/src/CaveEntrance.gd.uid b/demo/src/CaveEntrance.gd.uid new file mode 100644 index 0000000..28ca46f --- /dev/null +++ b/demo/src/CaveEntrance.gd.uid @@ -0,0 +1 @@ +uid://c444j1ucmv5ti diff --git a/demo/src/CodeGenerated.gd b/demo/src/CodeGenerated.gd new file mode 100644 index 0000000..a91652d --- /dev/null +++ b/demo/src/CodeGenerated.gd @@ -0,0 +1,133 @@ +extends Node + +var terrain: Terrain3D + + +func _ready() -> void: + $UI.player = $Player + + if has_node("RunThisSceneLabel3D"): + $RunThisSceneLabel3D.queue_free() + + terrain = await create_terrain() + + # Enable runtime navigation baking using the terrain + # Enable `Debug/Visible Navigation` if you wish to see it + $RuntimeNavigationBaker.terrain = terrain + $RuntimeNavigationBaker.enabled = true + + +func create_terrain() -> Terrain3D: + # Create textures + var green_gr := Gradient.new() + green_gr.set_color(0, Color.from_hsv(100./360., .35, .3)) + green_gr.set_color(1, Color.from_hsv(120./360., .4, .37)) + var green_ta: Terrain3DTextureAsset = await create_texture_asset("Grass", green_gr, 1024) + green_ta.uv_scale = 0.1 + green_ta.detiling_rotation = 0.1 + + var brown_gr := Gradient.new() + brown_gr.set_color(0, Color.from_hsv(30./360., .4, .3)) + brown_gr.set_color(1, Color.from_hsv(30./360., .4, .4)) + var brown_ta: Terrain3DTextureAsset = await create_texture_asset("Dirt", brown_gr, 1024) + brown_ta.uv_scale = 0.03 + green_ta.detiling_rotation = 0.1 + + var grass_ma: Terrain3DMeshAsset = create_mesh_asset("Grass", Color.from_hsv(120./360., .4, .37)) + + # Create a terrain + var terrain := Terrain3D.new() + terrain.name = "Terrain3D" + add_child(terrain, true) + + # Set material and assets + terrain.material.world_background = Terrain3DMaterial.NONE + terrain.material.auto_shader = true + terrain.material.set_shader_param("auto_slope", 10) + terrain.material.set_shader_param("blend_sharpness", .975) + terrain.assets = Terrain3DAssets.new() + terrain.assets.set_texture(0, green_ta) + terrain.assets.set_texture(1, brown_ta) + terrain.assets.set_mesh_asset(0, grass_ma) + + # Generate height map w/ 32-bit noise and import it with scale + var noise := FastNoiseLite.new() + noise.frequency = 0.0005 + var img: Image = Image.create_empty(2048, 2048, false, Image.FORMAT_RF) + for x in img.get_width(): + for y in img.get_height(): + img.set_pixel(x, y, Color(noise.get_noise_2d(x, y), 0., 0., 1.)) + terrain.region_size = 1024 + terrain.data.import_images([img, null, null], Vector3(-1024, 0, -1024), 0.0, 150.0) + + # Instance foliage + var xforms: Array[Transform3D] + var width: int = 100 + var step: int = 2 + for x in range(0, width, step): + for z in range(0, width, step): + var pos := Vector3(x, 0, z) - Vector3(width, 0, width) * .5 + pos.y = terrain.data.get_height(pos) + xforms.push_back(Transform3D(Basis(), pos)) + terrain.instancer.add_transforms(0, xforms) + + # Enable the next line and `Debug/Visible Collision Shapes` to see collision + #terrain.collision.mode = Terrain3DCollision.DYNAMIC_EDITOR + + return terrain + + +func create_texture_asset(asset_name: String, gradient: Gradient, texture_size: int = 512) -> Terrain3DTextureAsset: + # Create noise map + var fnl := FastNoiseLite.new() + fnl.frequency = 0.004 + + # Create albedo noise texture + var alb_noise_tex := NoiseTexture2D.new() + alb_noise_tex.width = texture_size + alb_noise_tex.height = texture_size + alb_noise_tex.seamless = true + alb_noise_tex.noise = fnl + alb_noise_tex.color_ramp = gradient + await alb_noise_tex.changed + var alb_noise_img: Image = alb_noise_tex.get_image() + + # Create albedo + height texture + for x in alb_noise_img.get_width(): + for y in alb_noise_img.get_height(): + var clr: Color = alb_noise_img.get_pixel(x, y) + clr.a = clr.v # Noise as height + alb_noise_img.set_pixel(x, y, clr) + alb_noise_img.generate_mipmaps() + var albedo := ImageTexture.create_from_image(alb_noise_img) + + # Create normal + rough texture + var nrm_noise_tex := NoiseTexture2D.new() + nrm_noise_tex.width = texture_size + nrm_noise_tex.height = texture_size + nrm_noise_tex.as_normal_map = true + nrm_noise_tex.seamless = true + nrm_noise_tex.noise = fnl + await nrm_noise_tex.changed + var nrm_noise_img = nrm_noise_tex.get_image() + for x in nrm_noise_img.get_width(): + for y in nrm_noise_img.get_height(): + var normal_rgh: Color = nrm_noise_img.get_pixel(x, y) + normal_rgh.a = 0.8 # Roughness + nrm_noise_img.set_pixel(x, y, normal_rgh) + nrm_noise_img.generate_mipmaps() + var normal := ImageTexture.create_from_image(nrm_noise_img) + + var ta := Terrain3DTextureAsset.new() + ta.name = asset_name + ta.albedo_texture = albedo + ta.normal_texture = normal + return ta + + +func create_mesh_asset(asset_name: String, color: Color) -> Terrain3DMeshAsset: + var ma := Terrain3DMeshAsset.new() + ma.name = asset_name + ma.generated_type = Terrain3DMeshAsset.TYPE_TEXTURE_CARD + ma.material_override.albedo_color = color + return ma diff --git a/demo/src/CodeGenerated.gd.uid b/demo/src/CodeGenerated.gd.uid new file mode 100644 index 0000000..108d980 --- /dev/null +++ b/demo/src/CodeGenerated.gd.uid @@ -0,0 +1 @@ +uid://dakis6gu8b7nm diff --git a/demo/src/DemoScene.gd b/demo/src/DemoScene.gd new file mode 100644 index 0000000..979be71 --- /dev/null +++ b/demo/src/DemoScene.gd @@ -0,0 +1,23 @@ +@tool +extends Node + +@onready var terrain: Terrain3D = find_child("Terrain3D") + + +func _ready(): + if not Engine.is_editor_hint() and has_node("UI"): + $UI.player = $Player + + # Load Sky3D into the demo environment if enabled + if Engine.is_editor_hint() and has_node("Environment") and \ + Engine.get_singleton(&"EditorInterface").is_plugin_enabled("sky_3d"): + $Environment.queue_free() + var sky3d = load("res://addons/sky_3d/src/Sky3D.gd").new() + sky3d.name = "Sky3D" + add_child(sky3d, true) + move_child(sky3d, 1) + sky3d.owner = self + sky3d.current_time = 10 + sky3d.enable_editor_time = false + + diff --git a/demo/src/DemoScene.gd.uid b/demo/src/DemoScene.gd.uid new file mode 100644 index 0000000..2afcbc9 --- /dev/null +++ b/demo/src/DemoScene.gd.uid @@ -0,0 +1 @@ +uid://chstoagn42gbr diff --git a/demo/src/Enemy.gd b/demo/src/Enemy.gd new file mode 100644 index 0000000..c8d444c --- /dev/null +++ b/demo/src/Enemy.gd @@ -0,0 +1,58 @@ +extends CharacterBody3D + +const RETARGET_COOLDOWN: float = 1.0 + +@export var MOVE_SPEED: float = 50.0 +@export var target: Node3D + +@onready var nav_agent: NavigationAgent3D = $NavigationAgent3D + +var _retarget_timer: float = 1.0 + + +func _ready() -> void: + nav_agent.velocity_computed.connect(_on_velocity_computed) + + +func _process(p_delta: float) -> void: + _retarget_timer += p_delta + if _retarget_timer > RETARGET_COOLDOWN and target: + # Don't reset the target position every frame. It triggers an A* search, which is expensive. + _retarget_timer = 0.0 + nav_agent.set_target_position(target.global_position) + + +func is_on_nav_mesh() -> bool: + var closest_point := NavigationServer3D.map_get_closest_point(nav_agent.get_navigation_map(), global_position) + return global_position.distance_squared_to(closest_point) < nav_agent.path_max_distance ** 2 + + +func _physics_process(p_delta: float) -> void: + if nav_agent.is_navigation_finished(): + velocity.x = 0.0 + velocity.z = 0.0 + else: + var next_path_position: Vector3 = nav_agent.get_next_path_position() + var current_agent_position: Vector3 = global_position + var velocity_xz := (next_path_position - current_agent_position).normalized() * MOVE_SPEED + velocity.x = velocity_xz.x + velocity.z = velocity_xz.z + + velocity.y -= 40 * p_delta + + if nav_agent.avoidance_enabled: + nav_agent.set_velocity(velocity) + else: + _on_velocity_computed(velocity) + + # Ensure enemy doesn't fall through terrain when collision absent + if get_parent().terrain: + var height: float = get_parent().terrain.data.get_height(global_position) + if not is_nan(height): + global_position.y = maxf(global_position.y, height) + + +func _on_velocity_computed(p_safe_velocity: Vector3) -> void: + velocity.x = p_safe_velocity.x + velocity.z = p_safe_velocity.z + move_and_slide() diff --git a/demo/src/Enemy.gd.uid b/demo/src/Enemy.gd.uid new file mode 100644 index 0000000..72794d4 --- /dev/null +++ b/demo/src/Enemy.gd.uid @@ -0,0 +1 @@ +uid://6j2rrp5f1gjs diff --git a/demo/src/Player.gd b/demo/src/Player.gd new file mode 100644 index 0000000..8ae1b84 --- /dev/null +++ b/demo/src/Player.gd @@ -0,0 +1,81 @@ +extends CharacterBody3D + +@export var MOVE_SPEED: float = 50.0 +@export var JUMP_SPEED: float = 2.0 +@export var first_person: bool = false : + set(p_value): + first_person = p_value + if first_person: + var tween: Tween = create_tween() + tween.tween_property($CameraManager/Arm, "spring_length", 0.0, .33) + tween.tween_callback($Body.set_visible.bind(false)) + else: + $Body.visible = true + create_tween().tween_property($CameraManager/Arm, "spring_length", 6.0, .33) + +@export var gravity_enabled: bool = true : + set(p_value): + gravity_enabled = p_value + if not gravity_enabled: + velocity.y = 0 + +@export var collision_enabled: bool = true : + set(p_value): + collision_enabled = p_value + $CollisionShapeBody.disabled = ! collision_enabled + $CollisionShapeRay.disabled = ! collision_enabled + + +func _physics_process(p_delta) -> void: + var direction: Vector3 = get_camera_relative_input() + var h_veloc: Vector2 = Vector2(direction.x, direction.z).normalized() * MOVE_SPEED + if Input.is_key_pressed(KEY_SHIFT): + h_veloc *= 2 + velocity.x = h_veloc.x + velocity.z = h_veloc.y + if gravity_enabled: + velocity.y -= 40 * p_delta + move_and_slide() + + +# Returns the input vector relative to the camera. Forward is always the direction the camera is facing +func get_camera_relative_input() -> Vector3: + var input_dir: Vector3 = Vector3.ZERO + if Input.is_key_pressed(KEY_A): # Left + input_dir -= %Camera3D.global_transform.basis.x + if Input.is_key_pressed(KEY_D): # Right + input_dir += %Camera3D.global_transform.basis.x + if Input.is_key_pressed(KEY_W): # Forward + input_dir -= %Camera3D.global_transform.basis.z + if Input.is_key_pressed(KEY_S): # Backward + input_dir += %Camera3D.global_transform.basis.z + if Input.is_key_pressed(KEY_E) or Input.is_key_pressed(KEY_SPACE): # Up + velocity.y += JUMP_SPEED + MOVE_SPEED*.016 + if Input.is_key_pressed(KEY_Q): # Down + velocity.y -= JUMP_SPEED + MOVE_SPEED*.016 + if Input.is_key_pressed(KEY_KP_ADD) or Input.is_key_pressed(KEY_EQUAL): + MOVE_SPEED = clamp(MOVE_SPEED + .5, 5, 9999) + if Input.is_key_pressed(KEY_KP_SUBTRACT) or Input.is_key_pressed(KEY_MINUS): + MOVE_SPEED = clamp(MOVE_SPEED - .5, 5, 9999) + return input_dir + + +func _input(p_event: InputEvent) -> void: + if p_event is InputEventMouseButton and p_event.pressed: + if p_event.button_index == MOUSE_BUTTON_WHEEL_UP: + MOVE_SPEED = clamp(MOVE_SPEED + 5, 5, 9999) + elif p_event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + MOVE_SPEED = clamp(MOVE_SPEED - 5, 5, 9999) + + elif p_event is InputEventKey: + if p_event.pressed: + if p_event.keycode == KEY_V: + first_person = ! first_person + elif p_event.keycode == KEY_G: + gravity_enabled = ! gravity_enabled + elif p_event.keycode == KEY_C: + collision_enabled = ! collision_enabled + + # Else if up/down released + elif p_event.keycode in [ KEY_Q, KEY_E, KEY_SPACE ]: + velocity.y = 0 diff --git a/demo/src/Player.gd.uid b/demo/src/Player.gd.uid new file mode 100644 index 0000000..fa920b7 --- /dev/null +++ b/demo/src/Player.gd.uid @@ -0,0 +1 @@ +uid://dajlr3n5wjwmb diff --git a/demo/src/RuntimeNavigationBaker.gd b/demo/src/RuntimeNavigationBaker.gd new file mode 100644 index 0000000..be3629d --- /dev/null +++ b/demo/src/RuntimeNavigationBaker.gd @@ -0,0 +1,151 @@ +extends Node + +signal bake_finished + +@export var enabled: bool = true : set = set_enabled +@export var enter_cost: float = 0.0 : set = set_enter_cost +@export var travel_cost: float = 1.0 : set = set_travel_cost +@export_flags_3d_navigation var navigation_layers: int = 1 : set = set_navigation_layers +@export var template: NavigationMesh : set = set_template +@export var terrain: Terrain3D +@export var player: Node3D +@export var mesh_size := Vector3(256, 512, 256) +@export var min_rebake_distance: float = 64.0 +@export var bake_cooldown: float = 1.0 +@export_group("Debug") +@export var log_timing: bool = false + +var _scene_geometry: NavigationMeshSourceGeometryData3D +var _current_center := Vector3(INF,INF,INF) + +var _bake_task_id: int = -1 +var _bake_task_timer: float = 0.0 +var _bake_cooldown_timer: float = 0.0 +var _nav_region: NavigationRegion3D + + +func _ready(): + _nav_region = NavigationRegion3D.new() + _nav_region.navigation_layers = navigation_layers + _nav_region.enabled = enabled + _nav_region.enter_cost = enter_cost + _nav_region.travel_cost = travel_cost + + # Enabling edge connections comes with a performance penalty that causes hitches whenever + # the nav mesh is updated. The navigation server has to compare each edge, and it does this on + # the main thread. + _nav_region.use_edge_connections = false + + add_child(_nav_region) + + _update_map_cell_size() + + # If you're using ProtonScatter, you will want to delay this next call until after all + # your scatter nodes have finished setting up. Here, we just defer one frame so that nodes + # after this one in the tree get set up first + parse_scene.call_deferred() + + +func set_enabled(p_value: bool) -> void: + enabled = p_value + if _nav_region: + _nav_region.enabled = enabled + set_process(enabled and template) + + +func set_enter_cost(p_value: bool) -> void: + enter_cost = p_value + if _nav_region: + _nav_region.enter_cost = enter_cost + + +func set_travel_cost(p_value: bool) -> void: + travel_cost = p_value + if _nav_region: + _nav_region.travel_cost = travel_cost + + +func set_navigation_layers(p_value: int) -> void: + navigation_layers = p_value + if _nav_region: + _nav_region.navigation_layers = navigation_layers + + +func set_template(p_value: NavigationMesh) -> void: + template = p_value + set_process(enabled and template) + _update_map_cell_size() + + +func parse_scene() -> void: + _scene_geometry = NavigationMeshSourceGeometryData3D.new() + NavigationServer3D.parse_source_geometry_data(template, _scene_geometry, self) + + +func _update_map_cell_size() -> void: + if get_viewport() and template: + var map := get_viewport().find_world_3d().navigation_map + NavigationServer3D.map_set_cell_size(map, template.cell_size) + NavigationServer3D.map_set_cell_height(map, template.cell_height) + + +func _process(p_delta: float) -> void: + if _bake_task_id != -1: + _bake_task_timer += p_delta + + if not player or _bake_task_id != -1: + return + + if _bake_cooldown_timer > 0.0: + _bake_cooldown_timer -= p_delta + return + + var track_pos := player.global_position + if player is CharacterBody3D: + # Center on where the player is likely _going to be_: + track_pos += player.velocity * bake_cooldown + + if track_pos.distance_squared_to(_current_center) >= min_rebake_distance * min_rebake_distance: + _current_center = track_pos + _rebake(_current_center) + + +func _rebake(p_center: Vector3) -> void: + assert(template != null) + _bake_task_id = WorkerThreadPool.add_task(_task_bake.bind(p_center), false, "RuntimeNavigationBaker") + _bake_task_timer = 0.0 + _bake_cooldown_timer = bake_cooldown + + +func _task_bake(p_center: Vector3) -> void: + var nav_mesh: NavigationMesh = template.duplicate() + nav_mesh.filter_baking_aabb = AABB(-mesh_size * 0.5, mesh_size) + nav_mesh.filter_baking_aabb_offset = p_center + var source_geometry: NavigationMeshSourceGeometryData3D + source_geometry = _scene_geometry.duplicate() + + if terrain: + var aabb: AABB = nav_mesh.filter_baking_aabb + aabb.position += nav_mesh.filter_baking_aabb_offset + var faces: PackedVector3Array = terrain.generate_nav_mesh_source_geometry(aabb, false) + source_geometry.add_faces(faces, Transform3D.IDENTITY) + + if source_geometry.has_data(): + NavigationServer3D.bake_from_source_geometry_data(nav_mesh, source_geometry) + _bake_finished.call_deferred(nav_mesh) + else: + _bake_finished.call_deferred(null) + + +func _bake_finished(p_nav_mesh: NavigationMesh) -> void: + if log_timing: + print("Navigation bake took ", _bake_task_timer, "s") + + _bake_task_timer = 0.0 + _bake_task_id = -1 + + if p_nav_mesh: + _nav_region.navigation_mesh = p_nav_mesh + + bake_finished.emit() + assert(!NavigationServer3D.region_get_use_edge_connections(_nav_region.get_region_rid())) diff --git a/demo/src/RuntimeNavigationBaker.gd.uid b/demo/src/RuntimeNavigationBaker.gd.uid new file mode 100644 index 0000000..157d6ce --- /dev/null +++ b/demo/src/RuntimeNavigationBaker.gd.uid @@ -0,0 +1 @@ +uid://brh8x1wnycrl5 diff --git a/demo/src/UI.gd b/demo/src/UI.gd new file mode 100644 index 0000000..970a1ac --- /dev/null +++ b/demo/src/UI.gd @@ -0,0 +1,64 @@ +extends Control + + +var player: Node +var visible_mode: int = 1 + + +func _init() -> void: + RenderingServer.set_debug_generate_wireframes(true) + + +func _process(p_delta) -> void: + $Label.text = "FPS: %d\n" % Engine.get_frames_per_second() + if(visible_mode == 1): + $Label.text += "Move Speed: %.1f\n" % player.MOVE_SPEED if player else "" + $Label.text += "Position: %.1v\n" % player.global_position if player else "" + $Label.text += """ + Player + Move: WASDEQ,Space,Mouse + Move speed: Wheel,+/-,Shift + Camera View: V + Gravity toggle: G + Collision toggle: C + + Window + Quit: F8 + UI toggle: F9 + Render mode: F10 + Full screen: F11 + Mouse toggle: Escape / F12 + """ + + +func _unhandled_key_input(p_event: InputEvent) -> void: + if p_event is InputEventKey and p_event.pressed: + match p_event.keycode: + KEY_F8: + get_tree().quit() + KEY_F9: + visible_mode = (visible_mode + 1 ) % 3 + $Label/Panel.visible = (visible_mode == 1) + visible = visible_mode > 0 + KEY_F10: + var vp = get_viewport() + vp.debug_draw = (vp.debug_draw + 1 ) % 6 + get_viewport().set_input_as_handled() + KEY_F11: + toggle_fullscreen() + get_viewport().set_input_as_handled() + KEY_ESCAPE, KEY_F12: + if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + else: + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + get_viewport().set_input_as_handled() + + +func toggle_fullscreen() -> void: + if DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_EXCLUSIVE_FULLSCREEN or \ + DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN: + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) + DisplayServer.window_set_size(Vector2(1280, 720)) + else: + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_EXCLUSIVE_FULLSCREEN) diff --git a/demo/src/UI.gd.uid b/demo/src/UI.gd.uid new file mode 100644 index 0000000..8a92755 --- /dev/null +++ b/demo/src/UI.gd.uid @@ -0,0 +1 @@ +uid://dne6na1m4xku8