diff --git a/addons/godot-rapier2d/Fluid2D.svg b/addons/godot-rapier2d/Fluid2D.svg deleted file mode 100644 index e55507f..0000000 --- a/addons/godot-rapier2d/Fluid2D.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/godot-rapier2d/LICENSE b/addons/godot-rapier2d/LICENSE deleted file mode 100644 index 556baa8..0000000 --- a/addons/godot-rapier2d/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Fabrice Cipolla, Sp3ctralCat and Dragos Daian - -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. diff --git a/addons/godot-rapier2d/Radial2D.svg b/addons/godot-rapier2d/Radial2D.svg deleted file mode 100644 index e7f0c49..0000000 --- a/addons/godot-rapier2d/Radial2D.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/addons/godot-rapier2d/THIRDPARTY.txt b/addons/godot-rapier2d/THIRDPARTY.txt deleted file mode 100644 index d115c87..0000000 --- a/addons/godot-rapier2d/THIRDPARTY.txt +++ /dev/null @@ -1,288 +0,0 @@ -Godot Rapier incorporates third-party material from the projects listed below. - -Godot Engine (https://github.com/godotengine/godot) - - Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). - Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to - deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -godot-cpp (https://github.com/godotengine/godot-cpp) - - Copyright (c) 2017-present Godot Engine contributors. - Copyright (c) 2022-present Mikael Hermansson. - - 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. - -rapier (https://github.com/dimforge/rapier) - - Copyright 2020 Sébastien Crozet - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -Godot Jolt (https://github.com/godot-jolt/godot-jolt) - - Copyright (c) Mikael Hermansson and Godot Jolt 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. - -salva (https://github.com/dimforge/salva) - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 Sébastien Crozet - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/addons/godot-rapier2d/bin/godot_rapier.wasm b/addons/godot-rapier2d/bin/godot_rapier.wasm deleted file mode 100644 index a2c8c6d..0000000 Binary files a/addons/godot-rapier2d/bin/godot_rapier.wasm and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.android.aarch64-linux-android.so b/addons/godot-rapier2d/bin/libgodot_rapier.android.aarch64-linux-android.so deleted file mode 100644 index 38fb157..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.android.aarch64-linux-android.so and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.android.i686-linux-android.so b/addons/godot-rapier2d/bin/libgodot_rapier.android.i686-linux-android.so deleted file mode 100644 index b7e8859..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.android.i686-linux-android.so and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.android.x86_64-linux-android.so b/addons/godot-rapier2d/bin/libgodot_rapier.android.x86_64-linux-android.so deleted file mode 100644 index aea50f0..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.android.x86_64-linux-android.so and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.ios.framework/Info.plist b/addons/godot-rapier2d/bin/libgodot_rapier.ios.framework/Info.plist deleted file mode 100644 index 56c6af5..0000000 --- a/addons/godot-rapier2d/bin/libgodot_rapier.ios.framework/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleInfoDictionaryVersion - 6.0 - CFBundleDevelopmentRegion - en - CFBundleExecutable - libgodot_rapier.ios - CFBundleName - Godot Rapier2D - CFBundleDisplayName - Godot Rapier2D - CFBundleIdentifier - org.godot-rapier2d.godot-rapier2d - NSHumanReadableCopyright - Copyright (c) 2023-present Fabrice Cipolla, Sp3ctralCat and Dragos Daian. - CFBundleVersion - 0.12.0 - CFBundleShortVersionString - 0.12.0 - CFBundlePackageType - FMWK - CSResourcesFileMapped - - DTPlatformName - iphoneos - MinimumOSVersion - 12.0 - - diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.ios.framework/libgodot_rapier.ios b/addons/godot-rapier2d/bin/libgodot_rapier.ios.framework/libgodot_rapier.ios deleted file mode 100644 index 02effc9..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.ios.framework/libgodot_rapier.ios and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.linux.x86_64-unknown-linux-gnu.so b/addons/godot-rapier2d/bin/libgodot_rapier.linux.x86_64-unknown-linux-gnu.so deleted file mode 100644 index 4128396..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.linux.x86_64-unknown-linux-gnu.so and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/Resources/Info.plist b/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/Resources/Info.plist deleted file mode 100644 index bde2089..0000000 --- a/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/Resources/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleExecutable - libgodot_rapier.macos.dylib - CFBundleIdentifier - org.godot-rapier2d.godot-rapier2d - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Godot Rapier2D - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0.0 - CFBundleSupportedPlatforms - - MacOSX - - NSHumanReadableCopyright - Copyright (c) 2023-present Fabrice Cipolla, Sp3ctralCat and Dragos Daian. - CFBundleVersion - 1.0.0 - LSMinimumSystemVersion - 10.12 - - diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/_CodeSignature/CodeResources b/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/_CodeSignature/CodeResources deleted file mode 100644 index 1eaabd7..0000000 --- a/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/_CodeSignature/CodeResources +++ /dev/null @@ -1,128 +0,0 @@ - - - - - files - - Resources/Info.plist - - FZy7+eYDJuYSbntBY+mwtyopSvE= - - - files2 - - Resources/Info.plist - - hash2 - - MMDYIVdI76poLGbcF02jJpJ+oHcs7q1NjyfgsaN1jus= - - - - rules - - ^Resources/ - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Resources/Base\.lproj/ - - weight - 1010 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ - - nested - - weight - 10 - - ^.* - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^Resources/ - - weight - 20 - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Resources/Base\.lproj/ - - weight - 1010 - - ^[^/]+$ - - nested - - weight - 10 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/libgodot_rapier.macos.dylib b/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/libgodot_rapier.macos.dylib deleted file mode 100644 index f710e7b..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.macos.framework/libgodot_rapier.macos.dylib and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.windows.aarch64-pc-windows-msvc.dll b/addons/godot-rapier2d/bin/libgodot_rapier.windows.aarch64-pc-windows-msvc.dll deleted file mode 100644 index 971cae5..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.windows.aarch64-pc-windows-msvc.dll and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.windows.i686-pc-windows-msvc.dll b/addons/godot-rapier2d/bin/libgodot_rapier.windows.i686-pc-windows-msvc.dll deleted file mode 100644 index 524761b..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.windows.i686-pc-windows-msvc.dll and /dev/null differ diff --git a/addons/godot-rapier2d/bin/libgodot_rapier.windows.x86_64-pc-windows-msvc.dll b/addons/godot-rapier2d/bin/libgodot_rapier.windows.x86_64-pc-windows-msvc.dll deleted file mode 100644 index 9847e37..0000000 Binary files a/addons/godot-rapier2d/bin/libgodot_rapier.windows.x86_64-pc-windows-msvc.dll and /dev/null differ diff --git a/addons/godot-rapier2d/bin/wasm-nothreads/godot_rapier.wasm b/addons/godot-rapier2d/bin/wasm-nothreads/godot_rapier.wasm deleted file mode 100644 index 2a9fdf3..0000000 Binary files a/addons/godot-rapier2d/bin/wasm-nothreads/godot_rapier.wasm and /dev/null differ diff --git a/addons/godot-rapier2d/bin/~libgodot_rapier.windows.x86_64-pc-windows-msvc.dll b/addons/godot-rapier2d/bin/~libgodot_rapier.windows.x86_64-pc-windows-msvc.dll deleted file mode 100644 index 9847e37..0000000 Binary files a/addons/godot-rapier2d/bin/~libgodot_rapier.windows.x86_64-pc-windows-msvc.dll and /dev/null differ diff --git a/addons/godot-rapier2d/circle_mesh.tres b/addons/godot-rapier2d/circle_mesh.tres deleted file mode 100644 index 630e7ea..0000000 --- a/addons/godot-rapier2d/circle_mesh.tres +++ /dev/null @@ -1,15 +0,0 @@ -[gd_resource type="ArrayMesh" format=3 uid="uid://dahp28qij58i1"] - -[resource] -_surfaces = [{ -"2d": true, -"aabb": AABB(-16, -16, 0, 32, 32, 0), -"attribute_data": PackedByteArray(0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 128, 63), -"format": 34393296913, -"index_count": 6, -"index_data": PackedByteArray(3, 0, 0, 0, 1, 0, 1, 0, 2, 0, 3, 0), -"primitive": 3, -"uv_scale": Vector4(0, 0, 0, 0), -"vertex_count": 4, -"vertex_data": PackedByteArray(0, 0, 128, 193, 0, 0, 128, 65, 0, 0, 128, 193, 0, 0, 128, 193, 0, 0, 128, 65, 0, 0, 128, 193, 0, 0, 128, 65, 0, 0, 128, 65) -}] diff --git a/addons/godot-rapier2d/faucet_2d.gd b/addons/godot-rapier2d/faucet_2d.gd deleted file mode 100644 index 6fd8653..0000000 --- a/addons/godot-rapier2d/faucet_2d.gd +++ /dev/null @@ -1,27 +0,0 @@ -class_name Faucet2D -extends Fluid2D - -@export var interval := 0.06 -@export var max_particles: int = 1000 -@export var width: int = 4 -@export var height: int = 2 - -var points_new: PackedVector2Array -var velocities_new: PackedVector2Array - - -func _ready(): - points_new = create_rectangle_points(width, height) - velocities_new.resize(points_new.size()) - var gravity_value = ProjectSettings.get("physics/2d/default_gravity") - var gravity_dir = ProjectSettings.get("physics/2d/default_gravity_vector") - var dir = global_transform.basis_xform(gravity_dir * gravity_value) - velocities_new.fill(dir) - get_tree().create_timer(interval).timeout.connect(_on_timer_timeout) - - -func _on_timer_timeout(): - get_tree().create_timer(interval).timeout.connect(_on_timer_timeout) - if len(points) > max_particles: - return - add_points_and_velocities(points_new, velocities_new) diff --git a/addons/godot-rapier2d/fluid_2d_circle.gd b/addons/godot-rapier2d/fluid_2d_circle.gd deleted file mode 100644 index 5c93e74..0000000 --- a/addons/godot-rapier2d/fluid_2d_circle.gd +++ /dev/null @@ -1,10 +0,0 @@ -@tool -extends Fluid2D - -@export var circle_radius := 10: - set(value): - if circle_radius != value: - circle_radius = value - points = create_circle_points(circle_radius) - get: - return circle_radius diff --git a/addons/godot-rapier2d/fluid_2d_rectangle.gd b/addons/godot-rapier2d/fluid_2d_rectangle.gd deleted file mode 100644 index d1eb6a2..0000000 --- a/addons/godot-rapier2d/fluid_2d_rectangle.gd +++ /dev/null @@ -1,17 +0,0 @@ -@tool -extends Fluid2D - -@export var height := 10: - set(value): - if height != value: - height = value - points = create_rectangle_points(width, height) - get: - return height -@export var width := 10: - set(value): - if width != value: - width = value - points = create_rectangle_points(width, height) - get: - return width diff --git a/addons/godot-rapier2d/fluid_2d_renderer.gd b/addons/godot-rapier2d/fluid_2d_renderer.gd deleted file mode 100644 index dca76dd..0000000 --- a/addons/godot-rapier2d/fluid_2d_renderer.gd +++ /dev/null @@ -1,31 +0,0 @@ -@tool -class_name Fluid2DRenderer -extends MultiMeshInstance2D - -@export var fluid: Fluid2D -@export var color: Color = Color(0.8, 0.8, 0.8, 0.3) -@export var mesh_scale: Vector2 = Vector2(5, 5) - - -func _ready(): - if multimesh == null: - multimesh = MultiMesh.new() - multimesh.mesh = load("res://addons/godot-rapier2d/circle_mesh.tres").duplicate() - multimesh.use_colors = true - if texture == null: - texture = load("res://addons/godot-rapier2d/Radial2D.svg") - - -func _process(_delta): - if fluid == null: - return - global_transform = fluid.global_transform - var index = 0 - multimesh.instance_count = fluid.points.size() - var points = fluid.points - for i in points.size(): - var point = points[i] - var new_transform: Transform2D = Transform2D(0, mesh_scale, 0, point) - multimesh.set_instance_transform_2d(index, new_transform) - multimesh.set_instance_color(index, color) - index += 1 diff --git a/addons/godot-rapier2d/fluid_2d_shader_renderer.gd b/addons/godot-rapier2d/fluid_2d_shader_renderer.gd deleted file mode 100644 index f2a4c0c..0000000 --- a/addons/godot-rapier2d/fluid_2d_shader_renderer.gd +++ /dev/null @@ -1,87 +0,0 @@ -@tool -class_name Fluid2DShaderRenderer -extends CanvasLayer - -@export var fluid: Fluid2D: - set(value): - fluid = value - update_configuration_warnings() -@export var camera: Camera2D -@export var water_material: Material = load("res://addons/godot-rapier2d/water_shader.tres") -@export var mesh_scale: Vector2 = Vector2(5, 5) -var fluid_renderer: Fluid2DRenderer -var inside_camera: Camera2D: - set(value): - inside_camera = value - update_configuration_warnings() -var sub_viewport_container: SubViewportContainer -var sub_viewport: SubViewport - - -func _get_configuration_warnings(): - var warnings = [] - if camera == null: - warnings += ["Camera property is empty."] - if fluid == null: - warnings += ["Fluid property is empty."] - return warnings - - -func _create_subviewport_container(): - sub_viewport_container = SubViewportContainer.new() - sub_viewport_container.name = "SubViewportContainer" - add_child(sub_viewport_container) - sub_viewport_container.material = water_material - sub_viewport_container.size = Vector2( - ProjectSettings.get("display/window/size/viewport_width"), - ProjectSettings.get("display/window/size/viewport_height") - ) - - -func _create_subviewport(): - sub_viewport = SubViewport.new() - sub_viewport.name = "SubViewport" - sub_viewport_container.add_child(sub_viewport) - sub_viewport.transparent_bg = true - sub_viewport.size = sub_viewport_container.size - - -func _create_fluid_renderer(): - fluid_renderer = Fluid2DRenderer.new() - fluid_renderer.name = "Fluid2DRenderer" - fluid_renderer.color = Color(255, 0, 255) - fluid_renderer.mesh_scale = mesh_scale - fluid_renderer.fluid = fluid - sub_viewport.add_child(fluid_renderer) - - -func _create_inside_camera(): - inside_camera = Camera2D.new() - inside_camera.name = "Camera2D" - inside_camera.material = water_material - sub_viewport.add_child(inside_camera) - - -func _ready() -> void: - _create_subviewport_container() - _create_subviewport() - _create_fluid_renderer() - _create_inside_camera() - if fluid: - fluid.debug_draw = false - - -func _process(_delta: float) -> void: - if camera != null: - inside_camera.offset = camera.offset - inside_camera.zoom = camera.zoom - inside_camera.transform = camera.transform - sub_viewport_container.scale = Vector2(1.0 / camera.zoom.x, 1.0 / camera.zoom.y) - sub_viewport_container.position = camera.global_position - sub_viewport.size = sub_viewport_container.size - if camera.anchor_mode == Camera2D.AnchorMode.ANCHOR_MODE_FIXED_TOP_LEFT: - sub_viewport_container.position -= sub_viewport_container.size / 2 - if !camera.ignore_rotation: - sub_viewport_container.rotation = camera.global_rotation - else: - sub_viewport_container.rotation = 0 diff --git a/addons/godot-rapier2d/godot-rapier2d.gdextension b/addons/godot-rapier2d/godot-rapier2d.gdextension deleted file mode 100644 index de8926f..0000000 --- a/addons/godot-rapier2d/godot-rapier2d.gdextension +++ /dev/null @@ -1,34 +0,0 @@ -[configuration] - -entry_symbol = "gdext_rust_init" -compatibility_minimum = 4.3 - - -[libraries] - -macos.debug = "bin/libgodot_rapier.macos.framework" -macos.release = "bin/libgodot_rapier.macos.framework" -windows.debug.x86_64 = "bin/libgodot_rapier.windows.x86_64-pc-windows-msvc.dll" -windows.release.x86_64 = "bin/libgodot_rapier.windows.x86_64-pc-windows-msvc.dll" -windows.debug.x86_32 = "bin/libgodot_rapier.windows.i686-pc-windows-msvc.dll" -windows.release.x86_32 = "bin/libgodot_rapier.windows.i686-pc-windows-msvc.dll" -windows.debug.arm64 = "bin/libgodot_rapier.windows.aarch64-pc-windows-msvc.dll" -windows.release.arm64 = "bin/libgodot_rapier.windows.aarch64-pc-windows-msvc.dll" -linux.debug.x86_64 = "bin/libgodot_rapier.linux.x86_64-unknown-linux-gnu.so" -linux.release.x86_64 = "bin/libgodot_rapier.linux.x86_64-unknown-linux-gnu.so" -android.debug.x86_64 = "bin/libgodot_rapier.android.x86_64-linux-android.so" -android.release.x86_64 = "bin/libgodot_rapier.android.x86_64-linux-android.so" -android.debug.x86_32 = "bin/libgodot_rapier.android.i686-linux-android.so" -android.release.x86_32 = "bin/libgodot_rapier.android.i686-linux-android.so" -android.debug.arm64 = "bin/libgodot_rapier.android.aarch64-linux-android.so" -android.release.arm64 = "bin/libgodot_rapier.android.aarch64-linux-android.so" -ios.debug = "bin/libgodot_rapier.ios.framework" -ios.release = "bin/libgodot_rapier.ios.framework" -web.debug.threads.wasm32 = "bin/godot_rapier.wasm" -web.release.threads.wasm32 = "bin/godot_rapier.wasm" -web.debug.wasm32 = "bin/wasm-nothreads/godot_rapier.wasm" -web.release.wasm32 = "bin/wasm-nothreads/godot_rapier.wasm" - -[icons] - -Fluid2D = "Fluid2D.svg" diff --git a/addons/godot-rapier2d/logo_square_2d.png b/addons/godot-rapier2d/logo_square_2d.png deleted file mode 100644 index 3a0eb7f..0000000 Binary files a/addons/godot-rapier2d/logo_square_2d.png and /dev/null differ diff --git a/addons/godot-rapier2d/plugin.info.cfg b/addons/godot-rapier2d/plugin.info.cfg deleted file mode 100644 index 363abc1..0000000 --- a/addons/godot-rapier2d/plugin.info.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[plugin] - -name="Godot Rapier 2D" -description="A 2D and 3D drop-in replacement for the Godot engine that adds stability and fluids." -author="appsinacup" -version="0.8.8" -flavour="godot-rapier-2d-single-simd-parallel" -script="" diff --git a/addons/godot-rapier2d/rapier_state_2d.gd b/addons/godot-rapier2d/rapier_state_2d.gd deleted file mode 100644 index ee5a98f..0000000 --- a/addons/godot-rapier2d/rapier_state_2d.gd +++ /dev/null @@ -1,105 +0,0 @@ -### Supports [CollisionObject2D], [Joint2D] and [CollisionShape2D]. -@icon("res://addons/godot-rapier2d/logo_square_2d.png") -class_name Rapier2DState -extends Node - -var state: Dictionary = {} - - -func _is_physics_object(node: Node) -> bool: - return node is CollisionObject2D or node is Joint2D - - -func _get_all_physics_nodes(p_node: Node, path: String = "/root/") -> Array[String]: - var results: Array[String] = [] - if path == "/root/" && _is_physics_object(p_node): - results.append(path + p_node.name) - path += p_node.name + "/" - for node in p_node.get_children(): - if _is_physics_object(node): - results.append(path + node.name) - if node.get_child_count() > 0: - results.append_array(_get_all_physics_nodes(node, path)) - return results - - -## Save a node's physics state -func save_node(rid: RID, save_json: bool): - if save_json: - return JSON.parse_string(RapierPhysicsServer2D.export_json(rid)) - return RapierPhysicsServer2D.export_binary(rid) - - -## Load a node's physics state -func load_node(rid: RID, data: PackedByteArray): - RapierPhysicsServer2D.import_binary(rid, data) - - -## Save the state of whole world (single space) -func save_state(save_json: bool = false) -> int: - var physics_nodes := _get_all_physics_nodes(get_tree().current_scene) - for node_path in physics_nodes: - var node := get_node(node_path) - var rid: RID - if node is CollisionObject2D: - rid = node.get_rid() - for owner_id in node.get_shape_owners(): - for owner_shape_id in node.shape_owner_get_shape_count(owner_id): - var shape_rid = node.shape_owner_get_shape(owner_id, owner_shape_id).get_rid() - state[node_path + "/" + str(owner_id) + "/" + str(owner_shape_id)] = save_node( - shape_rid, save_json - ) - if node is Joint2D: - rid = node.get_rid() - state[node_path] = save_node(rid, save_json) - var space_rid = get_viewport().world_2d.space - state["space"] = save_node(space_rid, save_json) - state["id"] = RapierPhysicsServer2D.get_global_id() - return hash(JSON.stringify(state)) - - -## Load the state of whole world (single space) -func load_state() -> int: - var physics_nodes := _get_all_physics_nodes(get_tree().current_scene) - for node_path in physics_nodes: - var node := get_node(node_path) - var rid: RID - if node is CollisionObject2D: - rid = node.get_rid() - for owner_id in node.get_shape_owners(): - for owner_shape_id in node.shape_owner_get_shape_count(owner_id): - var shape_rid = node.shape_owner_get_shape(owner_id, owner_shape_id).get_rid() - var shape_state = state[ - node_path + "/" + str(owner_id) + "/" + str(owner_shape_id) - ] - load_node(shape_rid, JSON.parse_string(shape_state)) - if node is Joint2D: - rid = node.get_rid() - var node_state = state[node_path] - load_node(rid, JSON.parse_string(node_state)) - var space_rid = get_viewport().world_2d.space - load_node(space_rid, JSON.parse_string(state["space"])) - RapierPhysicsServer2D.set_global_id(int(state["id"])) - return hash(JSON.stringify(state)) - - -## Export the state to file -func export_state(file_name: String = "user://state.json"): - save_state(false) - FileAccess.open(file_name, FileAccess.WRITE).store_string(JSON.stringify(state, " ")) - - -## Import the state from file -func import_state(file_name: String = "user://state.json"): - state = JSON.parse_string(FileAccess.open(file_name, FileAccess.READ).get_as_text()) - load_state() - - -func _notification(what: int) -> void: - if what == NOTIFICATION_ENTER_TREE: - print("enter tree") - if what == NOTIFICATION_EXIT_TREE: - save_state(false) - FileAccess.open("user://save.json", FileAccess.WRITE).store_string( - JSON.stringify(state, " ") - ) diff --git a/addons/godot-rapier2d/water_shader.gdshader b/addons/godot-rapier2d/water_shader.gdshader deleted file mode 100644 index ce31fd6..0000000 --- a/addons/godot-rapier2d/water_shader.gdshader +++ /dev/null @@ -1,22 +0,0 @@ -shader_type canvas_item; - -uniform float threshold = 0.8; -uniform vec4 water_color: source_color = vec4(0.12,0.24,0.45,0.65); -uniform vec4 test_color: source_color = vec4(1,0,1,1); - -uniform float speed = 0.1; // Speed of movement -uniform float amplitude = 0.1; // Amplitude of movement - -uniform sampler2D water_texture; - -void fragment(){ - float displacement = sin(TIME * speed) * amplitude; - vec4 screen_tex = texture(TEXTURE, SCREEN_UV).rgba; - - float color_distance = screen_tex.r; - if (color_distance > threshold) { - COLOR = texture(water_texture, SCREEN_UV + displacement).rgba * water_color; - } else { - COLOR = vec4(0.0); - } -} \ No newline at end of file diff --git a/addons/godot-rapier2d/water_shader.tres b/addons/godot-rapier2d/water_shader.tres deleted file mode 100644 index 1566b3c..0000000 --- a/addons/godot-rapier2d/water_shader.tres +++ /dev/null @@ -1,11 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://cysnk7s2ll173"] - -[ext_resource type="Shader" path="res://addons/godot-rapier2d/water_shader.gdshader" id="1_wgm3x"] - -[resource] -shader = ExtResource("1_wgm3x") -shader_parameter/threshold = 0.8 -shader_parameter/water_color = Color(0.12, 0.24, 0.45, 0.65) -shader_parameter/test_color = Color(1, 0, 1, 1) -shader_parameter/speed = 0.1 -shader_parameter/amplitude = 0.1 diff --git a/addons/guide/debugger/guide_debugger.gd b/addons/guide/debugger/guide_debugger.gd new file mode 100644 index 0000000..346a5d1 --- /dev/null +++ b/addons/guide/debugger/guide_debugger.gd @@ -0,0 +1,104 @@ +extends MarginContainer + +@onready var _actions:Container = %Actions +@onready var _inputs:Container = %Inputs +@onready var _priorities:Container = %Priorities +@onready var _formatter:GUIDEInputFormatter = GUIDEInputFormatter.for_active_contexts() + + +func _ready(): + process_mode = Node.PROCESS_MODE_ALWAYS + GUIDE.input_mappings_changed.connect(_update_priorities) + _update_priorities() + +func _process(delta): + if not is_visible_in_tree(): + return + + var index:int = 0 + for mapping in GUIDE._active_action_mappings: + var action:GUIDEAction = mapping.action + + var action_name:String = action.name + if action_name == "": + action_name = action._editor_name() + + var action_state:String = "" + match(action._last_state): + GUIDEAction.GUIDEActionState.COMPLETED: + action_state = "Completed" + GUIDEAction.GUIDEActionState.ONGOING: + action_state = "Ongoing" + GUIDEAction.GUIDEActionState.TRIGGERED: + action_state = "Triggered" + + var action_value:String = "" + match(action.action_value_type): + GUIDEAction.GUIDEActionValueType.BOOL: + action_value = str(action.value_bool) + GUIDEAction.GUIDEActionValueType.AXIS_1D: + action_value = str(action.value_axis_1d) + GUIDEAction.GUIDEActionValueType.AXIS_2D: + action_value = str(action.value_axis_2d) + GUIDEAction.GUIDEActionValueType.AXIS_3D: + action_value = str(action.value_axis_3d) + + + + + var label := _get_label(_actions, index) + label.text = "[%s] %s - %s" % [action_name, action_state, action_value] + + index += 1 + + # Clean out all labels we don't need anymore + _cleanup(_actions, index) + + index = 0 + for input in GUIDE._active_inputs: + var input_label = _formatter.input_as_text(input, false) + var input_value:String = str(input._value) + + var label := _get_label(_inputs, index) + label.text = "%s - %s" % [input_label, input_value] + index += 1 + + _cleanup(_inputs, index) + + +func _get_label(container:Container, index:int) -> Label: + var label:Label = null + if container.get_child_count() > index: + # reuse existing label + label = container.get_child(index) + else: + # make a new one + label = Label.new() + label.mouse_filter = Control.MOUSE_FILTER_IGNORE + container.add_child(label) + return label + +func _cleanup(container:Container, index:int) -> void: + while container.get_child_count() > index: + var to_free = container.get_child(index) + container.remove_child(to_free) + to_free.queue_free() + +func _update_priorities(): + # since we don't update these per frame, we can just clear them out and + # rebuild them when mapping contexts change + _cleanup(_priorities, 0) + + for mapping:GUIDEActionMapping in GUIDE._active_action_mappings: + var action := mapping.action + if GUIDE._actions_sharing_input.has(action): + var label := Label.new() + var names = ", ".join(GUIDE._actions_sharing_input[action].map(func(it): return it._editor_name())) + label.text = "[%s] > [%s]" % [action._editor_name(), names] + _priorities.add_child(label) + + + if _priorities.get_child_count() == 0: + var label := Label.new() + label.text = "" + _priorities.add_child(label) diff --git a/addons/guide/debugger/guide_debugger.tscn b/addons/guide/debugger/guide_debugger.tscn new file mode 100644 index 0000000..0e7caf4 --- /dev/null +++ b/addons/guide/debugger/guide_debugger.tscn @@ -0,0 +1,50 @@ +[gd_scene load_steps=2 format=3 uid="uid://dkr80d2pi0d41"] + +[ext_resource type="Script" path="res://addons/guide/debugger/guide_debugger.gd" id="1_ckdvj"] + +[node name="GuideDebugger" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +script = ExtResource("1_ckdvj") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="Label" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "G.U.I.D.E - Debugger" + +[node name="Label2" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Actions" + +[node name="Actions" type="VFlowContainer" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 + +[node name="Label3" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Inputs" + +[node name="Inputs" type="VFlowContainer" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 + +[node name="Label4" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Action Priority" + +[node name="Priorities" type="VFlowContainer" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 diff --git a/addons/guide/editor/action_mapping_editor/action_mapping_editor.gd b/addons/guide/editor/action_mapping_editor/action_mapping_editor.gd new file mode 100644 index 0000000..03dbdd8 --- /dev/null +++ b/addons/guide/editor/action_mapping_editor/action_mapping_editor.gd @@ -0,0 +1,138 @@ +@tool +extends MarginContainer + +const ActionSlot = preload("../action_slot/action_slot.gd") +const Utils = preload("../utils.gd") +const ArrayEdit = preload("../array_edit/array_edit.gd") + +signal delete_requested() +signal duplicate_requested() + +@export var input_mapping_editor_scene:PackedScene +@onready var _action_slot:ActionSlot = %ActionSlot +@onready var _input_mappings:ArrayEdit = %InputMappings + +const ClassScanner = preload("../class_scanner.gd") + +var _plugin:EditorPlugin +var _scanner:ClassScanner +var _undo_redo:EditorUndoRedoManager + +var _mapping:GUIDEActionMapping + +func _ready(): + _action_slot.action_changed.connect(_on_action_changed) + _input_mappings.delete_requested.connect(_on_input_mapping_delete_requested) + _input_mappings.add_requested.connect(_on_input_mappings_add_requested) + _input_mappings.move_requested.connect(_on_input_mappings_move_requested) + _input_mappings.clear_requested.connect(_on_input_mappings_clear_requested) + _input_mappings.duplicate_requested.connect(_on_input_mappings_duplicate_requested) + _input_mappings.collapse_state_changed.connect(_on_input_mappings_collapse_state_changed) + +func initialize(plugin:EditorPlugin, scanner:ClassScanner): + _plugin = plugin + _scanner = scanner + _undo_redo = _plugin.get_undo_redo() + + +func edit(mapping:GUIDEActionMapping): + assert(_mapping == null) + _mapping = mapping + + _mapping.changed.connect(_update) + + _update() + + +func _update(): + _input_mappings.clear() + + _action_slot.action = _mapping.action + + for i in _mapping.input_mappings.size(): + var input_mapping = _mapping.input_mappings[i] + var input_mapping_editor = input_mapping_editor_scene.instantiate() + _input_mappings.add_item(input_mapping_editor) + + input_mapping_editor.initialize(_plugin, _scanner) + input_mapping_editor.edit(input_mapping) + + _input_mappings.collapsed = _mapping.get_meta("_guide_input_mappings_collapsed", false) + +func _on_action_changed(): + _undo_redo.create_action("Change action") + _undo_redo.add_do_property(_mapping, "action", _action_slot.action) + _undo_redo.add_undo_property(_mapping, "action", _mapping.action) + _undo_redo.commit_action() + + +func _on_input_mappings_add_requested(): + var values = _mapping.input_mappings.duplicate() + var new_mapping = GUIDEInputMapping.new() + values.append(new_mapping) + + _undo_redo.create_action("Add input mapping") + + _undo_redo.add_do_property(_mapping, "input_mappings", values) + _undo_redo.add_undo_property(_mapping, "input_mappings", _mapping.input_mappings) + + _undo_redo.commit_action() + + +func _on_input_mapping_delete_requested(index:int): + var values = _mapping.input_mappings.duplicate() + values.remove_at(index) + + _undo_redo.create_action("Delete input mapping") + _undo_redo.add_do_property(_mapping, "input_mappings", values) + _undo_redo.add_undo_property(_mapping, "input_mappings", _mapping.input_mappings) + + _undo_redo.commit_action() + + +func _on_input_mappings_move_requested(from:int, to:int): + var values = _mapping.input_mappings.duplicate() + var mapping = values[from] + values.remove_at(from) + if from < to: + to -= 1 + values.insert(to, mapping) + + _undo_redo.create_action("Move input mapping") + _undo_redo.add_do_property(_mapping, "input_mappings", values) + _undo_redo.add_undo_property(_mapping, "input_mappings", _mapping.input_mappings) + + _undo_redo.commit_action() + + +func _on_input_mappings_clear_requested(): + var values:Array[GUIDEInputMapping] = [] + _undo_redo.create_action("Clear input mappings") + _undo_redo.add_do_property(_mapping, "input_mappings", values) + _undo_redo.add_undo_property(_mapping, "input_mappings", _mapping.input_mappings) + + _undo_redo.commit_action() + +func _on_input_mappings_duplicate_requested(index:int): + var values = _mapping.input_mappings.duplicate() + var copy:GUIDEInputMapping = values[index].duplicate() + copy.input = Utils.duplicate_if_inline(copy.input) + + for i in copy.modifiers.size(): + copy.modifiers[i] = Utils.duplicate_if_inline(copy.modifiers[i]) + + for i in copy.triggers.size(): + copy.triggers[i] = Utils.duplicate_if_inline(copy.triggers[i]) + + # insert copy after original + values.insert(index+1, copy) + + _undo_redo.create_action("Duplicate input mapping") + _undo_redo.add_do_property(_mapping, "input_mappings", values) + _undo_redo.add_undo_property(_mapping, "input_mappings", _mapping.input_mappings) + + _undo_redo.commit_action() + + +func _on_input_mappings_collapse_state_changed(new_state:bool): + _mapping.set_meta("_guide_input_mappings_collapsed", new_state) diff --git a/addons/guide/editor/action_mapping_editor/action_mapping_editor.tscn b/addons/guide/editor/action_mapping_editor/action_mapping_editor.tscn new file mode 100644 index 0000000..3730f92 --- /dev/null +++ b/addons/guide/editor/action_mapping_editor/action_mapping_editor.tscn @@ -0,0 +1,43 @@ +[gd_scene load_steps=5 format=3 uid="uid://361aipcef24h"] + +[ext_resource type="Script" path="res://addons/guide/editor/action_mapping_editor/action_mapping_editor.gd" id="1_2k0pi"] +[ext_resource type="PackedScene" uid="uid://du4x7ng6ntuk4" path="res://addons/guide/editor/action_slot/action_slot.tscn" id="1_hguf2"] +[ext_resource type="PackedScene" uid="uid://c323mdijdhktg" path="res://addons/guide/editor/input_mapping_editor/input_mapping_editor.tscn" id="2_a8nbp"] +[ext_resource type="PackedScene" uid="uid://cly0ff32fvpb2" path="res://addons/guide/editor/array_edit/array_edit.tscn" id="4_ehr5j"] + +[node name="ActionMappingEditor" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_vertical = 0 +theme_override_constants/margin_bottom = 5 +script = ExtResource("1_2k0pi") +input_mapping_editor_scene = ExtResource("2_a8nbp") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + +[node name="ActionSlot" parent="HBoxContainer/HBoxContainer" instance=ExtResource("1_hguf2")] +unique_name_in_owner = true +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +size_flags_stretch_ratio = 4.0 + +[node name="InputMappings" parent="HBoxContainer/VBoxContainer" instance=ExtResource("4_ehr5j")] +unique_name_in_owner = true +layout_mode = 2 +title = "Input mappings" +add_tooltip = "Add input mapping" +clear_tooltip = "Clear input mappings" diff --git a/addons/guide/editor/action_slot/action_slot.gd b/addons/guide/editor/action_slot/action_slot.gd new file mode 100644 index 0000000..4108d3b --- /dev/null +++ b/addons/guide/editor/action_slot/action_slot.gd @@ -0,0 +1,57 @@ +@tool +extends LineEdit + +signal action_changed() + +var index:int + +var action:GUIDEAction: + set(value): + if is_instance_valid(action): + action.changed.disconnect(_refresh) + + action = value + + if is_instance_valid(action): + action.changed.connect(_refresh) + + # action_changed can only be emitted by + # dragging an action into this, not when setting + # the property + _refresh() + + +func _refresh(): + if not is_instance_valid(action): + text = "" + tooltip_text = "" + else: + text = action._editor_name() + tooltip_text = action.resource_path + +func _can_drop_data(at_position, data) -> bool: + if not data is Dictionary: + return false + + if data.has("files"): + for file in data["files"]: + if ResourceLoader.load(file) is GUIDEAction: + return true + + return false + + +func _drop_data(at_position, data) -> void: + + for file in data["files"]: + var item = ResourceLoader.load(file) + if item is GUIDEAction: + action = item + action_changed.emit() + +func _gui_input(event): + if event is InputEventMouseButton: + if event.pressed and event.button_index == MOUSE_BUTTON_LEFT: + if is_instance_valid(action): + EditorInterface.edit_resource(action) + diff --git a/addons/guide/editor/action_slot/action_slot.tscn b/addons/guide/editor/action_slot/action_slot.tscn new file mode 100644 index 0000000..956be79 --- /dev/null +++ b/addons/guide/editor/action_slot/action_slot.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=2 format=3 uid="uid://du4x7ng6ntuk4"] + +[ext_resource type="Script" path="res://addons/guide/editor/action_slot/action_slot.gd" id="1_w5nxd"] + +[node name="ActionSlot" type="LineEdit"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "Name" +editable = false +selecting_enabled = false +script = ExtResource("1_w5nxd") diff --git a/addons/guide/editor/array_edit/array_edit.gd b/addons/guide/editor/array_edit/array_edit.gd new file mode 100644 index 0000000..0c5bfaa --- /dev/null +++ b/addons/guide/editor/array_edit/array_edit.gd @@ -0,0 +1,113 @@ +@tool +extends Container +const Utils = preload("../utils.gd") + +@export var item_scene:PackedScene + +@export var title:String = "": + set(value): + title = value + _refresh() + +@export var add_tooltip:String: + set(value): + add_tooltip = value + _refresh() + +@export var clear_tooltip:String: + set(value): + clear_tooltip = value + _refresh() + +@export var item_separation:int = 8: + set(value): + item_separation = value + _refresh() + + +@export var collapsed:bool = false: + set(value): + collapsed = value + _refresh() + +signal add_requested() +signal delete_requested(index:int) +signal move_requested(from:int, to:int) +signal insert_requested(index:int) +signal duplicate_requested(index:int) +signal clear_requested() +signal collapse_state_changed(collapsed:bool) + +@onready var _add_button:Button = %AddButton +@onready var _clear_button:Button = %ClearButton +@onready var _contents:Container = %Contents +@onready var _title_label:Label = %TitleLabel +@onready var _collapse_button:Button = %CollapseButton +@onready var _expand_button:Button = %ExpandButton +@onready var _count_label:Label = %CountLabel + +func _ready(): + _add_button.icon = get_theme_icon("Add", "EditorIcons") + _add_button.pressed.connect(func(): add_requested.emit()) + + _clear_button.icon = get_theme_icon("Clear", "EditorIcons") + _clear_button.pressed.connect(func(): clear_requested.emit()) + + _collapse_button.icon = get_theme_icon("Collapse", "EditorIcons") + _collapse_button.pressed.connect(_on_collapse_pressed) + + _expand_button.icon = get_theme_icon("Forward", "EditorIcons") + _expand_button.pressed.connect(_on_expand_pressed) + + + _refresh() + + +func _refresh(): + if is_instance_valid(_add_button): + _add_button.tooltip_text = add_tooltip + if is_instance_valid(_clear_button): + _clear_button.tooltip_text = clear_tooltip + _clear_button.visible = _contents.get_child_count() > 0 + + if is_instance_valid(_contents): + _contents.add_theme_constant_override("separation", item_separation) + _contents.visible = not collapsed + + if is_instance_valid(_collapse_button): + _collapse_button.visible = not collapsed + + if is_instance_valid(_expand_button): + _expand_button.visible = collapsed + + if is_instance_valid(_title_label): + _title_label.text = title + + if is_instance_valid(_count_label): + _count_label.text = "(%s)" % [_contents.get_child_count()] + + +func clear(): + Utils.clear(_contents) + _refresh() + + +func add_item(new_item:Control): + var item_wrapper = item_scene.instantiate() + _contents.add_child(item_wrapper) + item_wrapper.initialize(new_item) + item_wrapper.move_requested.connect(func(from:int, to:int): move_requested.emit(from, to)) + item_wrapper.delete_requested.connect(func(idx:int): delete_requested.emit(idx) ) + item_wrapper.duplicate_requested.connect(func(idx:int): duplicate_requested.emit(idx) ) + _refresh() + + +func _on_collapse_pressed(): + collapsed = true + collapse_state_changed.emit(true) + + +func _on_expand_pressed(): + collapsed = false + collapse_state_changed.emit(false) + diff --git a/addons/guide/editor/array_edit/array_edit.tscn b/addons/guide/editor/array_edit/array_edit.tscn new file mode 100644 index 0000000..c6c7408 --- /dev/null +++ b/addons/guide/editor/array_edit/array_edit.tscn @@ -0,0 +1,88 @@ +[gd_scene load_steps=5 format=3 uid="uid://cly0ff32fvpb2"] + +[ext_resource type="Script" path="res://addons/guide/editor/array_edit/array_edit.gd" id="1_y3qyt"] +[ext_resource type="PackedScene" uid="uid://cjabwsa4gmlpp" path="res://addons/guide/editor/array_edit/array_edit_item.tscn" id="2_n3ncl"] + +[sub_resource type="Image" id="Image_efj5n"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_uapko"] +image = SubResource("Image_efj5n") + +[node name="Array" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_y3qyt") +item_scene = ExtResource("2_n3ncl") +item_separation = 10 + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="Panel" type="Panel" parent="VBoxContainer/MarginContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/MarginContainer"] +layout_mode = 2 + +[node name="CollapseButton" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "Collapse" +icon = SubResource("ImageTexture_uapko") + +[node name="ExpandButton" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer"] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(48, 0) +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "Expand" +icon = SubResource("ImageTexture_uapko") + +[node name="AddButton" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 +icon = SubResource("ImageTexture_uapko") + +[node name="ClearButton" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_horizontal = 0 +icon = SubResource("ImageTexture_uapko") + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/MarginContainer/HBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer"] +layout_mode = 2 + +[node name="TitleLabel" type="Label" parent="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 + +[node name="CountLabel" type="Label" parent="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "(0)" + +[node name="Contents" type="VBoxContainer" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_constants/separation = 10 diff --git a/addons/guide/editor/array_edit/array_edit_item.gd b/addons/guide/editor/array_edit/array_edit_item.gd new file mode 100644 index 0000000..13c8a03 --- /dev/null +++ b/addons/guide/editor/array_edit/array_edit_item.gd @@ -0,0 +1,84 @@ +@tool +extends Container +const Utils = preload("../utils.gd") +const Dragger = preload("dragger.gd") + +signal move_requested(from:int, to:int) +signal delete_requested(index:int) +signal duplicate_requested(index:int) + +@onready var _dragger:Dragger = %Dragger +@onready var _content:Container = %Content +@onready var _before_indicator:ColorRect = %BeforeIndicator +@onready var _after_indicator:ColorRect = %AfterIndicator +@onready var _popup_menu:PopupMenu = %PopupMenu + + +const ID_DELETE = 2 +const ID_DUPLICATE = 3 + +func _ready(): + _dragger.icon = get_theme_icon("GuiSpinboxUpdown", "EditorIcons") + _before_indicator.color = get_theme_color("box_selection_stroke_color", "Editor") + _after_indicator.color = get_theme_color("box_selection_stroke_color", "Editor") + _before_indicator.visible = false + _after_indicator.visible = false + _dragger._parent_array = get_parent() + _dragger._index = get_index() + _dragger.pressed.connect(_show_popup_menu) + + _popup_menu.clear() + _popup_menu.add_icon_item(get_theme_icon("Duplicate", "EditorIcons"), "Duplicate", ID_DUPLICATE) + _popup_menu.add_icon_item(get_theme_icon("Remove", "EditorIcons"), "Delete", ID_DELETE) + _popup_menu.id_pressed.connect(_on_popup_menu_id_pressed) + +func initialize(content:Control): + Utils.clear(_content) + _content.add_child(content) + + +func _can_drop_data(at_position:Vector2, data) -> bool: + if data is Dictionary and data.has("parent_array") and data.parent_array == get_parent() and data.index != get_index(): + var height = size.y + + var is_before = not _is_last_child() or (at_position.y < height/2.0) + if is_before and data.index == get_index() - 1: + # don't allow the previous child to be inserted at its + # own position + return false + + _before_indicator.visible = is_before + _after_indicator.visible = not is_before + return true + + return false + + +func _drop_data(at_position, data): + var height = size.y + var is_before = not _is_last_child() or (at_position.y < height/2.0) + var from = data.index + var to = get_index() if is_before else get_index() + 1 + move_requested.emit(data.index, to) + _before_indicator.visible = false + _after_indicator.visible = false + +func _is_last_child() -> bool: + return get_index() == get_parent().get_child_count() - 1 + + +func _on_mouse_exited(): + _before_indicator.visible = false + _after_indicator.visible = false + + +func _show_popup_menu(): + _popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ZERO)) + + +func _on_popup_menu_id_pressed(id:int): + match id: + ID_DELETE: + delete_requested.emit(get_index()) + ID_DUPLICATE: + duplicate_requested.emit(get_index()) diff --git a/addons/guide/editor/array_edit/array_edit_item.tscn b/addons/guide/editor/array_edit/array_edit_item.tscn new file mode 100644 index 0000000..be3b43b --- /dev/null +++ b/addons/guide/editor/array_edit/array_edit_item.tscn @@ -0,0 +1,83 @@ +[gd_scene load_steps=5 format=3 uid="uid://cjabwsa4gmlpp"] + +[ext_resource type="Script" path="res://addons/guide/editor/array_edit/array_edit_item.gd" id="1_ujx05"] +[ext_resource type="Script" path="res://addons/guide/editor/array_edit/dragger.gd" id="2_53e2r"] + +[sub_resource type="Image" id="Image_efj5n"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_uapko"] +image = SubResource("Image_efj5n") + +[node name="ArrayEditItem" type="MarginContainer"] +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 8.0 +grow_horizontal = 2 +script = ExtResource("1_ujx05") + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +theme_override_constants/margin_top = 2 +theme_override_constants/margin_bottom = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="Dragger" type="Button" parent="MarginContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "Drag to reorder, click for options." +focus_mode = 0 +mouse_filter = 1 +icon = SubResource("ImageTexture_uapko") +script = ExtResource("2_53e2r") + +[node name="Content" type="MarginContainer" parent="MarginContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="BeforeIndicator" type="ColorRect" parent="VBoxContainer"] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(0, 2) +layout_mode = 2 +mouse_filter = 2 +color = Color(0, 0, 0, 1) + +[node name="Control" type="Control" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 + +[node name="AfterIndicator" type="ColorRect" parent="VBoxContainer"] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(0, 2) +layout_mode = 2 +mouse_filter = 2 +color = Color(0, 0, 0, 1) + +[node name="PopupMenu" type="PopupMenu" parent="."] +unique_name_in_owner = true +item_count = 2 +item_0/text = "Duplicate" +item_0/icon = SubResource("ImageTexture_uapko") +item_0/id = 3 +item_1/text = "Delete" +item_1/icon = SubResource("ImageTexture_uapko") +item_1/id = 2 + +[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"] diff --git a/addons/guide/editor/array_edit/dragger.gd b/addons/guide/editor/array_edit/dragger.gd new file mode 100644 index 0000000..629283e --- /dev/null +++ b/addons/guide/editor/array_edit/dragger.gd @@ -0,0 +1,8 @@ +@tool +extends Button + +var _parent_array:Variant +var _index:int + +func _get_drag_data(at_position): + return { "parent_array" : _parent_array, "index" : _index } diff --git a/addons/guide/editor/binding_dialog/binding_dialog.gd b/addons/guide/editor/binding_dialog/binding_dialog.gd new file mode 100644 index 0000000..96a1b02 --- /dev/null +++ b/addons/guide/editor/binding_dialog/binding_dialog.gd @@ -0,0 +1,148 @@ +@tool +extends Window + +const ClassScanner = preload("../class_scanner.gd") +const Utils = preload("../utils.gd") + +signal input_selected(input:GUIDEInput) + +@onready var _input_display = %InputDisplay +@onready var _available_types:Container = %AvailableTypes +@onready var _none_available:Control = %NoneAvailable +@onready var _some_available:Control = %SomeAvailable +@onready var _select_bool_button:Button = %SelectBoolButton +@onready var _select_1d_button:Button = %Select1DButton +@onready var _select_2d_button:Button = %Select2DButton +@onready var _select_3d_button:Button = %Select3DButton +@onready var _instructions_label:Label = %InstructionsLabel +@onready var _accept_detection_button:Button = %AcceptDetectionButton +@onready var _input_detector:GUIDEInputDetector = %InputDetector +@onready var _detect_bool_button:Button = %DetectBoolButton +@onready var _detect_1d_button:Button = %Detect1DButton +@onready var _detect_2d_button:Button = %Detect2DButton +@onready var _detect_3d_button:Button = %Detect3DButton + +var _scanner:ClassScanner +var _last_detected_input:GUIDEInput + + +func initialize(scanner:ClassScanner): + _scanner = scanner + _setup_dialog() + +func _setup_dialog(): + # we need to bind this here. if we bind it in the editor, the editor + # will crash when opening the scene because it will delete the node it + # just tries to edit. + focus_exited.connect(_on_close_requested) + + _show_inputs_of_value_type(GUIDEAction.GUIDEActionValueType.BOOL) + _instructions_label.text = tr("Press one of the buttons above to detect an input.") + _accept_detection_button.visible = false + + +func _on_close_requested(): + hide() + queue_free() + + +func _show_inputs_of_value_type(type:GUIDEAction.GUIDEActionValueType) -> void: + var items:Array[GUIDEInput] = [] + + _select_bool_button.set_pressed_no_signal(type == GUIDEAction.GUIDEActionValueType.BOOL) + _select_1d_button.set_pressed_no_signal(type == GUIDEAction.GUIDEActionValueType.AXIS_1D) + _select_2d_button.set_pressed_no_signal(type == GUIDEAction.GUIDEActionValueType.AXIS_2D) + _select_3d_button.set_pressed_no_signal(type == GUIDEAction.GUIDEActionValueType.AXIS_3D) + + var all_inputs = _scanner.find_inheritors("GUIDEInput") + for script in all_inputs.values(): + var dummy:GUIDEInput = script.new() + if dummy._native_value_type() == type: + items.append(dummy) + + _some_available.visible = not items.is_empty() + _none_available.visible = items.is_empty() + + if items.is_empty(): + return + + items.sort_custom(func(a,b): return a._editor_name().nocasecmp_to(b._editor_name()) < 0) + Utils.clear(_available_types) + + for item in items: + var button = Button.new() + button.text = item._editor_name() + button.tooltip_text = item._editor_description() + button.pressed.connect(_deliver.bind(item)) + button.size_flags_horizontal = Control.SIZE_EXPAND_FILL + + _available_types.add_child(button) + + +func _deliver(input:GUIDEInput): + input_selected.emit(input) + hide() + queue_free() + + +func _on_select_bool_button_pressed(): + _show_inputs_of_value_type(GUIDEAction.GUIDEActionValueType.BOOL) + + +func _on_select_1d_button_pressed(): + _show_inputs_of_value_type(GUIDEAction.GUIDEActionValueType.AXIS_1D) + + +func _on_select_2d_button_pressed(): + _show_inputs_of_value_type(GUIDEAction.GUIDEActionValueType.AXIS_2D) + + +func _on_select_3d_button_pressed(): + _show_inputs_of_value_type(GUIDEAction.GUIDEActionValueType.AXIS_3D) + + +func _on_input_detector_detection_started(): + _instructions_label.text = tr("Actuate the input now...") + + +func _on_input_detector_input_detected(input:GUIDEInput): + _instructions_label.visible = false + _input_display.visible = true + _input_display.input = input + _accept_detection_button.visible = true + _last_detected_input = input + + +func _begin_detect_input(type:GUIDEAction.GUIDEActionValueType): + _last_detected_input = null + _instructions_label.visible = true + _instructions_label.text = tr("Get ready...") + _accept_detection_button.visible = false + _input_display.visible = false + _input_detector.detect(type) + + +func _on_detect_bool_button_pressed(): + _detect_bool_button.release_focus() + _begin_detect_input(GUIDEAction.GUIDEActionValueType.BOOL) + + +func _on_detect_1d_button_pressed(): + _detect_1d_button.release_focus() + _begin_detect_input(GUIDEAction.GUIDEActionValueType.AXIS_1D) + + +func _on_detect_2d_button_pressed(): + _detect_2d_button.release_focus() + _begin_detect_input(GUIDEAction.GUIDEActionValueType.AXIS_2D) + + +func _on_detect_3d_button_pressed(): + _detect_3d_button.release_focus() + _begin_detect_input(GUIDEAction.GUIDEActionValueType.AXIS_3D) + + +func _on_accept_detection_button_pressed(): + input_selected.emit(_last_detected_input) + hide() + queue_free diff --git a/addons/guide/editor/binding_dialog/binding_dialog.tscn b/addons/guide/editor/binding_dialog/binding_dialog.tscn new file mode 100644 index 0000000..056fdac --- /dev/null +++ b/addons/guide/editor/binding_dialog/binding_dialog.tscn @@ -0,0 +1,216 @@ +[gd_scene load_steps=5 format=3 uid="uid://dic27bm4pfw3q"] + +[ext_resource type="Script" path="res://addons/guide/editor/binding_dialog/binding_dialog.gd" id="1_tknjd"] +[ext_resource type="PackedScene" uid="uid://dsv7s6tfmnsrs" path="res://addons/guide/editor/input_display/input_display.tscn" id="2_83ieu"] +[ext_resource type="Script" path="res://addons/guide/remapping/guide_input_detector.gd" id="3_c6q6r"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3e874"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(1, 0.365, 0.365, 1) +draw_center = false +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_detail = 1 + +[node name="BindingDialog" type="Window"] +title = "Input Configuration" +initial_position = 4 +size = Vector2i(1200, 600) +popup_window = true +min_size = Vector2i(1200, 600) +script = ExtResource("1_tknjd") + +[node name="MarginContainer" type="MarginContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_bottom = 5 + +[node name="BGPanel" type="Panel" parent="MarginContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_3e874") + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer"] +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="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MarginContainer"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="LeftPanel" type="Panel" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer"] +unique_name_in_owner = true +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer"] +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="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/separation = 10 + +[node name="Label" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Detect Input" +horizontal_alignment = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="DetectBoolButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "Boolean" + +[node name="Detect1DButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "1D" + +[node name="Detect2DButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "2D" + +[node name="Detect3DButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "3D" + +[node name="InstructionsLabel" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 6 +text = "3..2..1.." +horizontal_alignment = 1 +vertical_alignment = 1 +autowrap_mode = 2 + +[node name="InputDisplay" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer" instance=ExtResource("2_83ieu")] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 6 + +[node name="AcceptDetectionButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 4 +text = "Accept" + +[node name="MarginContainer2" type="MarginContainer" parent="MarginContainer/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="RightPanel" type="Panel" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2"] +unique_name_in_owner = true +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2"] +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="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/separation = 10 + +[node name="Label" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Select Input" +horizontal_alignment = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="SelectBoolButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +toggle_mode = true +text = "Boolean" + +[node name="Select1DButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +toggle_mode = true +text = "1D" + +[node name="Select2DButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +toggle_mode = true +text = "2D" + +[node name="Select3DButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +toggle_mode = true +text = "3D" + +[node name="NoneAvailable" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 6 +size_flags_vertical = 6 +text = "No matching inputs available." + +[node name="SomeAvailable" type="ScrollContainer" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 + +[node name="AvailableTypes" type="VBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/SomeAvailable"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="InputDetector" type="Node" parent="."] +unique_name_in_owner = true +script = ExtResource("3_c6q6r") + +[connection signal="close_requested" from="." to="." method="_on_close_requested"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/HBoxContainer/DetectBoolButton" to="." method="_on_detect_bool_button_pressed"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/HBoxContainer/Detect1DButton" to="." method="_on_detect_1d_button_pressed"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/HBoxContainer/Detect2DButton" to="." method="_on_detect_2d_button_pressed"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/HBoxContainer/Detect3DButton" to="." method="_on_detect_3d_button_pressed"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer/MarginContainer/VBoxContainer/AcceptDetectionButton" to="." method="_on_accept_detection_button_pressed"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/HBoxContainer/SelectBoolButton" to="." method="_on_select_bool_button_pressed"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/HBoxContainer/Select1DButton" to="." method="_on_select_1d_button_pressed"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/HBoxContainer/Select2DButton" to="." method="_on_select_2d_button_pressed"] +[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/MarginContainer2/MarginContainer/VBoxContainer/HBoxContainer/Select3DButton" to="." method="_on_select_3d_button_pressed"] +[connection signal="detection_started" from="InputDetector" to="." method="_on_input_detector_detection_started"] +[connection signal="input_detected" from="InputDetector" to="." method="_on_input_detector_input_detected"] diff --git a/addons/guide/editor/class_scanner.gd b/addons/guide/editor/class_scanner.gd new file mode 100644 index 0000000..d37e3da --- /dev/null +++ b/addons/guide/editor/class_scanner.gd @@ -0,0 +1,91 @@ +## Scanner to find inheriting classes. Used to detect inheritors of +## modifiers and triggers. Ideally this would be built into the editor +## but sometimes one has to hack their way around the limitations. +## This only scans to the extent needed to drive the UI, it's not a general +## purpose implementation. +@tool + +const GUIDESet = preload("../guide_set.gd") + +var _dirty:bool = true + +# looks like we only get very limited access to the script's inheritance tree, +# so we need to do a little caching ourselves +var _script_lut:Dictionary = {} + +func _init(): + EditorInterface.get_resource_filesystem().script_classes_updated.connect(_mark_dirty) + + +func _mark_dirty(): + _dirty = true + +## Returns all classes that directly or indirectly inherit from the +## given class. Only works for scripts in the project, e.g. doesn't +## scan the whole class_db. Key is class name, value is the Script instance +func find_inheritors(clazz_name:StringName) -> Dictionary: + var result:Dictionary = {} + + var root := EditorInterface.get_resource_filesystem().get_filesystem() + + # rebuild the LUT when needed + if _dirty: + _script_lut.clear() + _scan(root) + _dirty = false + + + var open_set:GUIDESet = GUIDESet.new() + # a closed set just to avoid infinite loops, we'll never + # look at the same class more than once. + var closed_set:GUIDESet = GUIDESet.new() + + open_set.add(clazz_name) + + while not open_set.is_empty(): + var next = open_set.pull() + closed_set.add(next) + if not _script_lut.has(next): + # we don't know this script, ignore, move on + continue + + # now find all scripts that extend the one we + # are looking at + for item:ScriptInfo in _script_lut.values(): + if item.extendz == next: + # put them into the result + result[item.clazz_name] = item.clazz_script + # and put their class in the open set + # unless we already looked at it. + if not closed_set.has(item.clazz_name): + open_set.add(item.clazz_name) + + return result + + +func _scan(folder:EditorFileSystemDirectory): + for i in folder.get_file_count(): + var script_clazz = folder.get_file_script_class_name(i) + if script_clazz != "": + var info := _script_lut.get(script_clazz) + if info == null: + info = ScriptInfo.new() + info.clazz_name = script_clazz + info.clazz_script = ResourceLoader.load(folder.get_file_path(i)) + _script_lut[script_clazz] = info + + var script_extendz = folder.get_file_script_class_extends(i) + info.extendz = script_extendz + + for i in folder.get_subdir_count(): + _scan(folder.get_subdir(i)) + + +class ScriptInfo: + var clazz_name:StringName + var extendz:StringName + var clazz_script:Script + + func _to_string() -> String: + return clazz_name + ":" + extendz + diff --git a/addons/guide/editor/input_display/input_display.gd b/addons/guide/editor/input_display/input_display.gd new file mode 100644 index 0000000..eb21aef --- /dev/null +++ b/addons/guide/editor/input_display/input_display.gd @@ -0,0 +1,39 @@ +@tool +extends RichTextLabel +signal clicked() + +var _formatter:GUIDEInputFormatter = GUIDEInputFormatter.new(64) + +var input:GUIDEInput: + set(value): + if value == input: + return + + if is_instance_valid(input): + input.changed.disconnect(_refresh) + + input = value + + if is_instance_valid(input): + input.changed.connect(_refresh) + + _refresh() + +func _refresh(): + if not is_instance_valid(input): + parse_bbcode("[center][i][/i][/center]") + tooltip_text = "" + return + + var text := await _formatter.input_as_richtext_async(input, false) + parse_bbcode("[center]" + text + "[/center]") + tooltip_text = _formatter.input_as_text(input) + + +func _gui_input(event): + if event is InputEventMouseButton: + if event.pressed and event.button_index == MOUSE_BUTTON_LEFT: + clicked.emit() + + + diff --git a/addons/guide/editor/input_display/input_display.tscn b/addons/guide/editor/input_display/input_display.tscn new file mode 100644 index 0000000..4cd79a3 --- /dev/null +++ b/addons/guide/editor/input_display/input_display.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=3 format=3 uid="uid://dsv7s6tfmnsrs"] + +[ext_resource type="Script" path="res://addons/guide/editor/input_display/input_display.gd" id="1_ne6sd"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_0bp65"] + +[node name="InputDisplay" type="RichTextLabel"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_styles/normal = SubResource("StyleBoxEmpty_0bp65") +bbcode_enabled = true +fit_content = true +script = ExtResource("1_ne6sd") diff --git a/addons/guide/editor/input_mapping_editor/input_mapping_editor.gd b/addons/guide/editor/input_mapping_editor/input_mapping_editor.gd new file mode 100644 index 0000000..e4c428c --- /dev/null +++ b/addons/guide/editor/input_mapping_editor/input_mapping_editor.gd @@ -0,0 +1,299 @@ +@tool +extends MarginContainer + +const ArrayEdit = preload("../array_edit/array_edit.gd") +const ClassScanner = preload("../class_scanner.gd") +const Utils = preload("../utils.gd") + +@export var modifier_slot_scene:PackedScene +@export var trigger_slot_scene:PackedScene +@export var binding_dialog_scene:PackedScene + +@onready var _edit_input_mapping_button:Button = %EditInputMappingButton +@onready var _input_display = %InputDisplay +@onready var _edit_input_button:Button = %EditInputButton +@onready var _clear_input_button:Button = %ClearInputButton + +@onready var _modifiers:ArrayEdit = %Modifiers +@onready var _add_modifier_popup:PopupMenu = %AddModifierPopup + +@onready var _triggers:ArrayEdit = %Triggers +@onready var _add_trigger_popup:PopupMenu = %AddTriggerPopup + +var _plugin:EditorPlugin +var _scanner:ClassScanner +var _undo_redo:EditorUndoRedoManager + +var _mapping:GUIDEInputMapping + +func _ready(): + _edit_input_button.icon = get_theme_icon("Edit", "EditorIcons") + _clear_input_button.icon = get_theme_icon("Remove", "EditorIcons") + _edit_input_mapping_button.icon = get_theme_icon("Tools", "EditorIcons") + + _modifiers.add_requested.connect(_on_modifiers_add_requested) + _modifiers.delete_requested.connect(_on_modifier_delete_requested) + _modifiers.duplicate_requested.connect(_on_modifier_duplicate_requested) + _modifiers.move_requested.connect(_on_modifier_move_requested) + _modifiers.clear_requested.connect(_on_modifiers_clear_requested) + _modifiers.collapse_state_changed.connect(_on_modifiers_collapse_state_changed) + + _triggers.add_requested.connect(_on_triggers_add_requested) + _triggers.delete_requested.connect(_on_trigger_delete_requested) + _triggers.duplicate_requested.connect(_on_trigger_duplicate_requested) + _triggers.move_requested.connect(_on_trigger_move_requested) + _triggers.clear_requested.connect(_on_triggers_clear_requested) + _triggers.collapse_state_changed.connect(_on_triggers_collapse_state_changed) + + +func initialize(plugin:EditorPlugin, scanner:ClassScanner) -> void: + _plugin = plugin + _scanner = scanner + _undo_redo = plugin.get_undo_redo() + _input_display.clicked.connect(_on_input_display_clicked) + + +func edit(mapping:GUIDEInputMapping) -> void: + assert(_mapping == null) + _mapping = mapping + _mapping.changed.connect(_update) + _update() + + +func _update(): + _modifiers.clear() + _triggers.clear() + + _input_display.input = _mapping.input + for i in _mapping.modifiers.size(): + var modifier_slot = modifier_slot_scene.instantiate() + _modifiers.add_item(modifier_slot) + + modifier_slot.modifier = _mapping.modifiers[i] + modifier_slot.changed.connect(_on_modifier_changed.bind(i, modifier_slot)) + + for i in _mapping.triggers.size(): + var trigger_slot = trigger_slot_scene.instantiate() + _triggers.add_item(trigger_slot) + + trigger_slot.trigger = _mapping.triggers[i] + trigger_slot.changed.connect(_on_trigger_changed.bind(i, trigger_slot)) + + _modifiers.collapsed = _mapping.get_meta("_guide_modifiers_collapsed", false) + _triggers.collapsed = _mapping.get_meta("_guide_triggers_collapsed", false) + + +func _on_modifiers_add_requested(): + _fill_popup(_add_modifier_popup, "GUIDEModifier") + _add_modifier_popup.popup(Rect2(get_global_mouse_position(), Vector2.ZERO)) + + +func _on_triggers_add_requested(): + _fill_popup(_add_trigger_popup, "GUIDETrigger") + _add_trigger_popup.popup(Rect2(get_global_mouse_position(), Vector2.ZERO)) + + +func _fill_popup(popup:PopupMenu, base_clazz:StringName): + popup.clear(true) + + var inheritors := _scanner.find_inheritors(base_clazz) + for type in inheritors.keys(): + var class_script:Script = inheritors[type] + var dummy = class_script.new() + popup.add_item(dummy._editor_name()) + popup.set_item_tooltip(popup.item_count -1, dummy._editor_description()) + popup.set_item_metadata(popup.item_count - 1, class_script) + +func _on_input_display_clicked(): + if is_instance_valid(_mapping.input): + EditorInterface.edit_resource(_mapping.input) + + +func _on_input_changed(input:GUIDEInput): + _undo_redo.create_action("Change input") + + _undo_redo.add_do_property(_mapping, "input", input) + _undo_redo.add_undo_property(_mapping, "input", _mapping.input) + + _undo_redo.commit_action() + + if is_instance_valid(input): + EditorInterface.edit_resource(input) + + +func _on_edit_input_button_pressed(): + var dialog:Window = binding_dialog_scene.instantiate() + EditorInterface.popup_dialog_centered(dialog) + dialog.initialize(_scanner) + dialog.input_selected.connect(_on_input_changed) + + +func _on_clear_input_button_pressed(): + _undo_redo.create_action("Delete bound input") + + _undo_redo.add_do_property(_mapping, "input", null) + _undo_redo.add_undo_property(_mapping, "triggers", _mapping.input) + + _undo_redo.commit_action() + + +func _on_add_modifier_popup_index_pressed(index:int) -> void: + var script = _add_modifier_popup.get_item_metadata(index) + var new_modifier = script.new() + + _undo_redo.create_action("Add " + new_modifier._editor_name() + " modifier") + var modifiers = _mapping.modifiers.duplicate() + modifiers.append(new_modifier) + + _undo_redo.add_do_property(_mapping, "modifiers", modifiers) + _undo_redo.add_undo_property(_mapping, "modifiers", _mapping.modifiers) + + _undo_redo.commit_action() + + +func _on_add_trigger_popup_index_pressed(index): + var script = _add_trigger_popup.get_item_metadata(index) + var new_trigger = script.new() + + _undo_redo.create_action("Add " + new_trigger._editor_name() + " trigger") + var triggers = _mapping.triggers.duplicate() + triggers.append(new_trigger) + + _undo_redo.add_do_property(_mapping, "triggers", triggers) + _undo_redo.add_undo_property(_mapping, "triggers", _mapping.triggers) + + _undo_redo.commit_action() + + +func _on_modifier_changed(index:int, slot) -> void: + var new_modifier = slot.modifier + + _undo_redo.create_action("Replace modifier") + var modifiers = _mapping.modifiers.duplicate() + modifiers[index] = new_modifier + + _undo_redo.add_do_property(_mapping, "modifiers", modifiers) + _undo_redo.add_undo_property(_mapping, "modifiers", _mapping.modifiers) + + _undo_redo.commit_action() + + +func _on_trigger_changed(index:int, slot) -> void: + var new_trigger = slot.trigger + + _undo_redo.create_action("Replace trigger") + var triggers = _mapping.triggers.duplicate() + triggers[index] = new_trigger + + _undo_redo.add_do_property(_mapping, "triggers", triggers) + _undo_redo.add_undo_property(_mapping, "triggers", _mapping.triggers) + + _undo_redo.commit_action() + + +func _on_modifier_move_requested(from:int, to:int) -> void: + _undo_redo.create_action("Move modifier") + var modifiers = _mapping.modifiers.duplicate() + var modifier = modifiers[from] + modifiers.remove_at(from) + if from < to: + to -= 1 + modifiers.insert(to, modifier) + + _undo_redo.add_do_property(_mapping, "modifiers", modifiers) + _undo_redo.add_undo_property(_mapping, "modifiers", _mapping.modifiers) + + _undo_redo.commit_action() + + +func _on_trigger_move_requested(from:int, to:int) -> void: + _undo_redo.create_action("Move trigger") + var triggers = _mapping.triggers.duplicate() + var trigger = triggers[from] + triggers.remove_at(from) + if from < to: + to -= 1 + triggers.insert(to, trigger) + + _undo_redo.add_do_property(_mapping, "triggers", triggers) + _undo_redo.add_undo_property(_mapping, "triggers", _mapping.triggers) + + _undo_redo.commit_action() + +func _on_modifier_duplicate_requested(index:int) -> void: + _undo_redo.create_action("Duplicate modifier") + var modifiers = _mapping.modifiers.duplicate() + var copy = Utils.duplicate_if_inline(modifiers[index]) + modifiers.insert(index+1, copy) + + _undo_redo.add_do_property(_mapping, "modifiers", modifiers) + _undo_redo.add_undo_property(_mapping, "modifiers", _mapping.modifiers) + + _undo_redo.commit_action() + +func _on_trigger_duplicate_requested(index:int) -> void: + _undo_redo.create_action("Duplicate trigger") + var triggers = _mapping.triggers.duplicate() + var copy = Utils.duplicate_if_inline(triggers[index]) + triggers.insert(index+1, copy) + + _undo_redo.add_do_property(_mapping, "triggers", triggers) + _undo_redo.add_undo_property(_mapping, "triggers", _mapping.triggers) + + _undo_redo.commit_action() + + + +func _on_modifier_delete_requested(index:int) -> void: + _undo_redo.create_action("Delete modifier") + var modifiers = _mapping.modifiers.duplicate() + modifiers.remove_at(index) + + _undo_redo.add_do_property(_mapping, "modifiers", modifiers) + _undo_redo.add_undo_property(_mapping, "modifiers", _mapping.modifiers) + + _undo_redo.commit_action() + + +func _on_trigger_delete_requested(index:int) -> void: + _undo_redo.create_action("Delete trigger") + var triggers = _mapping.triggers.duplicate() + triggers.remove_at(index) + + _undo_redo.add_do_property(_mapping, "triggers", triggers) + _undo_redo.add_undo_property(_mapping, "triggers", _mapping.triggers) + + _undo_redo.commit_action() + + +func _on_modifiers_clear_requested() -> void: + _undo_redo.create_action("Clear modifiers") + # if this is inlined into the do_property, then it doesn't work + # so lets keep it a local variable + var value:Array[GUIDEModifier] = [] + _undo_redo.add_do_property(_mapping, "modifiers", value) + _undo_redo.add_undo_property(_mapping, "modifiers", _mapping.modifiers) + + _undo_redo.commit_action() + + +func _on_triggers_clear_requested() -> void: + _undo_redo.create_action("Clear triggers") + # if this is inlined into the do_property, then it doesn't work + # so lets keep it a local variable + var value:Array[GUIDETrigger] = [] + _undo_redo.add_do_property(_mapping, "triggers", value) + _undo_redo.add_undo_property(_mapping, "triggers", _mapping.triggers) + + _undo_redo.commit_action() + + +func _on_modifiers_collapse_state_changed(new_state:bool): + _mapping.set_meta("_guide_modifiers_collapsed", new_state) + +func _on_triggers_collapse_state_changed(new_state:bool): + _mapping.set_meta("_guide_triggers_collapsed", new_state) + + +func _on_edit_input_mapping_button_pressed(): + EditorInterface.edit_resource(_mapping) diff --git a/addons/guide/editor/input_mapping_editor/input_mapping_editor.tscn b/addons/guide/editor/input_mapping_editor/input_mapping_editor.tscn new file mode 100644 index 0000000..a70f142 --- /dev/null +++ b/addons/guide/editor/input_mapping_editor/input_mapping_editor.tscn @@ -0,0 +1,140 @@ +[gd_scene load_steps=9 format=3 uid="uid://c323mdijdhktg"] + +[ext_resource type="PackedScene" uid="uid://dsv7s6tfmnsrs" path="res://addons/guide/editor/input_display/input_display.tscn" id="1_pg8n3"] +[ext_resource type="Script" path="res://addons/guide/editor/input_mapping_editor/input_mapping_editor.gd" id="1_xsluc"] +[ext_resource type="PackedScene" uid="uid://ck5a30syo6bpo" path="res://addons/guide/editor/modifier_slot/modifier_slot.tscn" id="2_uhbrq"] +[ext_resource type="PackedScene" uid="uid://tk30wnstb0ku" path="res://addons/guide/editor/trigger_slot/trigger_slot.tscn" id="3_e0jys"] +[ext_resource type="PackedScene" uid="uid://dic27bm4pfw3q" path="res://addons/guide/editor/binding_dialog/binding_dialog.tscn" id="4_oepf3"] +[ext_resource type="PackedScene" uid="uid://cly0ff32fvpb2" path="res://addons/guide/editor/array_edit/array_edit.tscn" id="6_jekhk"] + +[sub_resource type="Image" id="Image_m1w1j"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_y0eyy"] +image = SubResource("Image_m1w1j") + +[node name="InputMappingEditor" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_vertical = 0 +script = ExtResource("1_xsluc") +modifier_slot_scene = ExtResource("2_uhbrq") +trigger_slot_scene = ExtResource("3_e0jys") +binding_dialog_scene = ExtResource("4_oepf3") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 0 +theme_override_constants/separation = 8 + +[node name="MarginContainer" type="MarginContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_vertical = 0 + +[node name="Panel" type="Panel" parent="HBoxContainer/MarginContainer"] +visible = false +layout_mode = 2 + +[node name="EditInputMappingButton" type="Button" parent="HBoxContainer/MarginContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Open input mapping in inspector" +icon = SubResource("ImageTexture_y0eyy") +flat = true + +[node name="MarginContainer1" type="MarginContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Panel" type="Panel" parent="HBoxContainer/MarginContainer1"] +visible = false +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/MarginContainer1"] +layout_mode = 2 + +[node name="InputDisplay" parent="HBoxContainer/MarginContainer1/HBoxContainer" instance=ExtResource("1_pg8n3")] +unique_name_in_owner = true +layout_mode = 2 +scroll_active = false + +[node name="EditInputButton" type="Button" parent="HBoxContainer/MarginContainer1/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 0 +tooltip_text = "Edit bound input..." +icon = SubResource("ImageTexture_y0eyy") +flat = true + +[node name="ClearInputButton" type="Button" parent="HBoxContainer/MarginContainer1/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 0 +tooltip_text = "Delete bound input" +icon = SubResource("ImageTexture_y0eyy") +flat = true + +[node name="MarginContainer2" type="MarginContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 + +[node name="Panel" type="Panel" parent="HBoxContainer/MarginContainer2"] +visible = false +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/MarginContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +size_flags_stretch_ratio = 2.0 + +[node name="Modifiers" parent="HBoxContainer/MarginContainer2/VBoxContainer" instance=ExtResource("6_jekhk")] +unique_name_in_owner = true +layout_mode = 2 +title = "Modifiers" +add_tooltip = "Add modifier..." +clear_tooltip = "Clear modifiers" + +[node name="AddModifierPopup" type="PopupMenu" parent="HBoxContainer/MarginContainer2/VBoxContainer"] +unique_name_in_owner = true + +[node name="MarginContainer3" type="MarginContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 + +[node name="Panel" type="Panel" parent="HBoxContainer/MarginContainer3"] +visible = false +layout_mode = 2 + +[node name="VBoxContainer2" type="VBoxContainer" parent="HBoxContainer/MarginContainer3"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +size_flags_stretch_ratio = 2.0 + +[node name="Triggers" parent="HBoxContainer/MarginContainer3/VBoxContainer2" instance=ExtResource("6_jekhk")] +unique_name_in_owner = true +layout_mode = 2 +title = "Triggers" +add_tooltip = "Add trigger..." +clear_tooltip = "Clear triggers" + +[node name="AddTriggerPopup" type="PopupMenu" parent="HBoxContainer/MarginContainer3/VBoxContainer2"] +unique_name_in_owner = true + +[connection signal="pressed" from="HBoxContainer/MarginContainer/EditInputMappingButton" to="." method="_on_edit_input_mapping_button_pressed"] +[connection signal="pressed" from="HBoxContainer/MarginContainer1/HBoxContainer/EditInputButton" to="." method="_on_edit_input_button_pressed"] +[connection signal="pressed" from="HBoxContainer/MarginContainer1/HBoxContainer/ClearInputButton" to="." method="_on_clear_input_button_pressed"] +[connection signal="index_pressed" from="HBoxContainer/MarginContainer2/VBoxContainer/AddModifierPopup" to="." method="_on_add_modifier_popup_index_pressed"] +[connection signal="index_pressed" from="HBoxContainer/MarginContainer3/VBoxContainer2/AddTriggerPopup" to="." method="_on_add_trigger_popup_index_pressed"] diff --git a/addons/guide/editor/logo_editor_small.svg b/addons/guide/editor/logo_editor_small.svg new file mode 100644 index 0000000..38b6805 --- /dev/null +++ b/addons/guide/editor/logo_editor_small.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/guide/editor/logo_editor_small.svg.import b/addons/guide/editor/logo_editor_small.svg.import new file mode 100644 index 0000000..50a40ea --- /dev/null +++ b/addons/guide/editor/logo_editor_small.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cap7e0f05pj8j" +path="res://.godot/imported/logo_editor_small.svg-a18f1eaff840dcdf5215ef26c289caf9.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/editor/logo_editor_small.svg" +dest_files=["res://.godot/imported/logo_editor_small.svg-a18f1eaff840dcdf5215ef26c289caf9.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=0.5 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/editor/mapping_context_editor/mapping_context_editor.gd b/addons/guide/editor/mapping_context_editor/mapping_context_editor.gd new file mode 100644 index 0000000..8f7882c --- /dev/null +++ b/addons/guide/editor/mapping_context_editor/mapping_context_editor.gd @@ -0,0 +1,159 @@ +@tool +extends MarginContainer + +const ClassScanner = preload("../class_scanner.gd") +const Utils = preload("../utils.gd") +const ArrayEdit = preload("../array_edit/array_edit.gd") + +@export var action_mapping_editor_scene:PackedScene + +@onready var _title_label:Label = %TitleLabel +@onready var _action_mappings:ArrayEdit = %ActionMappings +@onready var _editing_view:Control = %EditingView +@onready var _empty_view = %EmptyView + +var _plugin:EditorPlugin +var _current_context:GUIDEMappingContext +var _undo_redo:EditorUndoRedoManager +var _scanner:ClassScanner + + +func _ready(): + _title_label.add_theme_font_override("font", get_theme_font("title", "EditorFonts")) + _scanner = ClassScanner.new() + + _editing_view.visible = false + _empty_view.visible = true + + _action_mappings.add_requested.connect(_on_action_mappings_add_requested) + _action_mappings.move_requested.connect(_on_action_mappings_move_requested) + _action_mappings.delete_requested.connect(_on_action_mapping_delete_requested) + _action_mappings.clear_requested.connect(_on_action_mappings_clear_requested) + _action_mappings.duplicate_requested.connect(_on_action_mapping_duplicate_requested) + _action_mappings.collapse_state_changed.connect(_on_action_mappings_collapse_state_changed) + +func initialize(plugin:EditorPlugin) -> void: + _plugin = plugin + _undo_redo = plugin.get_undo_redo() + + +func edit(context:GUIDEMappingContext) -> void: + if is_instance_valid(_current_context): + _current_context.changed.disconnect(_refresh) + + _current_context = context + + if is_instance_valid(_current_context): + _current_context.changed.connect(_refresh) + + _refresh() + + +func _refresh(): + _editing_view.visible = is_instance_valid(_current_context) + _empty_view.visible = not is_instance_valid(_current_context) + + if not is_instance_valid(_current_context): + return + + _title_label.text = _current_context._editor_name() + _title_label.tooltip_text = _current_context.resource_path + + _action_mappings.clear() + + for i in _current_context.mappings.size(): + var mapping = _current_context.mappings[i] + + var mapping_editor = action_mapping_editor_scene.instantiate() + mapping_editor.initialize(_plugin, _scanner) + + _action_mappings.add_item(mapping_editor) + + mapping_editor.edit(mapping) + + _action_mappings.collapsed = _current_context.get_meta("_guide_action_mappings_collapsed", false) + +func _on_action_mappings_add_requested(): + var mappings = _current_context.mappings.duplicate() + var new_mapping := GUIDEActionMapping.new() + # don't set an action because they should come from the file system + mappings.append(new_mapping) + + _undo_redo.create_action("Add action mapping") + + _undo_redo.add_do_property(_current_context, "mappings", mappings) + _undo_redo.add_undo_property(_current_context, "mappings", _current_context.mappings) + + _undo_redo.commit_action() + + +func _on_action_mappings_move_requested(from:int, to:int): + var mappings = _current_context.mappings.duplicate() + var mapping = mappings[from] + mappings.remove_at(from) + if from < to: + to -= 1 + mappings.insert(to, mapping) + + _undo_redo.create_action("Move action mapping") + + _undo_redo.add_do_property(_current_context, "mappings", mappings) + _undo_redo.add_undo_property(_current_context, "mappings", _current_context.mappings) + + _undo_redo.commit_action() + + +func _on_action_mapping_delete_requested(index:int): + var mappings = _current_context.mappings.duplicate() + mappings.remove_at(index) + + _undo_redo.create_action("Delete action mapping") + + _undo_redo.add_do_property(_current_context, "mappings", mappings) + _undo_redo.add_undo_property(_current_context, "mappings", _current_context.mappings) + + _undo_redo.commit_action() + + +func _on_action_mappings_clear_requested(): + var mappings:Array[GUIDEActionMapping] = [] + + _undo_redo.create_action("Clear action mappings") + + _undo_redo.add_do_property(_current_context, "mappings", mappings) + _undo_redo.add_undo_property(_current_context, "mappings", _current_context.mappings) + + _undo_redo.commit_action() + +func _on_action_mapping_duplicate_requested(index:int): + var mappings = _current_context.mappings.duplicate() + var to_duplicate:GUIDEActionMapping = mappings[index] + + var copy = GUIDEActionMapping.new() + # don't set the action, because each mapping should have a unique mapping + for input_mapping:GUIDEInputMapping in to_duplicate.input_mappings: + var copied_input_mapping := GUIDEInputMapping.new() + copied_input_mapping.input = Utils.duplicate_if_inline(input_mapping.input) + for modifier in input_mapping.modifiers: + copied_input_mapping.modifiers.append(Utils.duplicate_if_inline(modifier)) + + for trigger in input_mapping.triggers: + copied_input_mapping.triggers.append(Utils.duplicate_if_inline(trigger)) + + copy.input_mappings.append(copied_input_mapping) + + # insert the copy after the copied mapping + mappings.insert(index+1, copy) + + + _undo_redo.create_action("Duplicate action mapping") + + _undo_redo.add_do_property(_current_context, "mappings", mappings) + _undo_redo.add_undo_property(_current_context, "mappings", _current_context.mappings) + + _undo_redo.commit_action() + +func _on_action_mappings_collapse_state_changed(new_state:bool): + _current_context.set_meta("_guide_action_mappings_collapsed", new_state) + + diff --git a/addons/guide/editor/mapping_context_editor/mapping_context_editor.tscn b/addons/guide/editor/mapping_context_editor/mapping_context_editor.tscn new file mode 100644 index 0000000..f28a17f --- /dev/null +++ b/addons/guide/editor/mapping_context_editor/mapping_context_editor.tscn @@ -0,0 +1,58 @@ +[gd_scene load_steps=4 format=3 uid="uid://dm3hott3tfvwe"] + +[ext_resource type="Script" path="res://addons/guide/editor/mapping_context_editor/mapping_context_editor.gd" id="1_vytdu"] +[ext_resource type="PackedScene" uid="uid://361aipcef24h" path="res://addons/guide/editor/action_mapping_editor/action_mapping_editor.tscn" id="2_qb3p8"] +[ext_resource type="PackedScene" uid="uid://cly0ff32fvpb2" path="res://addons/guide/editor/array_edit/array_edit.tscn" id="3_x7h5x"] + +[node name="MappingContextEditor" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_constants/margin_left = 5 +theme_override_constants/margin_top = 5 +theme_override_constants/margin_right = 5 +theme_override_constants/margin_bottom = 5 +script = ExtResource("1_vytdu") +action_mapping_editor_scene = ExtResource("2_qb3p8") + +[node name="EditingView" type="VBoxContainer" parent="."] +unique_name_in_owner = true +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="EditingView"] +layout_mode = 2 + +[node name="TitleLabel" type="Label" parent="EditingView/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 6 +text = "narf.tres" +horizontal_alignment = 1 + +[node name="MarginContainer" type="MarginContainer" parent="EditingView"] +layout_mode = 2 +theme_override_constants/margin_bottom = 5 + +[node name="ScrollContainer" type="ScrollContainer" parent="EditingView"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="ActionMappings" parent="EditingView/ScrollContainer" instance=ExtResource("3_x7h5x")] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +title = "Action mappings" +add_tooltip = "Add action mapping" +clear_tooltip = "Clear action mappings" + +[node name="EmptyView" type="CenterContainer" parent="."] +unique_name_in_owner = true +layout_mode = 2 + +[node name="Label" type="Label" parent="EmptyView"] +layout_mode = 2 +text = "Create and open a GUIDEMappingContext to get started." diff --git a/addons/guide/editor/modifier_slot/modifier_slot.gd b/addons/guide/editor/modifier_slot/modifier_slot.gd new file mode 100644 index 0000000..30dc53d --- /dev/null +++ b/addons/guide/editor/modifier_slot/modifier_slot.gd @@ -0,0 +1,14 @@ +@tool +extends "../resource_slot/resource_slot.gd" + +var modifier:GUIDEModifier: + set(value): + _value = value + get: + return _value + +func _accepts_drop_data(data:Resource) -> bool: + return data is GUIDEModifier + + + diff --git a/addons/guide/editor/modifier_slot/modifier_slot.tscn b/addons/guide/editor/modifier_slot/modifier_slot.tscn new file mode 100644 index 0000000..6b2f91e --- /dev/null +++ b/addons/guide/editor/modifier_slot/modifier_slot.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=2 format=3 uid="uid://ck5a30syo6bpo"] + +[ext_resource type="Script" path="res://addons/guide/editor/modifier_slot/modifier_slot.gd" id="1_273m5"] + +[node name="LineEdit" type="LineEdit"] +offset_right = 1920.0 +offset_bottom = 31.0 +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "Name" +editable = false +context_menu_enabled = false +virtual_keyboard_enabled = false +shortcut_keys_enabled = false +middle_mouse_paste_enabled = false +selecting_enabled = false +drag_and_drop_selection_enabled = false +script = ExtResource("1_273m5") diff --git a/addons/guide/editor/resource_slot/resource_slot.gd b/addons/guide/editor/resource_slot/resource_slot.gd new file mode 100644 index 0000000..d54ec95 --- /dev/null +++ b/addons/guide/editor/resource_slot/resource_slot.gd @@ -0,0 +1,106 @@ +@tool +extends LineEdit + +signal changed() +const Utils = preload("../utils.gd") + +func _ready(): + editable = false + context_menu_enabled = false + virtual_keyboard_enabled = false + shortcut_keys_enabled = false + selecting_enabled = false + drag_and_drop_selection_enabled = false + middle_mouse_paste_enabled = false + +## The underlying resource. This is opened for editing when the user clicks on the control. Its also +## used when dragging from the control. +var _value:Resource = null: + set(value): + if _value == value: + return + + # stop tracking changes to the old resource (if any) + if is_instance_valid(_value): + _value.changed.disconnect(_update_from_value) + + _value = value + + # track changes to the resource itself + if is_instance_valid(_value): + _value.changed.connect(_update_from_value) + + _update_from_value() + changed.emit() + +func _update_from_value(): + if not is_instance_valid(_value): + text = "" + tooltip_text = "" + remove_theme_color_override("font_uneditable_color") + else: + text = _value._editor_name() + tooltip_text = _value.resource_path + # if the value is shared, we override the font color to indicate that + if not Utils.is_inline(_value): + add_theme_color_override("font_uneditable_color", get_theme_color("accent_color", "Editor")) + queue_redraw() + else: + remove_theme_color_override("font_uneditable_color") + +## Can be overridden to handle the drop data. This method is called when the user drops something on the control. +## If the value should be updated ,this method should set the _value property. +func _do_drop_data(data:Resource): + _value = data + + +## Whether this control can accept drop data. This method is called when the user drags something over the control. +func _accepts_drop_data(data:Resource) -> bool: + return false + +func _can_drop_data(at_position, data) -> bool: + if data is Resource: + return _accepts_drop_data(data) + + if not data is Dictionary: + return false + + if data.has("files"): + for file in data["files"]: + if _accepts_drop_data(ResourceLoader.load(file)): + return true + + return false + + +func _drop_data(at_position, data) -> void: + if data is Resource: + _do_drop_data(data) + return + + for file in data["files"]: + var item := ResourceLoader.load(file) + _do_drop_data(item) + + +func _get_drag_data(at_position: Vector2) -> Variant: + if is_instance_valid(_value): + var _preview := TextureRect.new() + _preview.texture = get_theme_icon("File", "EditorIcons") + set_drag_preview(_preview) + # if the value is shared, we just hand out the resource path + if not Utils.is_inline(_value): + return {"files": [_value.resource_path]} + else: + # otherwise we hand out a shallow copy + return _value.duplicate() + else: + return null + +func _gui_input(event): + if event is InputEventMouseButton: + if event.pressed and event.button_index == MOUSE_BUTTON_LEFT: + if is_instance_valid(_value): + EditorInterface.edit_resource(_value) + + diff --git a/addons/guide/editor/trigger_slot/trigger_slot.gd b/addons/guide/editor/trigger_slot/trigger_slot.gd new file mode 100644 index 0000000..70cb053 --- /dev/null +++ b/addons/guide/editor/trigger_slot/trigger_slot.gd @@ -0,0 +1,14 @@ +@tool +extends "../resource_slot/resource_slot.gd" + +var trigger:GUIDETrigger: + set(value): + _value = value + get: + return _value + +func _accepts_drop_data(data:Resource) -> bool: + return data is GUIDETrigger + + + diff --git a/addons/guide/editor/trigger_slot/trigger_slot.tscn b/addons/guide/editor/trigger_slot/trigger_slot.tscn new file mode 100644 index 0000000..3d5e6d8 --- /dev/null +++ b/addons/guide/editor/trigger_slot/trigger_slot.tscn @@ -0,0 +1,20 @@ +[gd_scene load_steps=2 format=3 uid="uid://tk30wnstb0ku"] + +[ext_resource type="Script" path="res://addons/guide/editor/trigger_slot/trigger_slot.gd" id="1_wxafc"] + +[node name="LineEdit" type="LineEdit"] +unique_name_in_owner = true +offset_right = 1920.0 +offset_bottom = 31.0 +size_flags_horizontal = 3 +size_flags_vertical = 0 +tooltip_text = "Delete trigger" +text = "Name" +editable = false +context_menu_enabled = false +virtual_keyboard_enabled = false +shortcut_keys_enabled = false +middle_mouse_paste_enabled = false +selecting_enabled = false +drag_and_drop_selection_enabled = false +script = ExtResource("1_wxafc") diff --git a/addons/guide/editor/utils.gd b/addons/guide/editor/utils.gd new file mode 100644 index 0000000..f3549af --- /dev/null +++ b/addons/guide/editor/utils.gd @@ -0,0 +1,22 @@ +## Removes and frees all children of a node. +static func clear(node:Node): + if not is_instance_valid(node): + return + for child in node.get_children(): + node.remove_child(child) + child.queue_free() + + +## Checks if the given resource is an inline resource. If so, returns a shallow copy, +## otherwise returns the resource. If the resource is null, returns null. +static func duplicate_if_inline(resource:Resource) -> Resource: + if is_inline(resource): + return resource.duplicate() + return resource + + +## Checks if the given resource is an inline resource. +static func is_inline(resource:Resource) -> bool: + if resource == null: + return false + return resource.resource_path.contains("::") or resource.resource_path == "" \ No newline at end of file diff --git a/addons/guide/guide.gd b/addons/guide/guide.gd new file mode 100644 index 0000000..1f8f19f --- /dev/null +++ b/addons/guide/guide.gd @@ -0,0 +1,365 @@ +extends Node + +const GUIDESet = preload("guide_set.gd") +const GUIDEReset = preload("guide_reset.gd") +const GUIDEInputTracker = preload("guide_input_tracker.gd") + +## This is emitted whenever input mappings change (either due to mapping +## contexts being enabled/disabled or remapping configs being re-applied or +## joystick devices being connected/disconnected). +## This is useful for updating UI prompts. +signal input_mappings_changed() + +## The currently active contexts. Key is the context, value is the priority +var _active_contexts:Dictionary = {} +## The currently active action mappings. +var _active_action_mappings:Array[GUIDEActionMapping] = [] + +## The currently active remapping config. +var _active_remapping_config:GUIDERemappingConfig + +## All currently active inputs as collected from the active input mappings +var _active_inputs:Array[GUIDEInput] = [] + +## A dictionary of actions sharing input. Key is the action, value +## is an array of lower-priority actions that share input with the +## key action. +var _actions_sharing_input:Dictionary = {} + +## A reference to the reset node which resets inputs that need a reset per frame +## This is an extra node because the reset should run at the end of the frame +## before new input is processed at the beginning of the frame. +var _reset_node:GUIDEReset + + +func _ready(): + process_mode = Node.PROCESS_MODE_ALWAYS + _reset_node = GUIDEReset.new() + add_child(_reset_node) + # attach to the current viewport to get input events + GUIDEInputTracker._instrument.call_deferred(get_viewport()) + + get_tree().node_added.connect(_on_node_added) + + # Emit a change of input mappings whenever a joystick was connected + # or disconnected. + Input.joy_connection_changed.connect(func(ig, ig2): input_mappings_changed.emit()) + + +## Called when a node is added to the tree. If the node is a window +## GUIDE will instrument it to get events when the window is focused. +func _on_node_added(node:Node) -> void: + if not node is Window: + return + + GUIDEInputTracker._instrument(node) + + +## Injects input into GUIDE. GUIDE will call this automatically but +## can also be used to manually inject input for GUIDE to handle +func inject_input(event:InputEvent) -> void: + if event is InputEventAction: + return # we don't react to Godot's built-in events + + for input:GUIDEInput in _active_inputs: + input._input(event) + + +## Applies an input remapping config. This will override all input bindings in the +## currently loaded mapping contexts with the bindings from the configuration. +## Note that GUIDE will not track changes to the remapping config. If your remapping +## config changes, you will need to call this method again. +func set_remapping_config(config:GUIDERemappingConfig) -> void: + _active_remapping_config = config + _update_caches() + + +## Enables the given context with the given priority. Lower numbers have higher priority. If +## disable_others is set to true, all other currently enabled mapping contexts will be disabled. +func enable_mapping_context(context:GUIDEMappingContext, disable_others:bool = false, priority:int = 0): + if not is_instance_valid(context): + push_error("Null context given. Ignoring.") + return + + if disable_others: + _active_contexts.clear() + + _active_contexts[context] = priority + _update_caches() + + +## Disables the given mapping context. +func disable_mapping_context(context:GUIDEMappingContext): + if not is_instance_valid(context): + push_error("Null context given. Ignoring.") + return + + _active_contexts.erase(context) + _update_caches() + + +## Checks whether the given mapping context is currently enabled. +func is_mapping_context_enabled(context:GUIDEMappingContext) -> bool: + return _active_contexts.has(context) + + +## Returns the currently enabled mapping contexts +func get_enabled_mapping_contexts() -> Array[GUIDEMappingContext]: + var result:Array[GUIDEMappingContext] = [] + for key in _active_contexts.keys(): + result.append(key) + return result + + +## Processes all currently active actions +func _process(delta:float) -> void: + var blocked_actions:GUIDESet = GUIDESet.new() + + for action_mapping:GUIDEActionMapping in _active_action_mappings: + + var action:GUIDEAction = action_mapping.action + + # Walk over all input mappings for this action and consolidate state + # and result value. + var consolidated_value:Vector3 = Vector3.ZERO + var consolidated_trigger_state:GUIDETrigger.GUIDETriggerState + + for input_mapping:GUIDEInputMapping in action_mapping.input_mappings: + input_mapping._update_state(delta, action.action_value_type) + consolidated_value += input_mapping._value + consolidated_trigger_state = max(consolidated_trigger_state, input_mapping._state) + + # we do the blocking check only here because triggers may need to run anyways + # (e.g. to collect hold times). + if blocked_actions.has(action): + consolidated_trigger_state = GUIDETrigger.GUIDETriggerState.NONE + + if action.block_lower_priority_actions and \ + consolidated_trigger_state == GUIDETrigger.GUIDETriggerState.TRIGGERED and \ + _actions_sharing_input.has(action): + for blocked_action in _actions_sharing_input[action]: + blocked_actions.add(blocked_action) + + + # Now state change events. + match(action._last_state): + GUIDEAction.GUIDEActionState.TRIGGERED: + match(consolidated_trigger_state): + GUIDETrigger.GUIDETriggerState.NONE: + action._completed(consolidated_value) + GUIDETrigger.GUIDETriggerState.ONGOING: + action._ongoing(consolidated_value, delta) + GUIDETrigger.GUIDETriggerState.TRIGGERED: + action._triggered(consolidated_value, delta) + + GUIDEAction.GUIDEActionState.ONGOING: + match(consolidated_trigger_state): + GUIDETrigger.GUIDETriggerState.NONE: + action._cancelled(consolidated_value) + GUIDETrigger.GUIDETriggerState.ONGOING: + action._ongoing(consolidated_value, delta) + GUIDETrigger.GUIDETriggerState.TRIGGERED: + action._triggered(consolidated_value, delta) + + GUIDEAction.GUIDEActionState.COMPLETED: + match(consolidated_trigger_state): + GUIDETrigger.GUIDETriggerState.NONE: + # make sure the value updated but don't emit any other events + action._update_value(consolidated_value) + GUIDETrigger.GUIDETriggerState.ONGOING: + action._started(consolidated_value) + GUIDETrigger.GUIDETriggerState.TRIGGERED: + action._triggered(consolidated_value, delta) + +func _update_caches(): + # Notify existing inputs that they aren no longer required + for input:GUIDEInput in _active_inputs: + input._reset() + input._end_usage() + + # Cancel all actions, so they don't remain in weird states. + for mapping:GUIDEActionMapping in _active_action_mappings: + match mapping.action._last_state: + GUIDEAction.GUIDEActionState.ONGOING: + mapping.action._cancelled(Vector3.ZERO) + GUIDEAction.GUIDEActionState.TRIGGERED: + mapping.action._completed(Vector3.ZERO) + # notify all modifiers they are no longer in use + for input_mapping in mapping.input_mappings: + for modifier in input_mapping.modifiers: + modifier._end_usage() + + _active_inputs.clear() + _active_action_mappings.clear() + _actions_sharing_input.clear() + + var sorted_contexts:Array[Dictionary] = [] + + for context:GUIDEMappingContext in _active_contexts.keys(): + sorted_contexts.append({"context": context, "priority": _active_contexts[context]}) + + sorted_contexts.sort_custom( func(a,b): return a.priority < b.priority ) + + # The actions we already have processed. Same action may appear in different + # contexts, so if we find the same action twice, only the first instance wins. + var processed_actions:GUIDESet = GUIDESet.new() + var consolidated_inputs:GUIDESet = GUIDESet.new() + + for entry:Dictionary in sorted_contexts: + var context:GUIDEMappingContext = entry.context + for action_mapping:GUIDEActionMapping in context.mappings: + var action := action_mapping.action + # If the action was already configured in a higher priority context, + # we'll skip it. + if processed_actions.has(action): + # skip + continue + + processed_actions.add(action) + + # We consolidate the inputs here, so we'll internally build a new + # action mapping that uses consolidated inputs rather than the + # original ones. This achieves multiple things: + # - if two actions check for the same input, we only need to + # process the input once instead of twice. + # - it allows us to prioritize input, if two actions check for + # the same input. This way the first action can consume the + # input and not have it affect further actions. + # - we make sure nobody shares triggers as they are stateful and + # should not be shared. + + var effective_mapping = GUIDEActionMapping.new() + effective_mapping.action = action + + # now update the input mappings + for index in action_mapping.input_mappings.size(): + var bound_input:GUIDEInput = action_mapping.input_mappings[index].input + + # if the mapping has an override for the input, apply it. + if _active_remapping_config != null and \ + _active_remapping_config._has(context, action, index): + bound_input = _active_remapping_config._get_bound_input_or_null(context, action, index) + + # make a new input mapping + var new_input_mapping := GUIDEInputMapping.new() + + # can be null for combo mappings, so check that + if bound_input != null: + # check if we already have this kind of input + var existing = consolidated_inputs.first_match(func(it:GUIDEInput): return it.is_same_as(bound_input)) + if existing != null: + # if we have this already, use the instance we have + bound_input = existing + else: + # otherwise register this input into the consolidated input + consolidated_inputs.add(bound_input) + + new_input_mapping.input = bound_input + # modifiers cannot be re-bound so we can just use the one + # from the original configuration. this is also needed for shared + # modifiers to work. + new_input_mapping.modifiers = action_mapping.input_mappings[index].modifiers + # triggers also cannot be re-bound but we still make a copy + # to ensure that no shared triggers exist. + new_input_mapping.triggers = [] + + for trigger in action_mapping.input_mappings[index].triggers: + new_input_mapping.triggers.append(trigger.duplicate()) + + new_input_mapping._initialize() + + # and add it to the new mapping + effective_mapping.input_mappings.append(new_input_mapping) + + + # if any binding remains, add the mapping to the list of active + # action mappings + if not effective_mapping.input_mappings.is_empty(): + _active_action_mappings.append(effective_mapping) + + # now we have a new set of active inputs + for input:GUIDEInput in consolidated_inputs.values(): + _active_inputs.append(input) + + # prepare the action input share lookup table + for i:int in _active_action_mappings.size(): + + var mapping = _active_action_mappings[i] + + if mapping.action.block_lower_priority_actions: + # first find out if the action uses any chorded actions and + # collect all inputs that this action uses + var chorded_actions:GUIDESet = GUIDESet.new() + var inputs:GUIDESet = GUIDESet.new() + var blocked_actions:GUIDESet = GUIDESet.new() + for input_mapping:GUIDEInputMapping in mapping.input_mappings: + if input_mapping.input != null: + inputs.add(input_mapping.input) + + for trigger:GUIDETrigger in input_mapping.triggers: + if trigger is GUIDETriggerChordedAction and trigger.action != null: + chorded_actions.add(trigger.action) + + # Now the action that has a chorded action (A) needs to make sure that + # the chorded action it depends upon (B) is not blocked (otherwise A would + # never trigger) and if that chorded action (B) in turn depends on chorded actions. So + # if chorded actions build a chain, we need to keep the full + # chain unblocked. In addition we need to add the inputs of all + # these chorded actions to the list of blocked inputs. + for j:int in range(i+1, _active_action_mappings.size()): + var inner_mapping = _active_action_mappings[j] + # this is a chorded action that is used by one other action + # in the chain. + if chorded_actions.has(inner_mapping.action): + for input_mapping:GUIDEInputMapping in inner_mapping.input_mappings: + # put all of its inputs into the list of blocked inputs + if input_mapping.input != null: + inputs.add(input_mapping.input) + + # also if this mapping in turn again depends on a chorded + # action, ad this one to the list of chorded actions + for trigger:GUIDETrigger in input_mapping.triggers: + if trigger is GUIDETriggerChordedAction and trigger.action != null: + chorded_actions.add(trigger.action) + + # now find lower priority actions that share input + for j:int in range(i+1, _active_action_mappings.size()): + var inner_mapping = _active_action_mappings[j] + if chorded_actions.has(inner_mapping.action): + continue + + for input_mapping:GUIDEInputMapping in inner_mapping.input_mappings: + if input_mapping.input == null: + continue + + # because we consolidated input, we can now do an == comparison + # to find equal input. + if inputs.has(input_mapping.input): + blocked_actions.add(inner_mapping.action) + # we can continue to the next action + break + + if not blocked_actions.is_empty(): + _actions_sharing_input[mapping.action] = blocked_actions.values() + + # finally collect which inputs we need to reset per frame + _reset_node._inputs_to_reset.clear() + for input:GUIDEInput in _active_inputs: + if input._needs_reset(): + _reset_node._inputs_to_reset.append(input) + # Notify inputs that GUIDE is about to use them + input._begin_usage() + + for mapping in _active_action_mappings: + for input_mapping in mapping.input_mappings: + # notify modifiers they will be used. + for modifier in input_mapping.modifiers: + modifier._begin_usage() + + # and copy over the hold time threshold from the mapping + mapping.action._trigger_hold_threshold = input_mapping._trigger_hold_threshold + + # and notify interested parties that the input mappings have changed + input_mappings_changed.emit() + + diff --git a/addons/guide/guide_action.gd b/addons/guide/guide_action.gd new file mode 100644 index 0000000..a92ef64 --- /dev/null +++ b/addons/guide/guide_action.gd @@ -0,0 +1,254 @@ +@tool +@icon("res://addons/guide/guide_action.svg") +class_name GUIDEAction +extends Resource + +enum GUIDEActionValueType { + BOOL = 0, + AXIS_1D = 1, + AXIS_2D = 2, + AXIS_3D = 3 +} + +enum GUIDEActionState { + TRIGGERED, + ONGOING, + COMPLETED +} + +## The name of this action. Required when this action should be used as +## Godot action. Also displayed in the debugger. +@export var name:StringName: + set(value): + if name == value: + return + name = value + emit_changed() + + +## The action value type. +@export var action_value_type: GUIDEActionValueType = GUIDEActionValueType.BOOL: + set(value): + if action_value_type == value: + return + action_value_type = value + emit_changed() + +## If this action triggers, lower-priority actions cannot trigger +## if they share input with this action unless these actions are +## chorded with this action. +@export var block_lower_priority_actions:bool = true: + set(value): + if block_lower_priority_actions == value: + return + block_lower_priority_actions = value + emit_changed() + + +@export_category("Godot Actions") +## If true, then this action will be emitted into Godot's +## built-in action system. This can be helpful to interact with +## code using this system, like Godot's UI system. Actions +## will be emitted on trigger and completion (e.g. button down +## and button up). +@export var emit_as_godot_actions:bool = false: + set(value): + if emit_as_godot_actions == value: + return + emit_as_godot_actions = value + emit_changed() + + +@export_category("Action Remapping") + +## If true, players can remap this action. To be remappable, make sure +## that a name and the action type are properly set. +@export var is_remappable:bool: + set(value): + if is_remappable == value: + return + is_remappable = value + emit_changed() + +## The display name of the action shown to the player. +@export var display_name:String: + set(value): + if display_name == value: + return + display_name = value + emit_changed() + +## The display category of the action shown to the player. +@export var display_category:String: + set(value): + if display_category == value: + return + display_category = value + emit_changed() + +## Emitted every frame while the action is triggered. +signal triggered() + +## Emitted when the action started evaluating. +signal started() + +## Emitted every frame while the action is still evaluating. +signal ongoing() + +## Emitted when the action finished evaluating. +signal completed() + +## Emitted when the action was cancelled. +signal cancelled() + +var _last_state:GUIDEActionState = GUIDEActionState.COMPLETED + +var _value_bool:bool +## Returns the value of this action as bool. +var value_bool:bool: + get: return _value_bool + +## Returns the value of this action as float. +var value_axis_1d:float: + get: return _value.x + +var _value_axis_2d:Vector2 = Vector2.ZERO +## Returns the value of this action as Vector2. +var value_axis_2d:Vector2: + get: return _value_axis_2d + +var _value:Vector3 = Vector3.ZERO +## Returns the value of this action as Vector3. +var value_axis_3d:Vector3: + get: return _value + + +var _elapsed_seconds:float +## The amount of seconds elapsed since the action started evaluating. +var elapsed_seconds:float: + get: return _elapsed_seconds + +var _elapsed_ratio:float +## The ratio of the elapsed time to the hold time. This is a percentage +## of the hold time that has passed. If the action has no hold time, this will +## be 0 when the action is not triggered and 1 when the action is triggered. +## Otherwise, this will be a value between 0 and 1. +var elapsed_ratio:float: + get: return _elapsed_ratio + +var _triggered_seconds:float +## The amount of seconds elapsed since the action triggered. +var triggered_seconds:float: + get: return _triggered_seconds + + +## This is a hint for how long the input must remain actuated (in seconds) before the action triggers. +## It depends on the mapping in which this action is used. If the mapping has no hold trigger it will be -1. +## In general, you should not access this variable directly, but rather the `elapsed_ratio` property of the action +## which is a percentage of the hold time that has passed. +var _trigger_hold_threshold:float = -1.0 + +func _triggered(value:Vector3, delta:float) -> void: + _triggered_seconds += delta + _elapsed_ratio = 1.0 + _update_value(value) + _last_state = GUIDEActionState.TRIGGERED + triggered.emit() + _emit_godot_action_maybe(true) + +func _started(value:Vector3) -> void: + _elapsed_ratio = 0.0 + _update_value(value) + _last_state = GUIDEActionState.ONGOING + started.emit() + ongoing.emit() + +func _ongoing(value:Vector3, delta:float) -> void: + _elapsed_seconds += delta + if _trigger_hold_threshold > 0: + _elapsed_ratio = _elapsed_seconds / _trigger_hold_threshold + _update_value(value) + var was_triggered:bool = _last_state == GUIDEActionState.TRIGGERED + _last_state = GUIDEActionState.ONGOING + ongoing.emit() + # if the action reverts from triggered to ongoing, this counts as + # releasing the action for the godot action system. + if was_triggered: + _emit_godot_action_maybe(false) + + +func _cancelled(value:Vector3) -> void: + _elapsed_seconds = 0 + _elapsed_ratio = 0 + _update_value(value) + _last_state = GUIDEActionState.COMPLETED + cancelled.emit() + completed.emit() + +func _completed(value:Vector3) -> void: + _elapsed_seconds = 0 + _elapsed_ratio = 0 + _triggered_seconds = 0 + _update_value(value) + _last_state = GUIDEActionState.COMPLETED + completed.emit() + _emit_godot_action_maybe(false) + +func _emit_godot_action_maybe(pressed:bool) -> void: + if not emit_as_godot_actions: + return + + if name.is_empty(): + push_error("Cannot emit action into Godot's system because name is empty.") + return + + var godot_action = InputEventAction.new() + godot_action.action = name + godot_action.strength = _value.x + godot_action.pressed = pressed + Input.parse_input_event(godot_action) + +func _update_value(value:Vector3): + match action_value_type: + GUIDEActionValueType.BOOL, GUIDEActionValueType.AXIS_1D: + _value_bool = abs(value.x) > 0 + _value_axis_2d = Vector2(abs(value.x), 0) + _value = Vector3(value.x, 0, 0) + GUIDEActionValueType.AXIS_2D: + _value_bool = abs(value.x) > 0 + _value_axis_2d = Vector2(value.x, value.y) + _value = Vector3(value.x, value.y, 0) + GUIDEActionValueType.AXIS_3D: + _value_bool = abs(value.x) > 0 + _value_axis_2d = Vector2(value.x, value.y) + _value = value + +## Returns whether the action is currently triggered. Can be used for a +## polling style input. +func is_triggered() -> bool: + return _last_state == GUIDEActionState.TRIGGERED + + +## Returns whether the action is currently completed. Can be used for a +## polling style input. +func is_completed() -> bool: + return _last_state == GUIDEActionState.COMPLETED + + +## Returns whether the action is currently completed. Can be used for a +## polling style input. +func is_ongoing() -> bool: + return _last_state == GUIDEActionState.ONGOING + + +func _editor_name() -> String: + # Try to give the most user friendly name + if display_name != "": + return display_name + + if name != "": + return name + + return resource_path.get_file().replace(".tres", "") + + diff --git a/addons/guide/guide_action.svg b/addons/guide/guide_action.svg new file mode 100644 index 0000000..b39120c --- /dev/null +++ b/addons/guide/guide_action.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/addons/godot-rapier2d/Radial2D.svg.import b/addons/guide/guide_action.svg.import similarity index 70% rename from addons/godot-rapier2d/Radial2D.svg.import rename to addons/guide/guide_action.svg.import index 317d9d1..a55db27 100644 --- a/addons/godot-rapier2d/Radial2D.svg.import +++ b/addons/guide/guide_action.svg.import @@ -2,8 +2,8 @@ importer="texture" type="CompressedTexture2D" -uid="uid://cho3shol3rky2" -path="res://.godot/imported/Radial2D.svg-4380d9841bddc115105cff2016be7c6a.ctex" +uid="uid://bei7cw115tks0" +path="res://.godot/imported/guide_action.svg-4d1dfb47183d95c4796078798ce2d0ab.ctex" metadata={ "has_editor_variant": true, "vram_texture": false @@ -11,8 +11,8 @@ metadata={ [deps] -source_file="res://addons/godot-rapier2d/Radial2D.svg" -dest_files=["res://.godot/imported/Radial2D.svg-4380d9841bddc115105cff2016be7c6a.ctex"] +source_file="res://addons/guide/guide_action.svg" +dest_files=["res://.godot/imported/guide_action.svg-4d1dfb47183d95c4796078798ce2d0ab.ctex"] [params] @@ -33,6 +33,6 @@ process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 detect_3d/compress_to=1 -svg/scale=1.0 +svg/scale=0.5 editor/scale_with_editor_scale=true editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/guide_action_mapping.gd b/addons/guide/guide_action_mapping.gd new file mode 100644 index 0000000..f965b9f --- /dev/null +++ b/addons/guide/guide_action_mapping.gd @@ -0,0 +1,21 @@ +@icon("res://addons/guide/guide_internal.svg") +@tool +## An action to input mapping +class_name GUIDEActionMapping +extends Resource + +## The action to be mapped +@export var action:GUIDEAction: + set(value): + if value == action: + return + action = value + emit_changed() + +## A set of input mappings that can trigger the action +@export var input_mappings:Array[GUIDEInputMapping] = []: + set(value): + if value == input_mappings: + return + input_mappings = value + emit_changed() diff --git a/addons/guide/guide_input_mapping.gd b/addons/guide/guide_input_mapping.gd new file mode 100644 index 0000000..62d4dd9 --- /dev/null +++ b/addons/guide/guide_input_mapping.gd @@ -0,0 +1,177 @@ +@icon("res://addons/guide/guide_internal.svg") +@tool +## A mapping from actuated input to a trigger result +class_name GUIDEInputMapping +extends Resource + +## Whether the remapping configuration in this input mapping +## should override the configuration of the bound action. Enable +## this, to give a key a custom name or category for remapping. +@export var override_action_settings:bool = false: + set(value): + if override_action_settings == value: + return + override_action_settings = value + emit_changed() + +## If true, players can remap this input mapping. Note that the +## action to which this input is bound also needs to be remappable +## for this setting to have an effect. +@export var is_remappable:bool = false: + set(value): + if is_remappable == value: + return + is_remappable = value + emit_changed() + +## The display name of the input mapping shown to the player. If empty, +## the display name of the action is used. +@export var display_name:String = "": + set(value): + if display_name == value: + return + display_name = value + emit_changed() + +## The display category of the input mapping. If empty, the display name of the +## action is used. +@export var display_category:String = "": + set(value): + if display_category == value: + return + display_category = value + emit_changed() + + +@export_group("Mappings") +## The input to be actuated +@export var input:GUIDEInput: + set(value): + if value == input: + return + input = value + emit_changed() + + +## A list of modifiers that preprocess the actuated input before +## it is fed to the triggers. +@export var modifiers:Array[GUIDEModifier] = []: + set(value): + if value == modifiers: + return + modifiers = value + emit_changed() + + +## A list of triggers that could trigger the mapped action. +@export var triggers:Array[GUIDETrigger] = []: + set(value): + if value == triggers: + return + triggers = value + emit_changed() + +## Hint for how long the input must remain actuated (in seconds) before the mapping triggers. +## If the mapping has no hold trigger it will be -1. If it has multiple hold triggers +## the shortest hold time will be used. +var _trigger_hold_threshold:float = -1.0 + +var _state:GUIDETrigger.GUIDETriggerState = GUIDETrigger.GUIDETriggerState.NONE +var _value:Vector3 = Vector3.ZERO + +var _trigger_list:Array[GUIDETrigger] = [] +var _implicit_count:int = 0 +var _explicit_count:int = 0 + +## Called when the mapping is started to be used by GUIDE. Calculates +## the number of implicit and explicit triggers so we don't need to do this +## per frame. Also creates a default trigger when none is set. +func _initialize() -> void : + _trigger_list.clear() + + _implicit_count = 0 + _explicit_count = 0 + _trigger_hold_threshold = -1.0 + + if triggers.is_empty(): + # make a default trigger and use that + var default_trigger = GUIDETriggerDown.new() + default_trigger.actuation_threshold = 0 + _explicit_count = 1 + _trigger_list.append(default_trigger) + return + + for trigger in triggers: + match trigger._get_trigger_type(): + GUIDETrigger.GUIDETriggerType.EXPLICIT: + _explicit_count += 1 + GUIDETrigger.GUIDETriggerType.IMPLICIT: + _implicit_count += 1 + _trigger_list.append(trigger) + + # collect the hold threshold for hinting the UI about how long + # the input must be held down. This is only relevant for hold triggers + if trigger is GUIDETriggerHold: + if _trigger_hold_threshold == -1: + _trigger_hold_threshold = trigger.hold_treshold + else: + _trigger_hold_threshold = min(_trigger_hold_threshold, trigger.hold_treshold) + + + +func _update_state(delta:float, value_type:GUIDEAction.GUIDEActionValueType): + # Collect the current input value + var input_value:Vector3 = input._value if input != null else Vector3.ZERO + + # Run it through all modifiers + for modifier:GUIDEModifier in modifiers: + input_value = modifier._modify_input(input_value, delta, value_type) + + _value = input_value + + var triggered_implicits:int = 0 + var triggered_explicits:int = 0 + var triggered_blocked:int = 0 + + # Run over all triggers + var result:int = GUIDETrigger.GUIDETriggerState.NONE + for trigger:GUIDETrigger in _trigger_list: + var trigger_result:GUIDETrigger.GUIDETriggerState = trigger._update_state(_value, delta, value_type) + trigger._last_value = _value + + var trigger_type = trigger._get_trigger_type() + if trigger_result == GUIDETrigger.GUIDETriggerState.TRIGGERED: + match trigger_type: + GUIDETrigger.GUIDETriggerType.EXPLICIT: + triggered_explicits += 1 + GUIDETrigger.GUIDETriggerType.IMPLICIT: + triggered_implicits += 1 + GUIDETrigger.GUIDETriggerType.BLOCKING: + triggered_blocked += 1 + + # we only care about the nuances of explicit triggers. implicits and blocking + # can only really return yes or no, so they have no nuance + if trigger_type == GUIDETrigger.GUIDETriggerType.EXPLICIT: + # Higher value results take precedence over lower value results + result = max(result, trigger_result) + + # final collection + if triggered_blocked > 0: + # some blocker triggered which means that this cannot succeed + _state = GUIDETrigger.GUIDETriggerState.NONE + return + + if triggered_implicits < _implicit_count: + # not all implicits triggered, which also fails this binding + _state = GUIDETrigger.GUIDETriggerState.NONE + return + + if _explicit_count == 0 and _implicit_count > 0: + # if no explicits exist, its enough when all implicits trigger + _state = GUIDETrigger.GUIDETriggerState.TRIGGERED + return + + # return the best result + _state = result + + diff --git a/addons/guide/guide_input_tracker.gd b/addons/guide/guide_input_tracker.gd new file mode 100644 index 0000000..6dd7ef1 --- /dev/null +++ b/addons/guide/guide_input_tracker.gd @@ -0,0 +1,26 @@ +## Tracker that tracks input for a window and injects it into GUIDE. +## Will automatically keep track of sub-windows. +extends Node + +## Instruments a sub-window so it forwards input events to GUIDE. +static func _instrument(viewport:Viewport): + if viewport.has_meta("x-guide-instrumented"): + return + + var tracker = preload("guide_input_tracker.gd").new() + tracker.process_mode = Node.PROCESS_MODE_ALWAYS + viewport.add_child(tracker, false, Node.INTERNAL_MODE_BACK) + viewport.gui_focus_changed.connect(tracker._control_focused) + +## Catches unhandled input and forwards it to GUIDE +func _unhandled_input(event:InputEvent): + GUIDE.inject_input(event) + +## Some ... creative code ... to catch events from popup windows +## that are spawned by Godot's control nodes. +func _control_focused(control:Control): + if control is OptionButton or control is ColorPickerButton \ + or control is MenuButton or control is TabContainer: + _instrument(control.get_popup()) + + diff --git a/addons/guide/guide_internal.svg b/addons/guide/guide_internal.svg new file mode 100644 index 0000000..78d42de --- /dev/null +++ b/addons/guide/guide_internal.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/addons/guide/guide_internal.svg.import b/addons/guide/guide_internal.svg.import new file mode 100644 index 0000000..f235301 --- /dev/null +++ b/addons/guide/guide_internal.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ddkj7kntb4fit" +path="res://.godot/imported/guide_internal.svg-560a143a1e289215e72d8844f5173844.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/guide_internal.svg" +dest_files=["res://.godot/imported/guide_internal.svg-560a143a1e289215e72d8844f5173844.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=0.5 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/guide_mapping_context.gd b/addons/guide/guide_mapping_context.gd new file mode 100644 index 0000000..097205b --- /dev/null +++ b/addons/guide/guide_mapping_context.gd @@ -0,0 +1,30 @@ +@tool +@icon("res://addons/guide/guide_mapping_context.svg") +class_name GUIDEMappingContext +extends Resource + +const GUIDESet = preload("guide_set.gd") + +## The display name for this mapping context during action remapping +@export var display_name:String: + set(value): + if value == display_name: + return + display_name = value + emit_changed() + +## The mappings. Do yourself a favour and use the G.U.I.D.E panel +## to edit these. +@export var mappings:Array[GUIDEActionMapping] = []: + set(value): + if value == mappings: + return + mappings = value + emit_changed() + + +func _editor_name() -> String: + if display_name.is_empty(): + return resource_path.get_file() + else: + return display_name diff --git a/addons/guide/guide_mapping_context.svg b/addons/guide/guide_mapping_context.svg new file mode 100644 index 0000000..eaa1abf --- /dev/null +++ b/addons/guide/guide_mapping_context.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/addons/guide/guide_mapping_context.svg.import b/addons/guide/guide_mapping_context.svg.import new file mode 100644 index 0000000..6f740b7 --- /dev/null +++ b/addons/guide/guide_mapping_context.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcwpqc8016n7b" +path="res://.godot/imported/guide_mapping_context.svg-025f10fbbdb2bb11a96754ab9b725bea.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/guide_mapping_context.svg" +dest_files=["res://.godot/imported/guide_mapping_context.svg-025f10fbbdb2bb11a96754ab9b725bea.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=0.5 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/guide_reset.gd b/addons/guide/guide_reset.gd new file mode 100644 index 0000000..b77817d --- /dev/null +++ b/addons/guide/guide_reset.gd @@ -0,0 +1,13 @@ +extends Node + + +var _inputs_to_reset:Array[GUIDEInput] = [] + +func _enter_tree() -> void: + # this should run at the end of the frame, so we put in a low priority (= high number) + process_priority = 10000000 + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + for input:GUIDEInput in _inputs_to_reset: + input._reset() diff --git a/addons/guide/guide_set.gd b/addons/guide/guide_set.gd new file mode 100644 index 0000000..d439c91 --- /dev/null +++ b/addons/guide/guide_set.gd @@ -0,0 +1,40 @@ +## Helper class for modelling sets +var _values:Dictionary = {} + +func add(value:Variant) -> void: + _values[value] = value + + +func remove(value:Variant) -> void: + _values.erase(value) + + +func clear() -> void: + _values.clear() + +func is_empty() -> bool: + return _values.is_empty() + + +func pull() -> Variant: + if is_empty(): + return null + + var key = _values.keys()[0] + remove(key) + return key + + +func has(value:Variant) -> bool: + return _values.has(value) + +## Returns the first item for which the given matcher function returns +## a true value. +func first_match(matcher:Callable) -> Variant: + for key in _values.keys(): + if matcher.call(key): + return key + return null + +func values() -> Array: + return _values.keys() diff --git a/addons/guide/inputs/guide_input.gd b/addons/guide/inputs/guide_input.gd new file mode 100644 index 0000000..cde42fa --- /dev/null +++ b/addons/guide/inputs/guide_input.gd @@ -0,0 +1,50 @@ +@tool +@icon("res://addons/guide/inputs/guide_input.svg") +## A class representing some actuated input. +class_name GUIDEInput +extends Resource + +## The current valueo f this input. Depending on the input type only parts of the +## returned vector may be relevant. +var _value:Vector3 = Vector3.ZERO + +## Whether this input needs a reset per frame. _input is only called when +## there is input happening, but some GUIDE inputs may need to be reset +## in the absence of input. +func _needs_reset() -> bool: + return false + +## Resets the input value to the default value. Is called once per frame if +## _needs_reset returns true. +func _reset() -> void: + _value = Vector3.ZERO + +## Called when an input event happens. Should update the +## the input value of this input. +func _input(event:InputEvent): + pass + +## Returns whether this input is the same input as the other input. +func is_same_as(other:GUIDEInput) -> bool: + return false + +## Called when the input is started to be used by GUIDE. Can be used to perform +## initializations. +func _begin_usage() -> void : + pass + +## Called, when the input is no longer used by GUIDE. Can be used to perform +## cleanup. +func _end_usage() -> void: + pass + + +func _editor_name() -> String: + return "" + +func _editor_description() -> String: + return "" + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return -1 diff --git a/addons/guide/inputs/guide_input.svg b/addons/guide/inputs/guide_input.svg new file mode 100644 index 0000000..7e2314f --- /dev/null +++ b/addons/guide/inputs/guide_input.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/addons/godot-rapier2d/Fluid2D.svg.import b/addons/guide/inputs/guide_input.svg.import similarity index 70% rename from addons/godot-rapier2d/Fluid2D.svg.import rename to addons/guide/inputs/guide_input.svg.import index 4a1f6c6..458a207 100644 --- a/addons/godot-rapier2d/Fluid2D.svg.import +++ b/addons/guide/inputs/guide_input.svg.import @@ -2,8 +2,8 @@ importer="texture" type="CompressedTexture2D" -uid="uid://cv17s0qjrqj16" -path="res://.godot/imported/Fluid2D.svg-947567c51a8b586a0e695be7cba2d975.ctex" +uid="uid://oku7f5t0ox3r" +path="res://.godot/imported/guide_input.svg-d7e8ae255db039e6a02cccc3f844cc0e.ctex" metadata={ "has_editor_variant": true, "vram_texture": false @@ -11,8 +11,8 @@ metadata={ [deps] -source_file="res://addons/godot-rapier2d/Fluid2D.svg" -dest_files=["res://.godot/imported/Fluid2D.svg-947567c51a8b586a0e695be7cba2d975.ctex"] +source_file="res://addons/guide/inputs/guide_input.svg" +dest_files=["res://.godot/imported/guide_input.svg-d7e8ae255db039e6a02cccc3f844cc0e.ctex"] [params] @@ -33,6 +33,6 @@ process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 detect_3d/compress_to=1 -svg/scale=1.0 +svg/scale=0.5 editor/scale_with_editor_scale=true editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/inputs/guide_input_action.gd b/addons/guide/inputs/guide_input_action.gd new file mode 100644 index 0000000..3c677a0 --- /dev/null +++ b/addons/guide/inputs/guide_input_action.gd @@ -0,0 +1,59 @@ +## An input that mirrors the action's value while the action is triggered. +@tool +class_name GUIDEInputAction +extends GUIDEInput + +## The action that this input should mirror. This is live tracked, so any change in +## the action will update the input. +@export var action:GUIDEAction: + set(value): + if value == action: + return + action = value + emit_changed() + +func _begin_usage(): + if is_instance_valid(action): + action.triggered.connect(_on) + action.completed.connect(_off) + action.ongoing.connect(_off) + if action.is_triggered(): + _on() + return + # not triggered or no action. + _off() + + +func _end_usage(): + if is_instance_valid(action): + action.triggered.disconnect(_on) + action.completed.disconnect(_off) + action.ongoing.disconnect(_off) + + +func _on() -> void: + # on is only called when the action is actually existing, so this is + # always not-null here + _value = action.value_axis_3d + +func _off() -> void: + _value = Vector3.ZERO + + +func is_same_as(other:GUIDEInput) -> bool: + return other is GUIDEInputAction and other.action == action + + +func _to_string(): + return "(GUIDEInputAction: " + str(action) + ")" + +func _editor_name() -> String: + return "Action" + + +func _editor_description() -> String: + return "An input that mirrors the action's value while the action is triggered." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_3D diff --git a/addons/guide/inputs/guide_input_any.gd b/addons/guide/inputs/guide_input_any.gd new file mode 100644 index 0000000..5cbd1b5 --- /dev/null +++ b/addons/guide/inputs/guide_input_any.gd @@ -0,0 +1,115 @@ +## Input that triggers if any input from the given device class +## is given. Only looks for button inputs, not axis inputs as axes +## have a tendency to accidentally trigger. +@tool +class_name GUIDEInputAny +extends GUIDEInput + + +## Should input from mouse buttons be considered? Deprecated, use +## mouse_buttons instead. +## @deprecated +var mouse:bool: + get: return mouse_buttons + set(value): mouse_buttons = value + +## Should input from joy buttons be considered. Deprecated, use +## joy_buttons instead. +## @deprecated +var joy:bool: + get: return joy_buttons + set(value): joy_buttons = value + +## Should input from mouse buttons be considered? +@export var mouse_buttons:bool = false + +## Should input from mouse movement be considered? +@export var mouse_movement:bool = false + +## Minimum movement distance of the mouse before it is considered +## moving. +@export var minimum_mouse_movement_distance:float = 1.0 + +## Should input from gamepad/joystick buttons be considered? +@export var joy_buttons:bool = false + +## Should input from gamepad/joystick axes be considered? +@export var joy_axes:bool = false + +## Minimum strength of a single joy axis actuation before it is considered +## as actuated. +@export var minimum_joy_axis_actuation_strength:float = 0.2 + +## Should input from the keyboard be considered? +@export var keyboard:bool = false + +## Should input from touch be considered? +@export var touch:bool = false + + +func _needs_reset() -> bool: + # Needs reset because we cannot detect the absence of input. + return true + +func _input(event:InputEvent): + if mouse_buttons and event is InputEventMouseButton: + _value = Vector3.RIGHT + return + + if mouse_movement and event is InputEventMouseMotion \ + and event.relative.length() >= minimum_mouse_movement_distance: + _value = Vector3.RIGHT + return + + if joy_buttons and event is InputEventJoypadButton: + _value = Vector3.RIGHT + return + + if joy_axes and event is InputEventJoypadMotion \ + and abs(event.axis_value) >= minimum_joy_axis_actuation_strength: + _value = Vector3.RIGHT + return + + if keyboard and event is InputEventKey: + _value = Vector3.RIGHT + return + + if touch and (event is InputEventScreenTouch or event is InputEventScreenDrag): + _value = Vector3.RIGHT + return + + _value = Vector3.ZERO + + +func is_same_as(other:GUIDEInput) -> bool: + return other is GUIDEInputAny and \ + other.mouse == mouse and \ + other.joy == joy and \ + other.keyboard == keyboard + +func _editor_name() -> String: + return "Any Input" + + +func _editor_description() -> String: + return "Input that triggers if any input from the given device class is given." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.BOOL + +# support for legacy properties +func _get_property_list(): + return [ + { + "name": "mouse", + "type": TYPE_BOOL, + "usage": PROPERTY_USAGE_NO_EDITOR + }, + { + "name": "joy", + "type": TYPE_BOOL, + "usage": PROPERTY_USAGE_NO_EDITOR + } + ] + diff --git a/addons/guide/inputs/guide_input_joy_axis_1d.gd b/addons/guide/inputs/guide_input_joy_axis_1d.gd new file mode 100644 index 0000000..54c4ae6 --- /dev/null +++ b/addons/guide/inputs/guide_input_joy_axis_1d.gd @@ -0,0 +1,43 @@ +## Input from a single joy axis. +@tool +class_name GUIDEInputJoyAxis1D +extends GUIDEInputJoyBase + +## The joy axis to sample +@export var axis:JoyAxis = JOY_AXIS_LEFT_X: + set(value): + if value == axis: + return + axis = value + emit_changed() + +func _input(event:InputEvent): + if not event is InputEventJoypadMotion: + return + + if event.axis != axis: + return + + if joy_index > -1 and event.device != _joy_id: + return + + _value.x = event.axis_value + + +func is_same_as(other:GUIDEInput) -> bool: + return other is GUIDEInputJoyAxis1D and \ + other.axis == axis and \ + other.joy_index == joy_index + +func _to_string(): + return "(GUIDEInputJoyAxis1D: axis=" + str(axis) + ", joy_index=" + str(joy_index) + ")" + +func _editor_name() -> String: + return "Joy Axis 1D" + +func _editor_description() -> String: + return "The input from a single joy axis." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_1D diff --git a/addons/guide/inputs/guide_input_joy_axis_2d.gd b/addons/guide/inputs/guide_input_joy_axis_2d.gd new file mode 100644 index 0000000..46359f9 --- /dev/null +++ b/addons/guide/inputs/guide_input_joy_axis_2d.gd @@ -0,0 +1,58 @@ +## Input from two joy axes. +class_name GUIDEInputJoyAxis2D +extends GUIDEInputJoyBase + +## The joy axis to sample for x input. +@export var x:JoyAxis = JOY_AXIS_LEFT_X: + set(value): + if value == x: + return + x = value + emit_changed() + + +## The joy axis to sample for y input. +@export var y:JoyAxis = JOY_AXIS_LEFT_Y: + set(value): + if value == y: + return + y = value + emit_changed() + + +func _input(event:InputEvent): + if not event is InputEventJoypadMotion: + return + + if event.axis != x and event.axis != y: + return + + if joy_index > -1 and event.device != _joy_id: + return + + if event.axis == x: + _value.x = event.axis_value + return + + if event.axis == y: + _value.y = event.axis_value + +func is_same_as(other:GUIDEInput) -> bool: + return other is GUIDEInputJoyAxis2D and \ + other.x == x and \ + other.y == y and \ + other.joy_index == joy_index + +func _to_string(): + return "(GUIDEInputJoyAxis2D: x=" + str(x) + ", y=" + str(y) + ", joy_index=" + str(joy_index) + ")" + + +func _editor_name() -> String: + return "Joy Axis 2D" + +func _editor_description() -> String: + return "The input from two Joy axes. Usually from a stick." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_2D diff --git a/addons/guide/inputs/guide_input_joy_base.gd b/addons/guide/inputs/guide_input_joy_base.gd new file mode 100644 index 0000000..621012b --- /dev/null +++ b/addons/guide/inputs/guide_input_joy_base.gd @@ -0,0 +1,35 @@ +## Base class for joystick inputs. +@tool +class_name GUIDEInputJoyBase +extends GUIDEInput + +## The index of the connected joy pad to check. If -1 checks all joypads. +@export var joy_index:int = -1: + set(value): + if value == joy_index: + return + joy_index = value + emit_changed() + +## Cached joystick ID if we use a joy index. +var _joy_id:int = -2 + +func _begin_usage(): + Input.joy_connection_changed.connect(_update_joy_id) + _update_joy_id(null, null) + +func _end_usage(): + Input.joy_connection_changed.disconnect(_update_joy_id) + +func _update_joy_id(_ignore, _ignore2): + if joy_index < 0: + return + + var joypads:Array[int] = Input.get_connected_joypads() + if joy_index < joypads.size(): + _joy_id = joypads[joy_index] + else: + push_warning("Only ", joypads.size(), " joy pads/sticks connected. Cannot sample in put from index ", joy_index, ".") + _joy_id = -2 + + diff --git a/addons/guide/inputs/guide_input_joy_button.gd b/addons/guide/inputs/guide_input_joy_button.gd new file mode 100644 index 0000000..8a83306 --- /dev/null +++ b/addons/guide/inputs/guide_input_joy_button.gd @@ -0,0 +1,44 @@ +@tool +class_name GUIDEInputJoyButton +extends GUIDEInputJoyBase + +@export var button:JoyButton = JOY_BUTTON_A: + set(value): + if value == button: + return + button = value + emit_changed() + +func _input(event:InputEvent): + if not event is InputEventJoypadButton: + return + + if event.button_index != button: + return + + + if joy_index > -1 and event.device != _joy_id: + return + + _value.x = 1.0 if event.pressed else 0.0 + + +func is_same_as(other:GUIDEInput) -> bool: + return other is GUIDEInputJoyButton and \ + other.button == button and \ + other.joy_index == joy_index + + +func _to_string(): + return "(GUIDEInputJoyButton: button=" + str(button) + ", joy_index=" + str(joy_index) + ")" + + +func _editor_name() -> String: + return "Joy Button" + +func _editor_description() -> String: + return "A button press from a joy button." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.BOOL diff --git a/addons/guide/inputs/guide_input_key.gd b/addons/guide/inputs/guide_input_key.gd new file mode 100644 index 0000000..06b79cf --- /dev/null +++ b/addons/guide/inputs/guide_input_key.gd @@ -0,0 +1,127 @@ +@tool +class_name GUIDEInputKey +extends GUIDEInput + +## The physical keycode of the key. +@export var key:Key: + set(value): + if value == key: + return + key = value + emit_changed() + + +@export_group("Modifiers") +## Whether shift must be pressed. +@export var shift:bool = false: + set(value): + if value == shift: + return + shift = value + emit_changed() + +## Whether control must be pressed. +@export var control:bool = false: + set(value): + if value == control: + return + control = value + emit_changed() + +## Whether alt must be pressed. +@export var alt:bool = false: + set(value): + if value == alt: + return + alt = value + emit_changed() + + +## Whether meta/win/cmd must be pressed. +@export var meta:bool = false: + set(value): + if value == meta: + return + meta = value + emit_changed() + +## Whether this input should fire if additional +## modifier keys are currently pressed. +@export var allow_additional_modifiers:bool = true: + set(value): + if value == allow_additional_modifiers: + return + allow_additional_modifiers = value + emit_changed() + + + +func _input(event:InputEvent): + if not event is InputEventKey: + return + + # we start assuming the key is not pressed right now + _value.x = 0.0 + + # the key itself must be pressed + if not Input.is_physical_key_pressed(key): + return + + # every required modifier must be pressed + if shift and not Input.is_physical_key_pressed(KEY_SHIFT): + return + + if control and not Input.is_physical_key_pressed(KEY_CTRL): + return + + if alt and not Input.is_physical_key_pressed(KEY_ALT): + return + + if meta and not Input.is_physical_key_pressed(KEY_META): + return + + # unless additional modifiers are allowed, every + # unselected modifier must not be pressed (except if the + # bound key is actually the modifier itself) + + if not allow_additional_modifiers: + if not shift and key != KEY_SHIFT and Input.is_physical_key_pressed(KEY_SHIFT): + return + + if not control and key != KEY_CTRL and Input.is_physical_key_pressed(KEY_CTRL): + return + + if not alt and key != KEY_ALT and Input.is_physical_key_pressed(KEY_ALT): + return + + if not meta and key != KEY_META and Input.is_physical_key_pressed(KEY_META): + return + + # we're still here, so all required keys are pressed and + # no extra keys are pressed + + _value.x = 1.0 + + +func is_same_as(other:GUIDEInput) -> bool: + return other is GUIDEInputKey \ + and other.key == key \ + and other.shift == shift \ + and other.control == control \ + and other.alt == alt \ + and other.meta == meta \ + and other.allow_additional_modifiers == allow_additional_modifiers + +func _to_string(): + return "(GUIDEInputKey: key=" + str(key) + ", shift=" + str(shift) + ", alt=" + str(alt) + ", control=" + str(control) + ", meta="+ str(meta) + ")" + + +func _editor_name() -> String: + return "Key" + +func _editor_description() -> String: + return "A button press on the keyboard." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.BOOL diff --git a/addons/guide/inputs/guide_input_mouse_axis_1d.gd b/addons/guide/inputs/guide_input_mouse_axis_1d.gd new file mode 100644 index 0000000..c489349 --- /dev/null +++ b/addons/guide/inputs/guide_input_mouse_axis_1d.gd @@ -0,0 +1,47 @@ +@tool +class_name GUIDEInputMouseAxis1D +extends GUIDEInput + +enum GUIDEInputMouseAxis { + X, + Y +} + +@export var axis:GUIDEInputMouseAxis: + set(value): + if value == axis: + return + axis = value + emit_changed() + +# we don't get mouse updates when the mouse is not moving, so this needs to be +# reset every frame +func _needs_reset() -> bool: + return true + +func _input(event:InputEvent) -> void: + if event is InputEventMouseMotion: + match axis: + GUIDEInputMouseAxis.X: + _value.x = event.relative.x + GUIDEInputMouseAxis.Y: + _value.x = event.relative.y + + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputMouseAxis1D and other.axis == axis + +func _to_string(): + return "(GUIDEInputMouseAxis1D: axis=" + str(axis) + ")" + + +func _editor_name() -> String: + return "Mouse Axis 1D" + + +func _editor_description() -> String: + return "Relative mouse movement on a single axis." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_1D diff --git a/addons/guide/inputs/guide_input_mouse_axis_2d.gd b/addons/guide/inputs/guide_input_mouse_axis_2d.gd new file mode 100644 index 0000000..bdefe76 --- /dev/null +++ b/addons/guide/inputs/guide_input_mouse_axis_2d.gd @@ -0,0 +1,35 @@ +@tool +class_name GUIDEInputMouseAxis2D +extends GUIDEInput + + +# we don't get mouse updates when the mouse is not moving, so this needs to be +# reset every frame +func _needs_reset() -> bool: + return true + +func _input(event:InputEvent) -> void: + if not event is InputEventMouseMotion: + return + + _value.x = event.relative.x + _value.y = event.relative.y + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputMouseAxis2D + + +func _to_string(): + return "(GUIDEInputMouseAxis2D)" + + +func _editor_name() -> String: + return "Mouse Axis 2D" + + +func _editor_description() -> String: + return "Relative mouse movement on 2 axes." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_2D diff --git a/addons/guide/inputs/guide_input_mouse_button.gd b/addons/guide/inputs/guide_input_mouse_button.gd new file mode 100644 index 0000000..e5315e9 --- /dev/null +++ b/addons/guide/inputs/guide_input_mouse_button.gd @@ -0,0 +1,65 @@ +@tool +class_name GUIDEInputMouseButton +extends GUIDEInput + + +@export var button:MouseButton = MOUSE_BUTTON_LEFT: + set(value): + if value == button: + return + button = value + emit_changed() + + +func _needs_reset(): + # mouse wheel up and down can potentially send multiple inputs within a single frame + # so we need to smooth this out a bit. + return button == MOUSE_BUTTON_WHEEL_UP or button == MOUSE_BUTTON_WHEEL_DOWN + +var _reset_to:Vector3 +var _was_pressed_this_frame:bool + +func _reset() -> void: + _was_pressed_this_frame = false + _value = _reset_to + + +func _input(event:InputEvent): + if not event is InputEventMouseButton: + return + + if event.button_index != button: + return + + + if _needs_reset(): + # we always reset to the last event we received in a frame + # so after the frame is over we're still in sync. + _reset_to.x = 1.0 if event.pressed else 0.0 + + if event.pressed: + _was_pressed_this_frame = true + + if not event.pressed and _was_pressed_this_frame: + # keep pressed state for this frame + return + + _value.x = 1.0 if event.pressed else 0.0 + +func is_same_as(other:GUIDEInput) -> bool: + return other is GUIDEInputMouseButton and other.button == button + + +func _to_string(): + return "(GUIDEInputMouseButton: button=" + str(button) + ")" + + +func _editor_name() -> String: + return "Mouse Button" + +func _editor_description() -> String: + return "A press of a mouse button. The mouse wheel is also a button." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.BOOL diff --git a/addons/guide/inputs/guide_input_mouse_position.gd b/addons/guide/inputs/guide_input_mouse_position.gd new file mode 100644 index 0000000..c3389b4 --- /dev/null +++ b/addons/guide/inputs/guide_input_mouse_position.gd @@ -0,0 +1,41 @@ +@tool +class_name GUIDEInputMousePosition +extends GUIDEInput + + +func _begin_usage() -> void : + _update_mouse_position() + + +func _input(event:InputEvent) -> void: + if not event is InputEventMouseMotion: + return + + _update_mouse_position() + + +func _update_mouse_position(): + var position:Vector2 = Engine.get_main_loop().root.get_mouse_position() + + _value.x = position.x + _value.y = position.y + + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputMousePosition + + +func _to_string(): + return "(GUIDEInputMousePosition)" + + +func _editor_name() -> String: + return "Mouse Position" + + +func _editor_description() -> String: + return "Position of the mouse in the main viewport." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_2D diff --git a/addons/guide/inputs/guide_input_touch_angle.gd b/addons/guide/inputs/guide_input_touch_angle.gd new file mode 100644 index 0000000..01fb829 --- /dev/null +++ b/addons/guide/inputs/guide_input_touch_angle.gd @@ -0,0 +1,83 @@ +## Input representing angle changes between two fingers. +@tool +class_name GUIDEInputTouchAngle +extends GUIDEInput + +const GUIDETouchState = preload("guide_touch_state.gd") + +## Unit in which the angle should be provided +enum AngleUnit { + ## Angle is provided in radians + RADIANS = 0, + ## Angle is provided in degrees. + DEGREES = 1 +} + +## The unit in which the angle should be provided +@export var unit:AngleUnit = AngleUnit.RADIANS + +var _initial_angle:float = INF + +# We use the reset call to calculate the angle for this frame +# so it can serve as reference for the next frame +func _needs_reset() -> bool: + return true + +func _reset(): + var angle = _calculate_angle() + # update initial angle when input is actuated or stops being actuated + if is_finite(_initial_angle) != is_finite(angle): + _initial_angle = angle + +func _input(event:InputEvent) -> void: + if not GUIDETouchState.process_input_event(event): + # not touch-related + return + + var angle := _calculate_angle() + # if either current angle or initial angle is not set, + # we are zero + if not is_finite(angle) or not is_finite(_initial_angle): + _value = Vector3.ZERO + return + + # we assume that _initial_distance is never 0 because + # you cannot have two fingers physically at the same place + # on a touch screen + _value = Vector3(angle - _initial_angle, 0, 0) + + +func _calculate_angle() -> float: + var pos1:Vector2 = GUIDETouchState.get_finger_position(0, 2) + # if we have no position for first finger, we can immediately abort + if not pos1.is_finite(): + return INF + + var pos2:Vector2 = GUIDETouchState.get_finger_position(1, 2) + # if there is no second finger, we can abort as well + if not pos2.is_finite(): + return INF + + # calculate distance for the fingers + return -pos1.angle_to_point(pos2) + + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputTouchAngle and \ + other.unit == unit + + +func _to_string(): + return "(GUIDEInputTouchAngle unit=" + ("radians" if unit == AngleUnit.RADIANS else "degrees") + ")" + + +func _editor_name() -> String: + return "Touch Angle" + + +func _editor_description() -> String: + return "Angle changes of two touching fingers." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_1D diff --git a/addons/guide/inputs/guide_input_touch_axis_1d.gd b/addons/guide/inputs/guide_input_touch_axis_1d.gd new file mode 100644 index 0000000..3615efa --- /dev/null +++ b/addons/guide/inputs/guide_input_touch_axis_1d.gd @@ -0,0 +1,44 @@ +@tool +class_name GUIDEInputTouchAxis1D +extends GUIDEInputTouchAxisBase + +enum GUIDEInputTouchAxis { + X, + Y +} + +@export var axis:GUIDEInputTouchAxis: + set(value): + if value == axis: + return + axis = value + emit_changed() + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputTouchAxis1D and \ + other.finger_count == finger_count and \ + other.finger_index == finger_index and \ + other.axis == axis + +func _apply_value(value:Vector2): + match axis: + GUIDEInputTouchAxis.X: + _value = Vector3(value.x, 0, 0) + GUIDEInputTouchAxis.Y: + _value = Vector3(value.y, 0, 0) + +func _to_string(): + return "(GUIDEInputTouchAxis1D finger_count=" + str(finger_count) + \ + " finger_index=" + str(finger_index) +" axis=" + ("X" if axis == GUIDEInputTouchAxis.X else "Y") + ")" + + +func _editor_name() -> String: + return "Touch Axis1D" + + +func _editor_description() -> String: + return "Relative movement of a touching finger on a single axis." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_1D diff --git a/addons/guide/inputs/guide_input_touch_axis_2d.gd b/addons/guide/inputs/guide_input_touch_axis_2d.gd new file mode 100644 index 0000000..13b79d7 --- /dev/null +++ b/addons/guide/inputs/guide_input_touch_axis_2d.gd @@ -0,0 +1,27 @@ +@tool +class_name GUIDEInputTouchAxis2D +extends GUIDEInputTouchAxisBase + +func _apply_value(value:Vector2): + _value = Vector3(value.x, value.y, 0) + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputTouchAxis2D and \ + other.finger_count == finger_count and \ + other.finger_index == finger_index + + +func _to_string(): + return "(GUIDEInputTouchAxis2D finger_count=" + str(finger_count) + \ + " finger_index=" + str(finger_index) +")" + + +func _editor_name() -> String: + return "Touch Axis2D" + + +func _editor_description() -> String: + return "2D relative movement of a touching finger." + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_2D diff --git a/addons/guide/inputs/guide_input_touch_axis_base.gd b/addons/guide/inputs/guide_input_touch_axis_base.gd new file mode 100644 index 0000000..3a2ab9f --- /dev/null +++ b/addons/guide/inputs/guide_input_touch_axis_base.gd @@ -0,0 +1,46 @@ +## Base class for axis-like touch input. +@tool +class_name GUIDEInputTouchAxisBase +extends GUIDEInputTouchBase + +const GUIDETouchState = preload("guide_touch_state.gd") + +var _last_position:Vector2 = Vector2.INF + +# We use the reset call to calculate the position for this frame +# so it can serve as reference for the next frame +func _needs_reset() -> bool: + return true + +func _reset() -> void: + _last_position = GUIDETouchState.get_finger_position(finger_index, finger_count) + _apply_value(_calculate_value(_last_position)) + +func _input(event:InputEvent) -> void: + if not GUIDETouchState.process_input_event(event): + # not touch-related + return + + # calculate live position from the cache + var new_position:Vector2 = GUIDETouchState.get_finger_position(finger_index, finger_count) + + _apply_value(_calculate_value(new_position)) + +func _apply_value(value:Vector2): + pass + +func _calculate_value(new_position:Vector2) -> Vector2: + # if we cannot calculate a delta because old or new position + # are undefined, we say the delta is zero + if not _last_position.is_finite() or not new_position.is_finite(): + return Vector2.ZERO + + return new_position - _last_position + + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputTouchAxis2D and \ + other.finger_count == finger_count and \ + other.finger_index == finger_index + + diff --git a/addons/guide/inputs/guide_input_touch_base.gd b/addons/guide/inputs/guide_input_touch_base.gd new file mode 100644 index 0000000..7f9aa0b --- /dev/null +++ b/addons/guide/inputs/guide_input_touch_base.gd @@ -0,0 +1,22 @@ +## Base class for generic touch input +@tool +class_name GUIDEInputTouchBase +extends GUIDEInput + +## The number of fingers to be tracked. +@export_range(1, 5, 1, "or_greater") var finger_count:int = 1: + set(value): + if value < 1: + value = 1 + finger_count = value + emit_changed() + +## The index of the finger for which the position/delta should be reported +## (0 = first finger, 1 = second finger, etc.). If -1, reports the average position/delta for +## all fingers currently touching. +@export_range(-1, 4, 1, "or_greater") var finger_index:int = 0: + set(value): + if value < -1: + value = -1 + finger_index = value + emit_changed() diff --git a/addons/guide/inputs/guide_input_touch_distance.gd b/addons/guide/inputs/guide_input_touch_distance.gd new file mode 100644 index 0000000..c4263a5 --- /dev/null +++ b/addons/guide/inputs/guide_input_touch_distance.gd @@ -0,0 +1,72 @@ +## Input representing the distance changes between two fingers. +@tool +class_name GUIDEInputTouchDistance +extends GUIDEInput + +const GUIDETouchState = preload("guide_touch_state.gd") + +var _initial_distance:float = INF + +# We use the reset call to calculate the distance for this frame +# so it can serve as reference for the next frame +func _needs_reset() -> bool: + return true + +func _reset(): + var distance = _calculate_distance() + # update initial distance when input is actuated or stops being actuated + if is_finite(_initial_distance) != is_finite(distance): + _initial_distance = distance + + +func _input(event:InputEvent) -> void: + if not GUIDETouchState.process_input_event(event): + # not touch-related + return + + var distance := _calculate_distance() + # if either current distance or initial distance is not set, + # we are zero + if not is_finite(distance) or not is_finite(_initial_distance): + _value = Vector3.ZERO + return + + # we assume that _initial_distance is never 0 because + # you cannot have two fingers physically at the same place + # on a touch screen + _value = Vector3(distance / _initial_distance, 0, 0) + + +func _calculate_distance() -> float: + var pos1:Vector2 = GUIDETouchState.get_finger_position(0, 2) + # if we have no position for first finger, we can immediately abort + if not pos1.is_finite(): + return INF + + var pos2:Vector2 = GUIDETouchState.get_finger_position(1, 2) + # if there is no second finger, we can abort as well + if not pos2.is_finite(): + return INF + + # calculate distance for the fingers + return pos1.distance_to(pos2) + + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputTouchDistance + + +func _to_string(): + return "(GUIDEInputTouchDistance)" + + +func _editor_name() -> String: + return "Touch Distance" + + +func _editor_description() -> String: + return "Distance of two touching fingers." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_1D diff --git a/addons/guide/inputs/guide_input_touch_position.gd b/addons/guide/inputs/guide_input_touch_position.gd new file mode 100644 index 0000000..7778987 --- /dev/null +++ b/addons/guide/inputs/guide_input_touch_position.gd @@ -0,0 +1,47 @@ +@tool +class_name GUIDEInputTouchPosition +extends GUIDEInputTouchBase + +const GUIDETouchState = preload("guide_touch_state.gd") + + +func _begin_usage(): + _value = Vector3.INF + + +func _input(event:InputEvent) -> void: + # update touch state + if not GUIDETouchState.process_input_event(event): + # not touch-related + return + + # update finger position + var position := GUIDETouchState.get_finger_position(finger_index, finger_count) + if not position.is_finite(): + _value = Vector3.INF + return + + _value = Vector3(position.x, position.y, 0) + + +func is_same_as(other:GUIDEInput): + return other is GUIDEInputTouchPosition and \ + other.finger_count == finger_count and \ + other.finger_index == finger_index + + +func _to_string(): + return "(GUIDEInputTouchPosition finger_count=" + str(finger_count) + \ + " finger_index=" + str(finger_index) +")" + + +func _editor_name() -> String: + return "Touch Position" + + +func _editor_description() -> String: + return "Position of a touching finger." + + +func _native_value_type() -> GUIDEAction.GUIDEActionValueType: + return GUIDEAction.GUIDEActionValueType.AXIS_2D diff --git a/addons/guide/inputs/guide_touch_state.gd b/addons/guide/inputs/guide_touch_state.gd new file mode 100644 index 0000000..dd10fb8 --- /dev/null +++ b/addons/guide/inputs/guide_touch_state.gd @@ -0,0 +1,73 @@ +@tool +## Shared information about current touch state. This simplifies implementation of the touch inputs +## and avoids having to process the same events multiple times. + +# Cached finger positions +static var _finger_positions:Dictionary = {} + +# Events processed this frame. +static var _processed_events:Dictionary = {} + +# Last frame we were called +static var _last_frame:int = -1 + + +## Processes an input event and updates touch state. Returns true, if the given event +## was touch-related. +static func process_input_event(event:InputEvent) -> bool: + if not event is InputEventScreenTouch and not event is InputEventScreenDrag: + return false + + var this_frame = Engine.get_process_frames() + + # if we are in a new frame, clear the processed events + if this_frame != _last_frame: + _last_frame = this_frame + _processed_events.clear() + + # if the event already was processed, skip processing it again + if _processed_events.has(event): + return true + + _processed_events[event] = true + + var index:int = event.index + + if event is InputEventScreenTouch: + if event.pressed: + _finger_positions[index] = event.position + else: + _finger_positions.erase(index) + + if event is InputEventScreenDrag: + _finger_positions[index] = event.position + + return true + + +## Gets the finger position of the finger at the given index. +## If finger_index is < 0, returns the average of all finger positions. +## Will only return a position if the amount of fingers +## currently touching matches finger_count. +## +## If no finger position can be determined, returns Vector2.INF. +static func get_finger_position(finger_index:int, finger_count:int) -> Vector2: + # if we have no finger positions right now, we can cut it short here + if _finger_positions.is_empty(): + return Vector2.INF + + # If the finger count doesn't match we have no position right now + if _finger_positions.size() != finger_count: + return Vector2.INF + + # if a finger index is set, use this fingers position, if available + if finger_index > -1: + return _finger_positions.get(finger_index, Vector2.INF) + + + var result = Vector2.ZERO + for value in _finger_positions.values(): + result += value + + result /= float(finger_count) + return result diff --git a/addons/guide/modifiers/guide_modifier.gd b/addons/guide/modifiers/guide_modifier.gd new file mode 100644 index 0000000..6253480 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier.gd @@ -0,0 +1,23 @@ +@tool +@icon("res://addons/guide/modifiers/guide_modifier.svg") +class_name GUIDEModifier +extends Resource + +## Called when the modifier is started to be used by GUIDE. Can be used to perform +## initializations. +func _begin_usage() -> void : + pass + +## Called, when the modifier is no longer used by GUIDE. Can be used to perform +## cleanup. +func _end_usage() -> void: + pass + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + return input + +func _editor_name() -> String: + return "" + +func _editor_description() -> String: + return "" diff --git a/addons/guide/modifiers/guide_modifier.svg b/addons/guide/modifiers/guide_modifier.svg new file mode 100644 index 0000000..e51d736 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/addons/guide/modifiers/guide_modifier.svg.import b/addons/guide/modifiers/guide_modifier.svg.import new file mode 100644 index 0000000..3d85142 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://j64d8n4am2uh" +path="res://.godot/imported/guide_modifier.svg-8cf939ca3244410aba00f7b558561d72.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/modifiers/guide_modifier.svg" +dest_files=["res://.godot/imported/guide_modifier.svg-8cf939ca3244410aba00f7b558561d72.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=0.5 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/modifiers/guide_modifier_3d_coordinates.gd b/addons/guide/modifiers/guide_modifier_3d_coordinates.gd new file mode 100644 index 0000000..21abb90 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_3d_coordinates.gd @@ -0,0 +1,53 @@ +## Converts a position input in viewport coordinates (e.g. from the mouse position input) +## into 3D coordinates (e.g. 3D world coordinates). Useful to get a 3D 'world' position. +## Returns a Vector3.INF if no 3D world coordinates can be determined. +@tool +class_name GUIDEModifier3DCoordinates +extends GUIDEModifier + +## The maximum depth of the ray cast used to detect the 3D position. +@export var max_depth:float = 1000.0 + +## Whether the rays cast should collide with areas. +@export var collide_with_areas:bool = false + +## Collision mask to use for the ray cast. +@export_flags_3d_physics var collision_mask:int + + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + # if we collide with nothing, no need to even try + if collision_mask == 0: + return Vector3.INF + + if not input.is_finite(): + return Vector3.INF + + var viewport = Engine.get_main_loop().root + var camera:Camera3D = viewport.get_camera_3d() + if camera == null: + return Vector3.INF + + + var input_position:Vector2 = Vector2(input.x, input.y) + + var from:Vector3 = camera.project_ray_origin(input_position) + var to:Vector3 = from + camera.project_ray_normal(input_position) * max_depth + var query:= PhysicsRayQueryParameters3D.create(from, to, collision_mask) + query.collide_with_areas = collide_with_areas + + var result = viewport.world_3d.direct_space_state.intersect_ray(query) + if result.has("position"): + return result.position + + return Vector3.INF + + + +func _editor_name() -> String: + return "3D coordinates" + + +func _editor_description() -> String: + return "Converts a position input in viewport coordinates (e.g. from the mouse position input)\n" + \ + "into 3D coordinates (e.g. 3D world coordinates). Useful to get a 3D 'world' position." diff --git a/addons/guide/modifiers/guide_modifier_8_way_direction.gd b/addons/guide/modifiers/guide_modifier_8_way_direction.gd new file mode 100644 index 0000000..8ae2954 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_8_way_direction.gd @@ -0,0 +1,47 @@ +@tool +## A filter that converts a 2D input into a boolean that is true when the +## input direction matches the selected direction. Note, that north is negative Y, +## because in Godot negative Y is up. +class_name GUIDEModifier8WayDirection +extends GUIDEModifier + +enum GUIDEDirection { + EAST = 0, + NORTH_EAST = 1, + NORTH = 2, + NORTH_WEST = 3, + WEST = 4, + SOUTH_WEST = 5, + SOUTH = 6, + SOUTH_EAST = 7 +} + +## The direction in which the input should point. +@export var direction:GUIDEDirection = GUIDEDirection.EAST + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + return Vector3.INF + + if input.is_zero_approx(): + return Vector3.ZERO + + + + # get the angle in which the direction is pointing in radians. + var angle_radians = atan2( -input.y, input.x ); + var octant = roundi( 8 * angle_radians / TAU + 8 ) % 8; + if octant == direction: + return Vector3.RIGHT # (1, 0, 0) indicating boolean true + else: + return Vector3.ZERO + + +func _editor_name() -> String: + return "8-way direction" + + +func _editor_description() -> String: + return "Converts a 2D input into a boolean that is true when the\n" + \ + "input direction matches the selected direction. Note, that north is negative Y,\n" + \ + "because in Godot negative Y is up." diff --git a/addons/guide/modifiers/guide_modifier_canvas_coordinates.gd b/addons/guide/modifiers/guide_modifier_canvas_coordinates.gd new file mode 100644 index 0000000..23a5938 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_canvas_coordinates.gd @@ -0,0 +1,35 @@ +## Converts a position input in viewport coordinates (e.g. from the mouse position input) +## into canvas coordinates (e.g. 2D world coordinates). Useful to get a 2D 'world' position. +@tool +class_name GUIDEModifierCanvasCoordinates +extends GUIDEModifier + +## If checked, the input will be treated as relative input (position change) +## rather than absolute input (position). +@export var relative_input:bool: + set(value): + relative_input = value + emit_changed() + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + return Vector3.INF + + var viewport = Engine.get_main_loop().root + var transform = viewport.canvas_transform.affine_inverse() + var coordinates = transform * Vector2(input.x, input.y) + + if relative_input: + var origin = transform * Vector2.ZERO + coordinates -= origin + + return Vector3(coordinates.x, coordinates.y, input.z) + + +func _editor_name() -> String: + return "Canvas coordinates" + + +func _editor_description() -> String: + return "Converts a position input in viewport coordinates (e.g. from the mouse position input)\n" + \ + "into canvas coordinates (e.g. 2D world coordinates). Useful to get a 2D 'world' position." diff --git a/addons/guide/modifiers/guide_modifier_curve.gd b/addons/guide/modifiers/guide_modifier_curve.gd new file mode 100644 index 0000000..bb55b11 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_curve.gd @@ -0,0 +1,51 @@ +@tool +## Applies a separate curve to each input axis. +class_name GUIDEModifierCurve +extends GUIDEModifier + + +## The curve to apply to the x axis +@export var curve: Curve = default_curve() + +## Apply modifier to X axis +@export var x: bool = true + +## Apply modifier to Y axis +@export var y: bool = true + +## Apply modifier to Z axis +@export var z: bool = true + + +## Create default curve resource with a smoothstep, 0.0 - 1.0 input/output range +static func default_curve() -> Curve: + var curve = Curve.new() + curve.add_point(Vector2(0.0, 0.0)) + curve.add_point(Vector2(1.0, 1.0)) + + return curve + + +func _modify_input(input: Vector3, delta: float, value_type: GUIDEAction.GUIDEActionValueType) -> Vector3: + # Curve should never be null + if curve == null: + push_error("No curve added to Curve modifier.") + return input + + if not input.is_finite(): + return Vector3.INF + + # Return vector with enabled axes modified, others remain unchanged. + return Vector3( + curve.sample(input.x) if x else input.x, + curve.sample(input.y) if y else input.y, + curve.sample(input.z) if z else input.z + ) + + +func _editor_name() -> String: + return "Curve" + + +func _editor_description() -> String: + return "Applies a curve to each input axis." diff --git a/addons/guide/modifiers/guide_modifier_deadzone.gd b/addons/guide/modifiers/guide_modifier_deadzone.gd new file mode 100644 index 0000000..b40a00c --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_deadzone.gd @@ -0,0 +1,63 @@ +@tool +## Inputs between the lower and upper threshold are mapped 0 -> 1. +## Values outside the thresholds are clamped. +class_name GUIDEModifierDeadzone +extends GUIDEModifier + +## Lower threshold for the deadzone. +@export_range(0,1) var lower_threshold:float = 0.2: + set(value): + if value > upper_threshold: + lower_threshold = upper_threshold + else: + lower_threshold = value + emit_changed() + + +## Upper threshold for the deadzone. +@export_range(0,1) var upper_threshold:float = 1.0: + set(value): + if value < lower_threshold: + upper_threshold = lower_threshold + else: + upper_threshold = value + emit_changed() + + +func _rescale(value:float) -> float: + return min(1.0, (max(0.0, abs(value) - lower_threshold) / (upper_threshold - lower_threshold))) * sign(value) + + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if upper_threshold <= lower_threshold: + return input + + if not input.is_finite(): + return Vector3.INF + + match value_type: + GUIDEAction.GUIDEActionValueType.BOOL, GUIDEAction.GUIDEActionValueType.AXIS_1D: + return Vector3(_rescale(input.x), input.y, input.z) + + GUIDEAction.GUIDEActionValueType.AXIS_2D: + var v2d = Vector2(input.x, input.y) + if v2d.is_zero_approx(): + return Vector3(0, 0, input.z) + v2d = v2d.normalized() * _rescale(v2d.length()) + return Vector3(v2d.x, v2d.y, input.z) + + GUIDEAction.GUIDEActionValueType.AXIS_3D: + if input.is_zero_approx(): + return Vector3.ZERO + return input.normalized() * _rescale(input.length()) + _: + push_error("Unsupported value type. This is a bug. Please report it.") + return input + + +func _editor_name() -> String: + return "Deadzone" + +func _editor_description() -> String: + return "Inputs between the lower and upper threshold are mapped 0 -> 1.\n" + \ + "Values outside the thresholds are clamped." diff --git a/addons/guide/modifiers/guide_modifier_input_swizzle.gd b/addons/guide/modifiers/guide_modifier_input_swizzle.gd new file mode 100644 index 0000000..115a50f --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_input_swizzle.gd @@ -0,0 +1,43 @@ +## Swizzle the input vector components. Useful to map 1D input to 2D or vice versa. +@tool +class_name GUIDEModifierInputSwizzle +extends GUIDEModifier + +enum GUIDEInputSwizzleOperation { + ## Swap X and Y axes. + YXZ, + ## Swap X and Z axes. + ZYX, + ## Swap Y and Z axes. + XZY, + ## Y to X, Z to Y, X to Z. + YZX, + ## Y to Z, Z to X, X to Y. + ZXY +} + +## The new order into which the input should be brought. +@export var order:GUIDEInputSwizzleOperation = GUIDEInputSwizzleOperation.YXZ + + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + match order: + GUIDEInputSwizzleOperation.YXZ: + return Vector3(input.y, input.x, input.z) + GUIDEInputSwizzleOperation.ZYX: + return Vector3(input.z, input.y, input.x) + GUIDEInputSwizzleOperation.XZY: + return Vector3(input.x, input.z, input.y) + GUIDEInputSwizzleOperation.YZX: + return Vector3(input.y, input.z, input.x) + GUIDEInputSwizzleOperation.ZXY: + return Vector3(input.z, input.x, input.y) + _: + push_error("Unknown order ", order , " this is most likely a bug, please report it.") + return input + +func _editor_name() -> String: + return "Input Swizzle" + +func _editor_description() -> String: + return "Swizzle the input vector components. Useful to map 1D input to 2D or vice versa." diff --git a/addons/guide/modifiers/guide_modifier_map_range.gd b/addons/guide/modifiers/guide_modifier_map_range.gd new file mode 100644 index 0000000..65f2275 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_map_range.gd @@ -0,0 +1,67 @@ +@tool +## Maps an input range to an output range and optionally clamps the output. +class_name GUIDEModifierMapRange +extends GUIDEModifier + +## Should the output be clamped to the range? +@export var apply_clamp:bool = true + +## The minimum input value +@export var input_min:float = 0.0 + +## The maximum input value +@export var input_max:float = 1.0 + +## The minimum output value +@export var output_min:float = 0.0 + +## The maximum output value +@export var output_max:float = 1.0 + +## Apply modifier to X axis +@export var x:bool = true + +## Apply modifier to Y axis +@export var y:bool = true + +## Apply modifier to Z axis +@export var z:bool = true + +var _omin:float +var _omax:float + +func _begin_usage(): + # we calculate the min and max of the output range here, so we can use them later and don't have to + # recalculate them every time the modifier is used + _omin = min(output_min, output_max) + _omax = max(output_min, output_max) + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + return Vector3.INF + + var x_value:float = remap(input.x, input_min, input_max, output_min, output_max) + var y_value:float = remap(input.y, input_min, input_max, output_min, output_max) + var z_value:float = remap(input.z, input_min, input_max, output_min, output_max) + + if apply_clamp: + # clamp doesn't handle reverse ranges, so we need to use our calculated normalized output range + # to clamp the output values + x_value = clamp(x_value, _omin, _omax) + y_value = clamp(y_value, _omin, _omax) + z_value = clamp(z_value, _omin, _omax) + + # Return vector with enabled axes set, others unchanged + return Vector3( + x_value if x else input.x, + y_value if y else input.y, + z_value if z else input.z, + ) + + +func _editor_name() -> String: + return "Map Range" + + +func _editor_description() -> String: + return "Maps an input range to an output range and optionally clamps the output" diff --git a/addons/guide/modifiers/guide_modifier_negate.gd b/addons/guide/modifiers/guide_modifier_negate.gd new file mode 100644 index 0000000..895d1ef --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_negate.gd @@ -0,0 +1,52 @@ +## Inverts input per axis. +@tool +class_name GUIDEModifierNegate +extends GUIDEModifier + +## Whether the X axis should be inverted. +@export var x:bool = true: + set(value): + if x == value: + return + x = value + _update_caches() + emit_changed() + +## Whether the Y axis should be inverted. +@export var y:bool = true: + set(value): + if y == value: + return + y = value + _update_caches() + emit_changed() + +## Whether the Z axis should be inverted. +@export var z:bool = true: + set(value): + if z == value: + return + z = value + _update_caches() + emit_changed() + +var _multiplier:Vector3 = Vector3.ONE * -1 + +func _update_caches(): + _multiplier.x = -1 if x else 1 + _multiplier.y = -1 if y else 1 + _multiplier.z = -1 if z else 1 + + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + return Vector3.INF + + return input * _multiplier + +func _editor_name() -> String: + return "Negate" + + +func _editor_description() -> String: + return "Inverts input per axis." diff --git a/addons/guide/modifiers/guide_modifier_normalize.gd b/addons/guide/modifiers/guide_modifier_normalize.gd new file mode 100644 index 0000000..7b10f52 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_normalize.gd @@ -0,0 +1,17 @@ +## Normalizes the input vector. +@tool +class_name GUIDEModifierNormalize +extends GUIDEModifier + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + return Vector3.INF + + return input.normalized() + +func _editor_name() -> String: + return "Normalize" + + +func _editor_description() -> String: + return "Normalizes the input vector." diff --git a/addons/guide/modifiers/guide_modifier_positive_negative.gd b/addons/guide/modifiers/guide_modifier_positive_negative.gd new file mode 100644 index 0000000..1f0ce35 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_positive_negative.gd @@ -0,0 +1,65 @@ +## Limits inputs to positive or negative values. +@tool +class_name GUIDEModifierPositiveNegative +extends GUIDEModifier + +enum LimitRange { + POSITIVE = 1, + NEGATIVE = 2 +} + +## The range of numbers to which the input should be limited +@export var range:LimitRange = LimitRange.POSITIVE + +## Whether the X axis should be affected. +@export var x:bool = true: + set(value): + if x == value: + return + x = value + emit_changed() + +## Whether the Y axis should be affected. +@export var y:bool = true: + set(value): + if y == value: + return + y = value + emit_changed() + +## Whether the Z axis should be affected. +@export var z:bool = true: + set(value): + if z == value: + return + z = value + emit_changed() + + + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + return Vector3.INF + + match range: + LimitRange.POSITIVE: + return Vector3( + max(0, input.x) if x else input.x, \ + max(0, input.y) if y else input.y, \ + max(0, input.z) if z else input.z \ + ) + LimitRange.NEGATIVE: + return Vector3( + min(0, input.x) if x else input.x, \ + min(0, input.y) if y else input.y, \ + min(0, input.z) if z else input.z \ + ) + # should never happen + return input + +func _editor_name() -> String: + return "Positive/Negative" + + +func _editor_description() -> String: + return "Clamps the input to positive or negative values." diff --git a/addons/guide/modifiers/guide_modifier_scale.gd b/addons/guide/modifiers/guide_modifier_scale.gd new file mode 100644 index 0000000..68e0564 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_scale.gd @@ -0,0 +1,35 @@ +@tool +## Scales the input by the given value and optionally, delta time. +class_name GUIDEModifierScale +extends GUIDEModifier + +## The scale by which the input should be scaled. +@export var scale:Vector3 = Vector3.ONE: + set(value): + scale = value + emit_changed() + + +## If true, delta time will be multiplied in addition to the scale. +@export var apply_delta_time:bool = false: + set(value): + apply_delta_time = value + emit_changed() + + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + return Vector3.INF + + if apply_delta_time: + return input * scale * delta + else: + return input * scale + + +func _editor_name() -> String: + return "Scale" + + +func _editor_description() -> String: + return "Scales the input by the given value and optionally, delta time." diff --git a/addons/guide/modifiers/guide_modifier_virtual_cursor.gd b/addons/guide/modifiers/guide_modifier_virtual_cursor.gd new file mode 100644 index 0000000..79ada82 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_virtual_cursor.gd @@ -0,0 +1,105 @@ +## Stateful modifier which provides a virtual "mouse" cursor driven by input. The modifier +## returns the current cursor position in pixels releative to the origin of the currently +## active window. +@tool +class_name GUIDEModifierVirtualCursor +extends GUIDEModifier + +enum ScreenScale { + ## Input is not scaled with input screen size. This means that the cursor will + ## visually move slower on higher resolutions. + NONE = 0, + ## Input is scaled with the longer axis of the screen size (e.g. width in + ## landscape mode, height in portrait mode). The cursor will move with + ## the same visual speed on all resolutions. + LONGER_AXIS = 1, + ## Input is scaled with the shorter axis of the screen size (e.g. height in + ## landscape mode, width in portrait mode). The cursor will move with the + ## same visual speed on all resolutions. + SHORTER_AXIS = 2 +} + +## The initial position of the virtual cursor (given in screen relative coordinates) +@export var initial_position:Vector2 = Vector2(0.5, 0.5): + set(value): + initial_position = value.clamp(Vector2.ZERO, Vector2.ONE) + +## The cursor movement speed in pixels. +@export var speed:Vector3 = Vector3.ONE + +## Screen scaling to be applied to the cursor movement. This controls +## whether the cursor movement speed is resolution dependent or not. +## If set to anything but [code]None[/code] then the input value will +## be multiplied with the window width/height depending on the setting. +@export var screen_scale:ScreenScale = ScreenScale.LONGER_AXIS + +## The scale by which the input should be scaled. +## @deprecated: use [member speed] instead. +var scale:Vector3: + get: return speed + set(value): speed = value + +## If true, the cursor movement speed is in pixels per second, otherwise it is in pixels +## per frame. +@export var apply_delta_time:bool = true + + +## Cursor offset in pixels. +var _offset:Vector3 = Vector3.ZERO + +## Returns the scaled screen size. This takes Godot's scaling factor for windows into account. +func _get_scaled_screen_size(): + # Get window size, including scaling factor + var window = Engine.get_main_loop().get_root() + return window.get_screen_transform().affine_inverse() * Vector2(window.size) + +func _begin_usage(): + var window_size = _get_scaled_screen_size() + _offset = Vector3(window_size.x * initial_position.x, window_size.y * initial_position.y, 0) + + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + # input is invalid, so just return current cursor position + return _offset + + var window_size = _get_scaled_screen_size() + input *= speed + + if apply_delta_time: + input *= delta + + var screen_scale_factor:float = 1.0 + match screen_scale: + ScreenScale.LONGER_AXIS: + screen_scale_factor = max(window_size.x, window_size.y) + ScreenScale.SHORTER_AXIS: + screen_scale_factor = min(window_size.x, window_size.y) + + input *= screen_scale_factor + + # apply input and clamp to window size + _offset = (_offset + input).clamp(Vector3.ZERO, Vector3(window_size.x, window_size.y, 0)) + + return _offset + +func _editor_name() -> String: + return "Virtual Cursor" + + +func _editor_description() -> String: + return "Stateful modifier which provides a virtual \"mouse\" cursor driven by input. The modifier\n" + \ + "returns the current cursor position in pixels releative to the origin of the currently \n" + \ + "active window." + + +# support for legacy properties +func _get_property_list(): + return [ + { + "name": "scale", + "type": TYPE_VECTOR3, + "usage": PROPERTY_USAGE_NO_EDITOR + } + ] + diff --git a/addons/guide/modifiers/guide_modifier_window_relative.gd b/addons/guide/modifiers/guide_modifier_window_relative.gd new file mode 100644 index 0000000..66c88d7 --- /dev/null +++ b/addons/guide/modifiers/guide_modifier_window_relative.gd @@ -0,0 +1,26 @@ +## Converts the value of the input into window-relative units between 0 and 1. +## E.g. if a mouse cursor moves half a screen to the right and down, then +## this modifier will return (0.5, 0.5). +@tool +class_name GUIDEModifierWindowRelative +extends GUIDEModifier + + +func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3: + if not input.is_finite(): + return Vector3.INF + + var window = Engine.get_main_loop().get_root() + # We want real pixels, so we need to factor in any scaling that the window does. + var window_size:Vector2 = window.get_screen_transform().affine_inverse() * Vector2(window.size) + return Vector3(input.x / window_size.x, input.y / window_size.y, input.z) + + +func _editor_name() -> String: + return "Window relative" + + +func _editor_description() -> String: + return "Converts the value of the input into window-relative units between 0 and 1.\n" + \ + "E.g. if a mouse cursor moves half a screen to the right and down, then \n" + \ + "this modifier will return (0.5, 0.5)." diff --git a/addons/guide/plugin.cfg b/addons/guide/plugin.cfg new file mode 100644 index 0000000..81e6856 --- /dev/null +++ b/addons/guide/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Godot Unified Input Detection Engine (G.U.I.D.E)" +description="" +author="Jan Thomä" +version="0.5.2" +script="plugin.gd" diff --git a/addons/guide/plugin.gd b/addons/guide/plugin.gd new file mode 100644 index 0000000..cb5410b --- /dev/null +++ b/addons/guide/plugin.gd @@ -0,0 +1,45 @@ +@tool +extends EditorPlugin +const MainPanel = preload("editor/mapping_context_editor/mapping_context_editor.tscn") + +var _main_panel:Control + + +func _enable_plugin(): + add_autoload_singleton("GUIDE", "res://addons/guide/guide.gd") + +func _enter_tree() -> void: + _main_panel = MainPanel.instantiate() + _main_panel.initialize(self) + EditorInterface.get_editor_main_screen().add_child(_main_panel) + # Hide the main panel. Very much required. + _make_visible(false) + +func _exit_tree() -> void: + if is_instance_valid(_main_panel): + _main_panel.queue_free() + GUIDEInputFormatter.cleanup() + +func _disable_plugin(): + remove_autoload_singleton("GUIDE") + + +func _edit(object): + if object is GUIDEMappingContext: + _main_panel.edit(object) + +func _get_plugin_name() -> String: + return "G.U.I.D.E" + +func _get_plugin_icon() -> Texture2D: + return preload("res://addons/guide/editor/logo_editor_small.svg") + +func _has_main_screen() -> bool: + return true + +func _handles(object:Variant) -> bool: + return object is GUIDEMappingContext + +func _make_visible(visible): + if is_instance_valid(_main_panel): + _main_panel.visible = visible diff --git a/addons/guide/remapping/guide_input_detector.gd b/addons/guide/remapping/guide_input_detector.gd new file mode 100644 index 0000000..6b2a5d0 --- /dev/null +++ b/addons/guide/remapping/guide_input_detector.gd @@ -0,0 +1,281 @@ +@tool +## Helper node for detecting inputs. Detects the next input matching a specification and +## emits a signal with the detected input. +class_name GUIDEInputDetector +extends Node + +## The device type for which the input should be filtered. +enum DeviceType { + ## Only detect input from keyboard. + KEYBOARD = 1, + ## Only detect input from the mouse. + MOUSE = 2, + ## Only detect input from joysticks/gamepads. + JOY = 4 + # touch doesn't make a lot of sense as this is usually + # not remappable. +} + +## Which joy index should be used for detected joy events +enum JoyIndex { + # Use -1, so the detected input will match any joystick + ANY = 0, + # Use the actual index of the detected joystick. + DETECTED = 1 +} + +## A countdown between initiating a dection and the actual start of the +## detection. This is useful because when the user clicks a button to +## start a detection, we want to make sure that the player is actually +## ready (and not accidentally moves anything). If set to 0, no countdown +## will be started. +@export_range(0, 2, 0.1, "or_greater") var detection_countdown_seconds:float = 0.5 + +## Minimum amplitude to detect any axis. +@export_range(0, 1, 0.1, "or_greater") var minimum_axis_amplitude:float = 0.2 + +## If any of these inputs is encountered, the detector will +## treat this as "abort detection". +@export var abort_detection_on:Array[GUIDEInput] = [] + +## Which joy index should be returned for detected joy events. +@export var use_joy_index:JoyIndex = JoyIndex.ANY + +## Whether trigger buttons on controllers should be detected when +## then action value type is limited to boolean. +@export var allow_triggers_for_boolean_actions:bool = true + +## Emitted when the detection has started (e.g. countdown has elapsed). +## Can be used to signal this to the player. +signal detection_started() + +## Emitted when the input detector detects an input of the given type. +## If detection was aborted the given input is null. +signal input_detected(input:GUIDEInput) + +# The timer for the detection countdown. +var _timer:Timer + + + +func _ready(): + _timer = Timer.new() + _timer.one_shot = true + add_child(_timer, false, Node.INTERNAL_MODE_FRONT) + _timer.timeout.connect(_begin_detection) + +var _is_detecting:bool + +## Whether the input detector is currently detecting input. +var is_detecting:bool: + get: return _is_detecting + +var _value_type:GUIDEAction.GUIDEActionValueType +var _device_types:Array[DeviceType] = [] + +## Detects a boolean input type. +func detect_bool(device_types:Array[DeviceType] = []) -> void: + detect(GUIDEAction.GUIDEActionValueType.BOOL, device_types) + + +## Detects a 1D axis input type. +func detect_axis_1d(device_types:Array[DeviceType] = []) -> void: + detect(GUIDEAction.GUIDEActionValueType.AXIS_1D, device_types) + + +## Detects a 2D axis input type. +func detect_axis_2d(device_types:Array[DeviceType] = []) -> void: + detect(GUIDEAction.GUIDEActionValueType.AXIS_2D, device_types) + + +## Detects a 3D axis input type. +func detect_axis_3d(device_types:Array[DeviceType] = []) -> void: + detect(GUIDEAction.GUIDEActionValueType.AXIS_3D, device_types) + + +## Aborts a running detection. If no detection currently runs +## does nothing. +func abort_detection() -> void: + _timer.stop() + if _is_detecting: + _is_detecting = false + input_detected.emit(null) + +## Detects the given input type. If device types are given +## will only detect inputs from the given device types. +## Otherwise will detect inputs from all supported device types. +func detect(value_type:GUIDEAction.GUIDEActionValueType, + device_types:Array[DeviceType] = []) -> void: + if device_types == null: + push_error("Device types must not be null. Supply an empty array if you want to detect input from all devices.") + return + + # reset all abort inputs + for input in abort_detection_on: + input._reset() + + abort_detection() + _value_type = value_type + _device_types = device_types + _timer.start(detection_countdown_seconds) + + +func _begin_detection(): + _is_detecting = true + detection_started.emit() + + +func _input(event:InputEvent) -> void: + if not _is_detecting: + return + + # feed the event into the abort inputs + for input in abort_detection_on: + input._input(event) + # if it triggers, we abort + if input._value.is_finite() and input._value.length() > 0: + # eat the input so it doesn't accidentally trigger something else + get_viewport().set_input_as_handled() + abort_detection() + return + + # check if the event matches the device type we are + # looking for + if not _matches_device_types(event): + return + + # then check if it can be mapped to the desired + # value type + match _value_type: + GUIDEAction.GUIDEActionValueType.BOOL: + _try_detect_bool(event) + GUIDEAction.GUIDEActionValueType.AXIS_1D: + _try_detect_axis_1d(event) + GUIDEAction.GUIDEActionValueType.AXIS_2D: + _try_detect_axis_2d(event) + GUIDEAction.GUIDEActionValueType.AXIS_3D: + _try_detect_axis_3d(event) + + +func _matches_device_types(event:InputEvent) -> bool: + if _device_types.is_empty(): + return true + + if event is InputEventKey: + return _device_types.has(DeviceType.KEYBOARD) + + if event is InputEventMouse: + return _device_types.has(DeviceType.MOUSE) + + if event is InputEventJoypadButton or event is InputEventJoypadMotion: + return _device_types.has(DeviceType.JOY) + + return false + + +func _try_detect_bool(event:InputEvent) -> void: + if event is InputEventKey and event.is_released(): + var result := GUIDEInputKey.new() + result.key = event.physical_keycode + result.shift = event.shift_pressed + result.control = event.ctrl_pressed + result.meta = event.meta_pressed + result.alt = event.alt_pressed + _deliver(result) + return + + if event is InputEventMouseButton and event.is_released(): + var result := GUIDEInputMouseButton.new() + result.button = event.button_index + _deliver(result) + return + + if event is InputEventJoypadButton and event.is_released(): + var result := GUIDEInputJoyButton.new() + result.button = event.button_index + result.joy_index = _find_joy_index(event.device) + _deliver(result) + + if allow_triggers_for_boolean_actions: + # only allow joypad trigger buttons + if not (event is InputEventJoypadMotion): + return + if event.axis != JOY_AXIS_TRIGGER_LEFT and \ + event.axis != JOY_AXIS_TRIGGER_RIGHT: + return + + var result := GUIDEInputJoyAxis1D.new() + result.axis = event.axis + result.joy_index = _find_joy_index(event.device) + _deliver(result) + + + +func _try_detect_axis_1d(event:InputEvent) -> void: + if event is InputEventMouseMotion: + var result := GUIDEInputMouseAxis1D.new() + # Pick the direction in which the mouse was moved more. + if abs(event.relative.x) > abs(event.relative.y): + result.axis = GUIDEInputMouseAxis1D.GUIDEInputMouseAxis.X + else: + result.axis = GUIDEInputMouseAxis1D.GUIDEInputMouseAxis.Y + _deliver(result) + return + + if event is InputEventJoypadMotion: + if abs(event.axis_value) < minimum_axis_amplitude: + return + + var result := GUIDEInputJoyAxis1D.new() + result.axis = event.axis + result.joy_index = _find_joy_index(event.device) + _deliver(result) + + +func _try_detect_axis_2d(event:InputEvent) -> void: + if event is InputEventMouseMotion: + var result := GUIDEInputMouseAxis2D.new() + _deliver(result) + return + + if event is InputEventJoypadMotion: + if event.axis_value < minimum_axis_amplitude: + return + + var result := GUIDEInputJoyAxis2D.new() + match event.axis: + JOY_AXIS_LEFT_X, JOY_AXIS_LEFT_Y: + result.x = JOY_AXIS_LEFT_X + result.y = JOY_AXIS_LEFT_Y + JOY_AXIS_RIGHT_X, JOY_AXIS_RIGHT_Y: + result.x = JOY_AXIS_RIGHT_X + result.y = JOY_AXIS_RIGHT_Y + _: + # not supported for detection + return + result.joy_index = _find_joy_index(event.device) + _deliver(result) + return + + +func _try_detect_axis_3d(event:InputEvent) -> void: + # currently no input for 3D + pass + + +func _find_joy_index(device_id:int) -> int: + if use_joy_index == JoyIndex.ANY: + return -1 + + var pads := Input.get_connected_joypads() + for i in pads.size(): + if pads[i] == device_id: + return i + + return -1 + +func _deliver(input:GUIDEInput) -> void: + _is_detecting = false + # eat the input so it doesn't accidentally trigger something else + get_viewport().set_input_as_handled() + input_detected.emit(input) diff --git a/addons/guide/remapping/guide_remapper.gd b/addons/guide/remapping/guide_remapper.gd new file mode 100644 index 0000000..4037819 --- /dev/null +++ b/addons/guide/remapping/guide_remapper.gd @@ -0,0 +1,307 @@ +class_name GUIDERemapper + +## Emitted when the bound input of an item changes. +signal item_changed(item:ConfigItem, input:GUIDEInput) + +var _remapping_config:GUIDERemappingConfig = GUIDERemappingConfig.new() +var _mapping_contexts:Array[GUIDEMappingContext] = [] + +const GUIDESet = preload("../guide_set.gd") + +## Loads the default bindings as they are currently configured in the mapping contexts and a mapping +## config for editing. Note that the given mapping config will not be modified, so editing can be +## cancelled. Call get_mapping_config to get the modified mapping config. +func initialize(mapping_contexts:Array[GUIDEMappingContext], remapping_config:GUIDERemappingConfig): + _remapping_config = remapping_config.duplicate() if remapping_config != null else GUIDERemappingConfig.new() + + _mapping_contexts.clear() + + for mapping_context in mapping_contexts: + if not is_instance_valid(mapping_context): + push_error("Cannot add null mapping context. Ignoring.") + return + _mapping_contexts.append(mapping_context) + + +## Returns the mapping config with all modifications applied. +func get_mapping_config() -> GUIDERemappingConfig: + return _remapping_config.duplicate() + + +func set_custom_data(key:Variant, value:Variant): + _remapping_config.custom_data[key] = value + + +func get_custom_data(key:Variant, default:Variant = null) -> Variant: + return _remapping_config.custom_data.get(key, default) + + +func remove_custom_data(key:Variant) -> void: + _remapping_config.custom_data.erase(key) + + +## Returns all remappable items. Can be filtered by context, display category or +## action. +func get_remappable_items(context:GUIDEMappingContext = null, + display_category:String = "", + action:GUIDEAction = null) -> Array[ConfigItem]: + + if action != null and not action.is_remappable: + push_warning("Action filter was set but filtered action is not remappable.") + return [] + + + var result:Array[ConfigItem] = [] + for a_context:GUIDEMappingContext in _mapping_contexts: + if context != null and context != a_context: + continue + for action_mapping:GUIDEActionMapping in a_context.mappings: + var mapped_action:GUIDEAction = action_mapping.action + # filter non-remappable actions + if not mapped_action.is_remappable: + continue + + # if action filter is set, only pick mappings for this action + if action != null and action != mapped_action: + continue + + # make config items + for index:int in action_mapping.input_mappings.size(): + var input_mapping:GUIDEInputMapping = action_mapping.input_mappings[index] + if input_mapping.override_action_settings and not input_mapping.is_remappable: + # skip non-remappable items + continue + + # Calculate effective display category + var effective_display_category:String = \ + _get_effective_display_category(mapped_action, input_mapping) + + # if display category filter is set, only pick mappings + # in this category + if display_category.length() > 0 and effective_display_category != display_category: + continue + + var item = ConfigItem.new(a_context, action_mapping.action, index, input_mapping) + item_changed.connect(item._item_changed) + result.append(item) + + return result + + +static func _get_effective_display_category(action:GUIDEAction, input_mapping:GUIDEInputMapping) -> String: + var result:String = "" + if input_mapping.override_action_settings: + result = input_mapping.display_category + + if result.is_empty(): + result = action.display_category + + return result + + +static func _get_effective_display_name(action:GUIDEAction, input_mapping:GUIDEInputMapping) -> String: + var result:String = "" + if input_mapping.override_action_settings: + result = input_mapping.display_name + + if result.is_empty(): + result = action.display_name + + return result + +static func _is_effectively_remappable(action:GUIDEAction, input_mapping:GUIDEInputMapping) -> bool: + return action.is_remappable and ((not input_mapping.override_action_settings) or input_mapping.is_remappable) + + +static func _get_effective_value_type(action:GUIDEAction, input_mapping:GUIDEInputMapping) -> GUIDEAction.GUIDEActionValueType: + if input_mapping.override_action_settings and input_mapping.input != null: + return input_mapping.input._native_value_type() + + return action.action_value_type + + +## Returns a list of all collisions in all contexts when this new input would be applied to the config item. +func get_input_collisions(item:ConfigItem, input:GUIDEInput) -> Array[ConfigItem]: + if not _check_item(item): + return [] + var result:Array[ConfigItem] = [] + + if input == null: + # no item collides with absent input + return result + + # walk over all known contexts and find any mappings. + for context:GUIDEMappingContext in _mapping_contexts: + for action_mapping:GUIDEActionMapping in context.mappings: + for index:int in action_mapping.input_mappings.size(): + var action := action_mapping.action + if context == item.context and action == item.action and index == item.index: + # collisions with self are allowed + continue + + var input_mapping:GUIDEInputMapping = action_mapping.input_mappings[index] + var bound_input:GUIDEInput = input_mapping.input + # check if this is currently overridden + if _remapping_config._has(context, action, index): + bound_input = _remapping_config._get_bound_input_or_null(context, action, index) + + # We have a collision + if bound_input != null and bound_input.is_same_as(input): + var collision_item := ConfigItem.new(context, action, index, input_mapping) + item_changed.connect(collision_item._item_changed) + result.append(collision_item) + + return result + + +## Gets the input currently bound to the action in the given context. Can be null if the input +## is currently not bound. +func get_bound_input_or_null(item:ConfigItem) -> GUIDEInput: + if not _check_item(item): + return null + + # If the remapping config has a binding for this, this binding wins. + if _remapping_config._has(item.context, item.action, item.index): + return _remapping_config._get_bound_input_or_null(item.context, item.action, item.index) + + # otherwise return the default binding for this action in the context + for action_mapping:GUIDEActionMapping in item.context.mappings: + if action_mapping.action == item.action: + if action_mapping.input_mappings.size() > item.index: + return action_mapping.input_mappings[item.index].input + else: + push_error("Action mapping does not have an index of ", item.index , ".") + + return null + +## Sets the bound input to the new value for the given config item. Ignores collisions +## because collision resolution is highly game specific. Use get_input_collisions to find +## potential collisions and then resolve them in a way that suits the game. Note that +## bound input can be set to null, which deliberately unbinds the input. If you want +## to restore the defaults, call restore_default instead. +func set_bound_input(item:ConfigItem, input:GUIDEInput) -> void: + if not _check_item(item): + return + + # first remove any custom binding we have + _remapping_config._clear(item.context, item.action, item.index) + + # Now check if the input is the same as the default + var bound_input:GUIDEInput = get_bound_input_or_null(item) + + if bound_input == null and input == null: + item_changed.emit(item, input) + return # nothing to do + + if bound_input == null: + _remapping_config._bind(item.context, item.action, input, item.index) + item_changed.emit(item, input) + return + + if bound_input != null and input != null and bound_input.is_same_as(input): + item_changed.emit(item, input) + return # nothing to do + + _remapping_config._bind(item.context, item.action, input, item.index) + item_changed.emit(item, input) + + +## Returns the default binding for the given config item. +func get_default_input(item:ConfigItem) -> GUIDEInput: + if not _check_item(item): + return null + + for mapping:GUIDEActionMapping in item.context.mappings: + if mapping.action == item.action: + # _check_item verifies the index exists, so no need to check here. + return mapping.input_mappings[item.index].input + + return null + + +## Restores the default binding for the given config item. Note that this may +## introduce a conflict if other bindings have bound conflicting input. You can +## call get_default_input for the given item to get the default input and then +## call get_input_collisions for that to find out whether you would get a collision. +func restore_default_for(item:ConfigItem) -> void: + if not _check_item(item): + return + + _remapping_config._clear(item.context, item.action, item.index) + item_changed.emit(item, get_bound_input_or_null(item)) + + + +## Verifies that the given item is valid. +func _check_item(item:ConfigItem) -> bool: + if not _mapping_contexts.has(item.context): + push_error("Given context is not known to this mapper. Did you call initialize()?") + return false + + var action_found := false + var size_ok := false + for mapping in item.context.mappings: + if mapping.action == item.action: + action_found = true + if mapping.input_mappings.size() > item.index and item.index >= 0: + size_ok = true + break + + if not action_found: + push_error("Given action does not belong to the given context.") + return false + + if not size_ok: + push_error("Given index does not exist for the given action's input binding.") + + + if not item.action.is_remappable: + push_error("Given action is not remappable.") + return false + + return true + + +class ConfigItem: + ## Emitted when the input to this item has changed. + signal changed(input:GUIDEInput) + + var _input_mapping:GUIDEInputMapping + + ## The display category for this config item + var display_category:String: + get: return GUIDERemapper._get_effective_display_category(action, _input_mapping) + + ## The display name for this config item. + var display_name:String: + get: return GUIDERemapper._get_effective_display_name(action, _input_mapping) + + ## Whether this item is remappable. + var is_remappable:bool: + get: return GUIDERemapper._is_effectively_remappable(action, _input_mapping) + + ## The value type for this config item. + var value_type:GUIDEAction.GUIDEActionValueType: + get: return GUIDERemapper._get_effective_value_type(action, _input_mapping) + + var context:GUIDEMappingContext + var action:GUIDEAction + var index:int + + func _init(context:GUIDEMappingContext, action:GUIDEAction, index:int, input_mapping:GUIDEInputMapping): + self.context = context + self.action = action + self.index = index + _input_mapping = input_mapping + + ## Checks whether this config item is the same as some other + ## e.g. refers to the same input mapping. + func is_same_as(other:ConfigItem) -> bool: + return context == other.context and \ + action == other.action and \ + index == other.index + + func _item_changed(item:ConfigItem, input:GUIDEInput): + if item.is_same_as(self): + changed.emit(input) + diff --git a/addons/guide/remapping/guide_remapping_config.gd b/addons/guide/remapping/guide_remapping_config.gd new file mode 100644 index 0000000..7bd6453 --- /dev/null +++ b/addons/guide/remapping/guide_remapping_config.gd @@ -0,0 +1,85 @@ +@icon("res://addons/guide/guide_internal.svg") +## A remapping configuration. This only holds changes to the context mapping, +## so to get the full input map you need to apply this on top of one or more +## mapping contexts. The settings from this config take precedence over the +## settings from the mapping contexts. +class_name GUIDERemappingConfig +extends Resource + +## Dictionary with remapped inputs. Structure is: +## { +## mapping_context : { +## action : { +## index : bound input +## ... +## }, ... +## } +## The bound input can be NULL which means that this was deliberately unbound. +@export var remapped_inputs:Dictionary = {} + +## Dictionary for additional custom data to store (e.g. modifier settings, etc.) +## Note that this data is completely under application control and it's the responsibility +## of the application to ensure that this data is serializable and gets applied at +## the necessary point in time. +@export var custom_data:Dictionary = {} + +## Binds the given input to the given action. Index can be given to have +## alternative bindings for the same action. +func _bind(mapping_context:GUIDEMappingContext, action:GUIDEAction, input:GUIDEInput, index:int = 0) -> void: + if not remapped_inputs.has(mapping_context): + remapped_inputs[mapping_context] = {} + + if not remapped_inputs[mapping_context].has(action): + remapped_inputs[mapping_context][action] = {} + + remapped_inputs[mapping_context][action][index] = input + + +## Unbinds the given input from the given action. This is a deliberate unbind +## which means that the action should not be triggerable by the input anymore. It +## its not the same as _clear. +func _unbind(mapping_context:GUIDEMappingContext, action:GUIDEAction, index:int = 0) -> void: + _bind(mapping_context, action, null, index) + + +## Removes the given input action binding from this configuration. The action will +## now have the default input that it has in the mapping_context. This is not the +## same as _unbind. +func _clear(mapping_context:GUIDEMappingContext, action:GUIDEAction, index:int = 0) -> void: + if not remapped_inputs.has(mapping_context): + return + + if not remapped_inputs[mapping_context].has(action): + return + + remapped_inputs[mapping_context][action].erase(index) + + if remapped_inputs[mapping_context][action].is_empty(): + remapped_inputs[mapping_context].erase(action) + + if remapped_inputs[mapping_context].is_empty(): + remapped_inputs.erase(mapping_context) + + +## Returns the bound input for the given action name and index. Returns null +## if there is matching binding. +func _get_bound_input_or_null(mapping_context:GUIDEMappingContext, action:GUIDEAction, index:int = 0) -> GUIDEInput: + if not remapped_inputs.has(mapping_context): + return null + + if not remapped_inputs[mapping_context].has(action): + return null + + return remapped_inputs[mapping_context][action].get(index, null) + + +## Returns whether or not this mapping has a configuration for the given combination (even if the +## combination is set to null). +func _has(mapping_context:GUIDEMappingContext, action:GUIDEAction, index:int = 0) -> bool: + if not remapped_inputs.has(mapping_context): + return false + + if not remapped_inputs[mapping_context].has(action): + return false + + return remapped_inputs[mapping_context][action].has(index) diff --git a/addons/guide/triggers/guide_trigger.gd b/addons/guide/triggers/guide_trigger.gd new file mode 100644 index 0000000..d158ece --- /dev/null +++ b/addons/guide/triggers/guide_trigger.gd @@ -0,0 +1,65 @@ +@tool +@icon("res://addons/guide/triggers/guide_trigger.svg") +class_name GUIDETrigger +extends Resource + +enum GUIDETriggerState { + ## The trigger did not fire. + NONE, + ## The trigger's conditions are partially met + ONGOING, + ## The trigger has fired. + TRIGGERED +} + +enum GUIDETriggerType { + # If there are more than one explicit triggers at least one must trigger + # for the action to trigger. + EXPLICIT = 1, + # All implicit triggers must trigger for the action to trigger. + IMPLICIT = 2, + # All blocking triggers prevent the action from triggering. + BLOCKING = 3 +} + + +@export var actuation_threshold:float = 0.5 +var _last_value:Vector3 + +## Returns the trigger type of this trigger. +func _get_trigger_type() -> GUIDETriggerType: + return GUIDETriggerType.EXPLICIT + + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + return GUIDETriggerState.NONE + + +func _is_actuated(input:Vector3, value_type:GUIDEAction.GUIDEActionValueType) -> bool: + match value_type: + GUIDEAction.GUIDEActionValueType.AXIS_1D, GUIDEAction.GUIDEActionValueType.BOOL: + return _is_axis1d_actuated(input) + GUIDEAction.GUIDEActionValueType.AXIS_2D: + return _is_axis2d_actuated(input) + GUIDEAction.GUIDEActionValueType.AXIS_3D: + return _is_axis3d_actuated(input) + + return false + +## Checks if a 1D input is actuated. +func _is_axis1d_actuated(input:Vector3) -> bool: + return is_finite(input.x) and abs(input.x) > actuation_threshold + +## Checks if a 2D input is actuated. +func _is_axis2d_actuated(input:Vector3) -> bool: + return is_finite(input.x) and is_finite(input.y) and Vector2(input.x, input.y).length_squared() > actuation_threshold * actuation_threshold + +## Checks if a 3D input is actuated. +func _is_axis3d_actuated(input:Vector3) -> bool: + return input.is_finite() and input.length_squared() > actuation_threshold * actuation_threshold + +func _editor_name() -> String: + return "GUIDETrigger" + +func _editor_description() -> String: + return "" diff --git a/addons/guide/triggers/guide_trigger.svg b/addons/guide/triggers/guide_trigger.svg new file mode 100644 index 0000000..48f8822 --- /dev/null +++ b/addons/guide/triggers/guide_trigger.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/addons/guide/triggers/guide_trigger.svg.import b/addons/guide/triggers/guide_trigger.svg.import new file mode 100644 index 0000000..e63657a --- /dev/null +++ b/addons/guide/triggers/guide_trigger.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ca1eiagyinhl7" +path="res://.godot/imported/guide_trigger.svg-cd87acbd491929cf49a255f8481b0b63.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/triggers/guide_trigger.svg" +dest_files=["res://.godot/imported/guide_trigger.svg-cd87acbd491929cf49a255f8481b0b63.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=0.5 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/triggers/guide_trigger_chorded_action.gd b/addons/guide/triggers/guide_trigger_chorded_action.gd new file mode 100644 index 0000000..2b06f8c --- /dev/null +++ b/addons/guide/triggers/guide_trigger_chorded_action.gd @@ -0,0 +1,28 @@ +## Fires, when the given action is currently triggering. This trigger is implicit, +## so it will prevent the action from triggering even if other triggers are successful. +@tool +class_name GUIDETriggerChordedAction +extends GUIDETrigger + +@export var action:GUIDEAction + + +func _get_trigger_type() -> GUIDETriggerType: + return GUIDETriggerType.IMPLICIT + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + if action == null: + push_warning("Chorded trigger without action will never trigger.") + return GUIDETriggerState.NONE + + if action.is_triggered(): + return GUIDETriggerState.TRIGGERED + return GUIDETriggerState.NONE + + +func _editor_name() -> String: + return "Chorded Action" + +func _editor_description() -> String: + return "Fires, when the given action is currently triggering. This trigger is implicit,\n" + \ + "so it will prevent the action from triggering even if other triggers are successful." diff --git a/addons/guide/triggers/guide_trigger_combo.gd b/addons/guide/triggers/guide_trigger_combo.gd new file mode 100644 index 0000000..2464e65 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_combo.gd @@ -0,0 +1,117 @@ +@tool +class_name GUIDETriggerCombo +extends GUIDETrigger + +enum ActionEventType { + TRIGGERED = 1, + STARTED = 2, + ONGOING = 4, + CANCELLED = 8, + COMPLETED = 16 +} + +## If set to true, the combo trigger will print information +## about state changes to the debug log. +@export var enable_debug_print:bool = false +@export var steps:Array[GUIDETriggerComboStep] = [] +@export var cancellation_actions:Array[GUIDETriggerComboCancelAction] = [] + +var _current_step:int = -1 +var _remaining_time:float = 0 + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + if steps.is_empty(): + push_warning("Combo with no steps will never fire.") + return GUIDETriggerState.NONE + + # initial setup + if _current_step == -1: + for step in steps: + step._prepare() + for action in cancellation_actions: + action._prepare() + _reset() + + + var current_action := steps[_current_step].action + if current_action == null: + push_warning("Step ", _current_step , " has no action ", resource_path) + return GUIDETriggerState.NONE + + # check if any of our cancellation actions fired + for action in cancellation_actions: + # if the action is the current action we don't count its firing as cancellation + if action.action == current_action: + continue + + if action._has_fired: + if enable_debug_print: + print("Combo cancelled by action '", action.action._editor_name(), "'.") + _reset() + return GUIDETriggerState.NONE + + # check if any of the steps has fired out of order + for step in steps: + if step.action == current_action: + continue + + if step._has_fired: + if enable_debug_print: + print("Combo out of order step by action '", step.action._editor_name(), "'.") + _reset() + return GUIDETriggerState.NONE + + # check if we took too long (unless we're in the first step) + if _current_step > 0: + _remaining_time -= delta + if _remaining_time <= 0.0: + if enable_debug_print: + print("Step time for step ", _current_step , " exceeded.") + _reset() + return GUIDETriggerState.NONE + + # if the current action was fired, if so advance to the next + if steps[_current_step]._has_fired: + # reset this step, so it will not count as misfired next round + steps[_current_step]._has_fired = false + if _current_step + 1 >= steps.size(): + # we finished the combo + if enable_debug_print: + print("Combo fired.") + _reset() + return GUIDETriggerState.TRIGGERED + + # otherwise, pick the next step + _current_step += 1 + if enable_debug_print: + print("Combo advanced to step " , _current_step, ".") + _remaining_time = steps[_current_step].time_to_actuate + + # Reset all steps and cancellation actions to "not fired" in + # case they were triggered by this action. Otherwise a double-tap + # would immediately fire for both taps once the first is through + for step in steps: + step._has_fired = false + for action in cancellation_actions: + action._has_fired = false + + # and in any case we're still processing. + return GUIDETriggerState.ONGOING + + +func _reset(): + if enable_debug_print: + print("Combo reset.") + _current_step = 0 + _remaining_time = steps[0].time_to_actuate + for step in steps: + step._has_fired = false + for action in cancellation_actions: + action._has_fired = false + +func _editor_name() -> String: + return "Combo" + +func _editor_description() -> String: + return "Fires, when the input exceeds the actuation threshold." + diff --git a/addons/guide/triggers/guide_trigger_combo_cancel_action.gd b/addons/guide/triggers/guide_trigger_combo_cancel_action.gd new file mode 100644 index 0000000..10a0e83 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_combo_cancel_action.gd @@ -0,0 +1,27 @@ +@icon("res://addons/guide/guide_internal.svg") +class_name GUIDETriggerComboCancelAction +extends Resource + +@export var action:GUIDEAction +@export_flags("Triggered:1", "Started:2", "Ongoing:4", "Cancelled:8","Completed:16") +var completion_events:int = GUIDETriggerCombo.ActionEventType.TRIGGERED + +var _has_fired:bool = false + +func _prepare(): + if completion_events & GUIDETriggerCombo.ActionEventType.TRIGGERED: + action.triggered.connect(_fired) + if completion_events & GUIDETriggerCombo.ActionEventType.STARTED: + action.started.connect(_fired) + if completion_events & GUIDETriggerCombo.ActionEventType.ONGOING: + action.ongoing.connect(_fired) + if completion_events & GUIDETriggerCombo.ActionEventType.CANCELLED: + action.cancelled.connect(_fired) + if completion_events & GUIDETriggerCombo.ActionEventType.COMPLETED: + action.completed.connect(_fired) + _has_fired = false + + +func _fired(): + _has_fired = true + diff --git a/addons/guide/triggers/guide_trigger_combo_step.gd b/addons/guide/triggers/guide_trigger_combo_step.gd new file mode 100644 index 0000000..4e22bf7 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_combo_step.gd @@ -0,0 +1,29 @@ +@icon("res://addons/guide/guide_internal.svg") +class_name GUIDETriggerComboStep +extends Resource + +@export var action:GUIDEAction +@export_flags("Triggered:1", "Started:2", "Ongoing:4", "Cancelled:8","Completed:16") +var completion_events:int = GUIDETriggerCombo.ActionEventType.TRIGGERED +@export var time_to_actuate:float = 0.5 + + +var _has_fired:bool = false + +func _prepare(): + if completion_events & GUIDETriggerCombo.ActionEventType.TRIGGERED: + action.triggered.connect(_fired) + if completion_events & GUIDETriggerCombo.ActionEventType.STARTED: + action.started.connect(_fired) + if completion_events & GUIDETriggerCombo.ActionEventType.ONGOING: + action.ongoing.connect(_fired) + if completion_events & GUIDETriggerCombo.ActionEventType.CANCELLED: + action.cancelled.connect(_fired) + if completion_events & GUIDETriggerCombo.ActionEventType.COMPLETED: + action.completed.connect(_fired) + _has_fired = false + + +func _fired(): + _has_fired = true + diff --git a/addons/guide/triggers/guide_trigger_down.gd b/addons/guide/triggers/guide_trigger_down.gd new file mode 100644 index 0000000..5327d62 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_down.gd @@ -0,0 +1,20 @@ +## Fires, when the input exceeds the actuation threshold. This is +## the default trigger when no trigger is specified. +@tool +class_name GUIDETriggerDown +extends GUIDETrigger + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + # if the input is actuated, then the trigger is triggered. + if _is_actuated(input, value_type): + return GUIDETriggerState.TRIGGERED + # otherwise, the trigger is not triggered. + return GUIDETriggerState.NONE + + +func _editor_name() -> String: + return "Down" + +func _editor_description() -> String: + return "Fires, when the input exceeds the actuation threshold. This is\n" +\ + "the default trigger when no trigger is specified." diff --git a/addons/guide/triggers/guide_trigger_hold.gd b/addons/guide/triggers/guide_trigger_hold.gd new file mode 100644 index 0000000..8ad5bb2 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_hold.gd @@ -0,0 +1,43 @@ +@tool +## A trigger that activates when the input is held down for a certain amount of time. +class_name GUIDETriggerHold +extends GUIDETrigger + +## The time for how long the input must be held. +@export var hold_treshold:float = 1.0 +## If true, the trigger will only fire once until the input is released. Otherwise the trigger will fire every frame. +@export var is_one_shot:bool = false + +var _accumulated_time:float = 0 +var _did_shoot:bool = false + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + # if the input is actuated, accumulate time and check if the hold threshold has been reached + if _is_actuated(input, value_type): + _accumulated_time += delta + + if _accumulated_time >= hold_treshold: + # if the trigger is one shot and we already shot, then we will not trigger again. + if is_one_shot and _did_shoot: + return GUIDETriggerState.NONE + else: + # otherwise, we will just trigger. + _did_shoot = true + return GUIDETriggerState.TRIGGERED + else: + # if the hold threshold has not been reached, then the trigger is ongoing. + return GUIDETriggerState.ONGOING + else: + # if the input is not actuated, then the trigger is not triggered and we reset the accumulated time. + # and our one shot flag. + _accumulated_time = 0 + _did_shoot = false + return GUIDETriggerState.NONE + + +func _editor_name() -> String: + return "Hold" + +func _editor_description() -> String: + return "Fires, once the input has remained actuated for hold_threshold seconds.\n" + \ + "My fire once or repeatedly." diff --git a/addons/guide/triggers/guide_trigger_pressed.gd b/addons/guide/triggers/guide_trigger_pressed.gd new file mode 100644 index 0000000..97fd0e1 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_pressed.gd @@ -0,0 +1,22 @@ +@tool +## A trigger that activates when the input is pushed down. Will only emit a +## trigger event once. Holding the input will not trigger further events. +class_name GUIDETriggerPressed +extends GUIDETrigger + + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + if _is_actuated(input, value_type): + if not _is_actuated(_last_value, value_type): + return GUIDETriggerState.TRIGGERED + + return GUIDETriggerState.NONE + + +func _editor_name() -> String: + return "Pressed" + + +func _editor_description() -> String: + return "Fires once, when the input exceeds actuation threshold. Holding the input\n" + \ + "will not fire additional triggers." diff --git a/addons/guide/triggers/guide_trigger_pulse.gd b/addons/guide/triggers/guide_trigger_pulse.gd new file mode 100644 index 0000000..61ee88c --- /dev/null +++ b/addons/guide/triggers/guide_trigger_pulse.gd @@ -0,0 +1,86 @@ +@tool +## A trigger that activates when the input is pushed down and then repeatedly sends trigger events at a fixed interval. +## Note: the trigger will be either triggering or ongoing until the input is released. +## Note: at most one pulse will be emitted per frame. +class_name GUIDETriggerPulse +extends GUIDETrigger + +## If true, the trigger will trigger immediately when the input is actuated. Otherwise, the trigger will wait for the initial delay. +@export var trigger_on_start:bool = true +## The delay after the initial actuation before pulsing begins. +@export var initial_delay:float = 0.3: + set(value): + initial_delay = max(0, value) + +## The interval between pulses. Set to 0 to pulse every frame. +@export var pulse_interval:float = 0.1: + set(value): + pulse_interval = max(0, value) + +## Maximum number of pulses. If <= 0, the trigger will pulse indefinitely. +@export var max_pulses:int = 0 + +var _delay_until_next_pulse:float = 0 +var _emitted_pulses:int = 0 + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + if _is_actuated(input, value_type): + if not _is_actuated(_last_value, value_type): + # we went from "not actuated" to actuated, pulsing starts + _delay_until_next_pulse = initial_delay + if trigger_on_start: + return GUIDETriggerState.TRIGGERED + else: + return GUIDETriggerState.ONGOING + + # if we already are pulsing and have exceeded the maximum number of pulses, we will not pulse anymore. + if max_pulses > 0 and _emitted_pulses >= max_pulses: + return GUIDETriggerState.NONE + + # subtract the delta from the delay until the next pulse + _delay_until_next_pulse -= delta + + if _delay_until_next_pulse > 0: + # we are still waiting for the next pulse, nothing to do. + return GUIDETriggerState.ONGOING + + # now delta could be larger than our pulse, in which case we loose a few pulses. + # as we can pulse at most once per frame. + + # in case someone sets the pulse interval to 0, we will pulse every frame. + if is_equal_approx(pulse_interval, 0): + _delay_until_next_pulse = 0 + if max_pulses > 0: + _emitted_pulses += 1 + return GUIDETriggerState.TRIGGERED + + # Now add the delay until the next pulse + _delay_until_next_pulse += pulse_interval + + # If the interval is really small, we can potentially have skipped some pulses + if _delay_until_next_pulse <= 0: + # we have skipped some pulses + var skipped_pulses:int = int(-_delay_until_next_pulse / pulse_interval) + _delay_until_next_pulse += skipped_pulses * pulse_interval + if max_pulses > 0: + _emitted_pulses += skipped_pulses + if _emitted_pulses >= max_pulses: + return GUIDETriggerState.NONE + + # Record a pulse and return triggered + if max_pulses > 0: + _emitted_pulses += 1 + return GUIDETriggerState.TRIGGERED + + # if the input is not actuated, then the trigger is not triggered. + _emitted_pulses = 0 + _delay_until_next_pulse = 0 + return GUIDETriggerState.NONE + + +func _editor_name() -> String: + return "Pulse" + + +func _editor_description() -> String: + return "Fires at an interval while the input is actuated." diff --git a/addons/guide/triggers/guide_trigger_released.gd b/addons/guide/triggers/guide_trigger_released.gd new file mode 100644 index 0000000..d1509e9 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_released.gd @@ -0,0 +1,21 @@ +@tool +## A trigger that activates when the input is released down. Will only emit a +## trigger event once. +class_name GUIDETriggerReleased +extends GUIDETrigger + + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + if not _is_actuated(input, value_type): + if _is_actuated(_last_value, value_type): + return GUIDETriggerState.TRIGGERED + + return GUIDETriggerState.NONE + + +func _editor_name() -> String: + return "Released" + + +func _editor_description() -> String: + return "Fires once, when the input goes from actuated to not actuated. The opposite of the Pressed trigger." diff --git a/addons/guide/triggers/guide_trigger_stability.gd b/addons/guide/triggers/guide_trigger_stability.gd new file mode 100644 index 0000000..cfe01f9 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_stability.gd @@ -0,0 +1,72 @@ +@tool +## Triggers depending on whether the input changes while actuated. This trigger is +## is implicit, so it must succeed for all other triggers to succeed. +class_name GUIDETriggerStability +extends GUIDETrigger + +enum TriggerWhen { + ## Input must be stable + INPUT_IS_STABLE, + ## Input must change + INPUT_CHANGES +} + + +## The maximum amount that the input can change after actuation before it is +## considered "changed". +@export var max_deviation:float = 1 + +## When should the trigger trigger? +@export var trigger_when:TriggerWhen = TriggerWhen.INPUT_IS_STABLE + + +var _initial_value:Vector3 +var _deviated:bool = false + + +func _get_trigger_type() -> GUIDETriggerType: + return GUIDETriggerType.IMPLICIT + + +func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + if _is_actuated(input, value_type): + if _deviated: + if trigger_when == TriggerWhen.INPUT_IS_STABLE: + return GUIDETriggerState.NONE + return GUIDETriggerState.TRIGGERED + + + if not _is_actuated(_last_value, value_type): + # we went from "not actuated" to actuated, start + _initial_value = input + if trigger_when == TriggerWhen.INPUT_IS_STABLE: + return GUIDETriggerState.TRIGGERED + else: + return GUIDETriggerState.ONGOING + + # calculate how far the input is from the initial value + if _initial_value.distance_squared_to(input) > (max_deviation * max_deviation): + _deviated = true + if trigger_when == TriggerWhen.INPUT_IS_STABLE: + return GUIDETriggerState.NONE + return GUIDETriggerState.TRIGGERED + + if trigger_when == TriggerWhen.INPUT_IS_STABLE: + return GUIDETriggerState.TRIGGERED + + return GUIDETriggerState.ONGOING + + # if the input is not actuated + _deviated = false + return GUIDETriggerState.NONE + + + + +func _editor_name() -> String: + return "Stability" + + +func _editor_description() -> String: + return "Triggers depending on whether the input changes while actuated. This trigger\n" +\ + "is implicit, so it must succeed for all other triggers to succeed." diff --git a/addons/guide/triggers/guide_trigger_tap.gd b/addons/guide/triggers/guide_trigger_tap.gd new file mode 100644 index 0000000..a0d0c26 --- /dev/null +++ b/addons/guide/triggers/guide_trigger_tap.gd @@ -0,0 +1,48 @@ +@tool +## A trigger that activates when the input is tapped and released before the time threshold is reached. +class_name GUIDETriggerTap +extends GUIDETrigger + +## The time threshold for the tap to be considered a tap. +@export var tap_threshold: float = 0.2 + +var _accumulated_time: float = 0 + + +func _update_state(input: Vector3, delta: float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState: + if _is_actuated(input, value_type): + # if the input was actuated before, and the tap threshold has been exceeded, the trigger is locked down + # until the input is released and we can exit out early + if _is_actuated(_last_value, value_type) and _accumulated_time > tap_threshold: + return GUIDETriggerState.NONE + + # accumulate time + _accumulated_time += delta + + if _accumulated_time < tap_threshold: + return GUIDETriggerState.ONGOING + else: + # we have exceeded the tap threshold, so the tap is not triggered. + return GUIDETriggerState.NONE + + else: # not actuated right now + # if the input was actuated before... + if _is_actuated(_last_value, value_type): + # ... and the accumulated time is less than the threshold, then the tap is triggered. + if _accumulated_time < tap_threshold: + _accumulated_time = 0 + return GUIDETriggerState.TRIGGERED + + # Otherwise, the tap is not triggered, but we reset the accumulated time + # so the trigger is now again ready to be triggered. + _accumulated_time = 0 + + # in either case, the trigger is not triggered. + return GUIDETriggerState.NONE + +func _editor_name() -> String: + return "Tap" + + +func _editor_description() -> String: + return "Fires when the input is actuated and released within the given timeframe." diff --git a/addons/guide/ui/guide_icon_renderer.gd b/addons/guide/ui/guide_icon_renderer.gd new file mode 100644 index 0000000..558303e --- /dev/null +++ b/addons/guide/ui/guide_icon_renderer.gd @@ -0,0 +1,30 @@ +## Base class for icon renderers. Note that all icon renderers must be tool +## scripts. +@tool +class_name GUIDEIconRenderer +extends Control + +## The priority of this icon renderer. Built-in renderers use priority 0. Built-in +## fallback renderer uses priority 100. The smaller the number the higher the priority. +@export var priority:int = 0 + +## Whether or not this renderer can render an icon for this input. +func supports(input:GUIDEInput) -> bool: + return false + +## Set up the scene so that the given input can be rendered. This will +## only be called for input where `supports` has returned true. +func render(input:GUIDEInput) -> void: + pass + + +## A cache key for the given input. This should be unique for this renderer +## and the given input. The same input should yield the same cache key for +## each renderer. +func cache_key(input:GUIDEInput) -> String: + push_error("Custom renderers must override the cache_key function to ensure proper caching.") + return "i-forgot-the-cache-key" + +func _ready(): + process_mode = Node.PROCESS_MODE_ALWAYS + diff --git a/addons/guide/ui/guide_input_formatter.gd b/addons/guide/ui/guide_input_formatter.gd new file mode 100644 index 0000000..1fd670c --- /dev/null +++ b/addons/guide/ui/guide_input_formatter.gd @@ -0,0 +1,358 @@ +@tool +## Helper class for formatting GUIDE input for the UI. +class_name GUIDEInputFormatter + +const IconMaker = preload("icon_maker/icon_maker.gd") +const KeyRenderer = preload("renderers/keyboard/key_renderer.tscn") +const MouseRenderer = preload("renderers/mouse/mouse_renderer.tscn") +const TouchRenderer = preload("renderers/touch/touch_renderer.tscn") +const JoyRenderer = preload("renderers/joy/joy_renderer.tscn") +const XboxRenderer = preload("renderers/controllers/xbox/xbox_controller_renderer.tscn") +const PlayStationRenderer = preload("renderers/controllers/playstation/playstation_controller_renderer.tscn") +const SwitchRenderer = preload("renderers/controllers/switch/switch_controller_renderer.tscn") +const ActionRenderer = preload("renderers/misc/action_renderer.tscn") +const FallbackRenderer = preload("renderers/misc/fallback_renderer.tscn") +const DefaultTextProvider = preload("text_providers/default_text_provider.gd") +const XboxTextProvider = preload("text_providers/controllers/xbox/xbox_controller_text_provider.gd") +const PlayStationTextProvider = preload("text_providers/controllers/playstation/playstation_controller_text_provider.gd") +const SwitchTextProvider = preload("text_providers/controllers/switch/switch_controller_text_provider.gd") + +# These are shared across all instances +static var _icon_maker:IconMaker +static var _icon_renderers:Array[GUIDEIconRenderer] = [] +static var _text_providers:Array[GUIDETextProvider] = [] +static var _is_ready:bool = false + +## Separator to separate mixed input. +static var mixed_input_separator:String = ", " +## Separator to separate chorded input. +static var chorded_input_separator:String = " + " +## Separator to separate combo input. +static var combo_input_separator:String = " > " + +# These are per-instance +var _action_resolver:Callable +var _icon_size:int + +static func _ensure_readiness(): + if _is_ready: + return + + # reconnect to an icon maker that might be there + var root = Engine.get_main_loop().root + for child in root.get_children(): + if child is IconMaker: + _icon_maker = child + + if _icon_maker == null: + _icon_maker = preload("icon_maker/icon_maker.tscn").instantiate() + root.add_child.call_deferred(_icon_maker) + + add_icon_renderer(KeyRenderer.instantiate()) + add_icon_renderer(MouseRenderer.instantiate()) + add_icon_renderer(TouchRenderer.instantiate()) + add_icon_renderer(ActionRenderer.instantiate()) + add_icon_renderer(JoyRenderer.instantiate()) + add_icon_renderer(XboxRenderer.instantiate()) + add_icon_renderer(PlayStationRenderer.instantiate()) + add_icon_renderer(SwitchRenderer.instantiate()) + add_icon_renderer(FallbackRenderer.instantiate()) + + add_text_provider(DefaultTextProvider.new()) + add_text_provider(XboxTextProvider.new()) + add_text_provider(PlayStationTextProvider.new()) + add_text_provider(SwitchTextProvider.new()) + + _is_ready = true + + +## This will clean up the rendering infrastructure used for generating +## icons. Note that in a normal game you will have no need to call this +## as the infrastructure is needed throughout the run of your game. +## It might be useful in tests though, to get rid of spurious warnings +## about orphaned nodes. +static func cleanup(): + _is_ready = false + + # free all the nodes to avoid memory leaks + for renderer in _icon_renderers: + renderer.queue_free() + + _icon_renderers.clear() + + _text_providers.clear() + if is_instance_valid(_icon_maker): + _icon_maker.queue_free() + + +func _init(icon_size:int = 32, resolver:Callable = func(action) -> GUIDEActionMapping: return null ): + _icon_size = icon_size + _action_resolver = resolver + + +## Adds an icon renderer for rendering icons. +static func add_icon_renderer(renderer:GUIDEIconRenderer) -> void: + _icon_renderers.append(renderer) + _icon_renderers.sort_custom(func(r1, r2): return r1.priority < r2.priority) + +## Removes an icon renderer. +static func remove_icon_renderer(renderer:GUIDEIconRenderer) -> void: + _icon_renderers.erase(renderer) + +## Adds a text provider for rendering text. +static func add_text_provider(provider:GUIDETextProvider) -> void: + _text_providers.append(provider) + _text_providers.sort_custom(func(r1, r2): return r1.priority < r2.priority) + + +## Removes a text provider +static func remove_text_provider(provider:GUIDETextProvider) -> void: + _text_providers.erase(provider) + + +## Returns an input formatter that can format actions using the currently active inputs. +static func for_active_contexts(icon_size:int = 32) -> GUIDEInputFormatter: + var resolver = func(action:GUIDEAction) -> GUIDEActionMapping: + for mapping in GUIDE._active_action_mappings: + if mapping.action == action: + return mapping + return null + return GUIDEInputFormatter.new(icon_size, resolver) + + +## Returns an input formatter that can format actions using the given context. +static func for_context(context:GUIDEMappingContext, icon_size:int = 32) -> GUIDEInputFormatter: + var resolver:Callable = func(action:GUIDEAction) -> GUIDEActionMapping: + for mapping in context.mappings: + if mapping.action == action: + return mapping + return null + + return GUIDEInputFormatter.new(icon_size, resolver) + + +## Formats the action input as richtext with icons suitable for a RichTextLabel. This function +## is async as icons may need to be rendered in the background which can take a few frames, so +## you will need to await on it. +func action_as_richtext_async(action:GUIDEAction) -> String: + return await _materialized_as_richtext_async(_materialize_action_input(action)) + + +## Formats the action input as plain text which can be used in any UI component. This is a bit +## more light-weight than formatting as icons and returns immediately. +func action_as_text(action:GUIDEAction) -> String: + return _materialized_as_text(_materialize_action_input(action)) + +## Formats the input as richtext with icons suitable for a RichTextLabel. This function +## is async as icons may need to be rendered in the background which can take a few frames, so +## you will need to await on it. +func input_as_richtext_async(input:GUIDEInput, materialize_actions:bool = true) -> String: + return await _materialized_as_richtext_async(_materialize_input(input, materialize_actions)) + + +## Formats the input as plain text which can be used in any UI component. This is a bit +## more light-weight than formatting as icons and returns immediately. +func input_as_text(input:GUIDEInput, materialize_actions:bool = true) -> String: + return _materialized_as_text(_materialize_input(input, materialize_actions)) + + +## Renders materialized input as text. +func _materialized_as_text(input:MaterializedInput) -> String: + _ensure_readiness() + if input is MaterializedSimpleInput: + var text:String = "" + for provider in _text_providers: + if provider.supports(input.input): + text = provider.get_text(input.input) + # first provider wins + break + if text == "": + pass + ## push_warning("No formatter found for input ", input) + return text + + var separator = _separator_for_input(input) + if separator == "" or input.parts.is_empty(): + return "" + + var parts:Array[String] = [] + for part in input.parts: + parts.append(_materialized_as_text(part)) + + return separator.join(parts) + +## Renders materialized input as rich text. +func _materialized_as_richtext_async(input:MaterializedInput) -> String: + _ensure_readiness() + if input is MaterializedSimpleInput: + var icon:Texture2D = null + for renderer in _icon_renderers: + if renderer.supports(input.input): + icon = await _icon_maker.make_icon(input.input, renderer, _icon_size) + # first renderer wins + break + if icon == null: + push_warning("No renderer found for input ", input) + return "" + + return "[img]%s[/img]" % [icon.resource_path] + + + var separator = _separator_for_input(input) + if separator == "" or input.parts.is_empty(): + return "" + + var parts:Array[String] = [] + for part in input.parts: + parts.append(await _materialized_as_richtext_async(part)) + + return separator.join(parts) + + +func _separator_for_input(input:MaterializedInput) -> String: + if input is MaterializedMixedInput: + return mixed_input_separator + elif input is MaterializedComboInput: + return combo_input_separator + elif input is MaterializedChordedInput: + return chorded_input_separator + + push_error("Unknown materialized input type") + return "" + + +## Materializes action input. +func _materialize_action_input(action:GUIDEAction) -> MaterializedInput: + var result := MaterializedMixedInput.new() + if action == null: + push_warning("Trying to get inputs for a null action.") + return result + + # get the mapping for this action + var mapping:GUIDEActionMapping = _action_resolver.call(action) + + # if we have no mapping, well that's it, return an empty mixed input + if mapping == null: + return result + + # collect input mappings + for input_mapping in mapping.input_mappings: + var chorded_actions:Array[MaterializedInput] = [] + var combos:Array[MaterializedInput] = [] + + for trigger in input_mapping.triggers: + # if we have a combo trigger, materialize its input. + if trigger is GUIDETriggerCombo: + var combo := MaterializedComboInput.new() + for step:GUIDETriggerComboStep in trigger.steps: + combo.parts.append(_materialize_action_input(step.action)) + combos.append(combo) + + # if we have a chorded action, materialize its input + if trigger is GUIDETriggerChordedAction: + chorded_actions.append(_materialize_action_input(trigger.action)) + + if not chorded_actions.is_empty(): + # if we have chorded action then the whole mapping is chorded. + var chord := MaterializedChordedInput.new() + for chorded_action in chorded_actions: + chord.parts.append(chorded_action) + for combo in combos: + chord.parts.append(combo) + if combos.is_empty(): + if input_mapping.input != null: + chord.parts.append(_materialize_input(input_mapping.input)) + result.parts.append(chord) + else: + for combo in combos: + result.parts.append(combo) + if combos.is_empty(): + if input_mapping.input != null: + result.parts.append(_materialize_input(input_mapping.input)) + return result + +## Materializes direct input. +func _materialize_input(input:GUIDEInput, materialize_actions:bool = true) -> MaterializedInput: + if input == null: + push_warning("Trying to materialize a null input.") + return MaterializedMixedInput.new() + + # if its an action input, get its parts + if input is GUIDEInputAction: + if materialize_actions: + return _materialize_action_input(input.action) + else: + return MaterializedSimpleInput.new(input) + + # if its a key input, split out the modifiers + if input is GUIDEInputKey: + var chord := MaterializedChordedInput.new() + if input.control: + var ctrl = GUIDEInputKey.new() + ctrl.key = KEY_CTRL + chord.parts.append(MaterializedSimpleInput.new(ctrl)) + if input.alt: + var alt = GUIDEInputKey.new() + alt.key = KEY_ALT + chord.parts.append(MaterializedSimpleInput.new(alt)) + if input.shift: + var shift = GUIDEInputKey.new() + shift.key = KEY_SHIFT + chord.parts.append(MaterializedSimpleInput.new(shift)) + if input.meta: + var meta = GUIDEInputKey.new() + meta.key = KEY_META + chord.parts.append(MaterializedSimpleInput.new(meta)) + + # got no modifiers? + if chord.parts.is_empty(): + return MaterializedSimpleInput.new(input) + + chord.parts.append(MaterializedSimpleInput.new(input)) + return chord + + # everything else is just a simple input + return MaterializedSimpleInput.new(input) + +class MaterializedInput: + pass + +class MaterializedSimpleInput: + extends MaterializedInput + var input:GUIDEInput + + func _init(input:GUIDEInput): + self.input = input + +class MaterializedMixedInput: + extends MaterializedInput + var parts:Array[MaterializedInput] = [] + +class MaterializedChordedInput: + extends MaterializedInput + var parts:Array[MaterializedInput] = [] + +class MaterializedComboInput: + extends MaterializedInput + var parts:Array[MaterializedInput] = [] + + +## Returns the name of the associated joystick/pad of the given input. +## If the input is no joy input or the device name cannot be determined +## returns an empty string. +static func _joy_name_for_input(input:GUIDEInput) -> String: + if not input is GUIDEInputJoyBase: + return "" + + var joypads:Array[int] = Input.get_connected_joypads() + var joy_index = input.joy_index + if joy_index < 0: + # pick the first one + joy_index = 0 + + # We don't have such a controller, so bail out. + if joypads.size() <= joy_index: + return "" + + var id = joypads[joy_index] + return Input.get_joy_name(id) diff --git a/addons/guide/ui/guide_text_provider.gd b/addons/guide/ui/guide_text_provider.gd new file mode 100644 index 0000000..2f84075 --- /dev/null +++ b/addons/guide/ui/guide_text_provider.gd @@ -0,0 +1,22 @@ +## Base class for text providers. A text provider provides a textual representation +## of an input which is displayed to the user. +## scripts. +@tool +class_name GUIDETextProvider + +## The priority of this text provider. The built-in text provider uses priority 0. +## The smaller the number the higher the priority. +@export var priority:int = 0 + +## Whether or not this provider can provide a text for this input. +func supports(input:GUIDEInput) -> bool: + return false + +## Provides the text for the given input. Will only be called when the +## input is supported by this text provider. Note that for key input +## this is not supposed to look at the modifiers. This function will +## be called separately for each modifier. +func get_text(input:GUIDEInput) -> String: + return "not implemented" + + diff --git a/addons/guide/ui/icon_maker/icon_maker.gd b/addons/guide/ui/icon_maker/icon_maker.gd new file mode 100644 index 0000000..1a03a0d --- /dev/null +++ b/addons/guide/ui/icon_maker/icon_maker.gd @@ -0,0 +1,103 @@ +@tool +extends Node + +const CACHE_DIR:String = "user://_guide_cache" + +@onready var _sub_viewport:SubViewport = %SubViewport +@onready var _root:Node2D = %Root +@onready var _scene_holder = %SceneHolder + +var _pending_requests:Array[Job] = [] +var _current_request:Job = null +var _fetch_image:bool = false + +func _ready(): + # keep working when game is paused + process_mode = Node.PROCESS_MODE_ALWAYS + # don't needlessly eat performance + if _pending_requests.is_empty(): + set_process(false) + + +func clear_cache(): + var files = DirAccess.get_files_at(CACHE_DIR) + for file in files: + DirAccess.remove_absolute(CACHE_DIR + "/" + file) + +## Makes an icon for the given input and returns a Texture2D with the icon. Icons +## are cached on disk so subsequent calls for the same input will be faster. +func make_icon(input:GUIDEInput, renderer:GUIDEIconRenderer, height_px:int) -> Texture2D: + DirAccess.make_dir_recursive_absolute(CACHE_DIR) + var cache_key = (str(height_px) + renderer.cache_key(input)).sha256_text() + var cache_path = "user://_guide_cache/" + cache_key + ".res" + if ResourceLoader.exists(cache_path): + return ResourceLoader.load(cache_path, "Texture2D") + + var job = Job.new() + job.height = height_px + job.input = input + job.renderer = renderer + _pending_requests.append(job) + set_process(true) + + await job.done + + var image_texture = ImageTexture.create_from_image(job.result) + ResourceSaver.save(image_texture, cache_path) + image_texture.take_over_path(cache_path) + + return image_texture + + + +func _process(delta): + if _current_request == null and _pending_requests.is_empty(): + # nothing more to do.. + set_process(false) + return + + # nothing in progress, so pick the next request + if _current_request == null: + _current_request = _pending_requests.pop_front() + var renderer = _current_request.renderer + _root.add_child(renderer) + + renderer.render(_current_request.input) + await get_tree().process_frame + + var actual_size = renderer.get_rect().size + var scale = float(_current_request.height) / float(actual_size.y) + _root.scale = Vector2.ONE * scale + _sub_viewport.size = actual_size * scale + + _sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS + + # give the renderer some time to update itself. 3 frames seem + # to work nicely and keep things speedy. + await get_tree().process_frame + await get_tree().process_frame + await get_tree().process_frame + + _fetch_image = true + return + + # fetch the image after the renderer is done + if _fetch_image: + # we're done. make a copy of the viewport texture + var image:Image = _scene_holder.texture.get_image() + _current_request.result = image + _current_request.done.emit() + _current_request = null + # remove the renderer + _root.remove_child(_root.get_child(0)) + _sub_viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED + _fetch_image = false + +class Job: + signal done() + var height:int + var input:GUIDEInput + var renderer:GUIDEIconRenderer + var result:Image + + diff --git a/addons/guide/ui/icon_maker/icon_maker.tscn b/addons/guide/ui/icon_maker/icon_maker.tscn new file mode 100644 index 0000000..662d2ce --- /dev/null +++ b/addons/guide/ui/icon_maker/icon_maker.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=3 format=3 uid="uid://8thurteeibtu"] + +[ext_resource type="Script" path="res://addons/guide/ui/icon_maker/icon_maker.gd" id="1_hdbjk"] + +[sub_resource type="ViewportTexture" id="ViewportTexture_kra7t"] +viewport_path = NodePath("SubViewport") + +[node name="GUIDEIconMaker" type="Node2D"] +script = ExtResource("1_hdbjk") + +[node name="SubViewport" type="SubViewport" parent="."] +unique_name_in_owner = true +transparent_bg = true +gui_disable_input = true +gui_snap_controls_to_pixels = false + +[node name="Root" type="Node2D" parent="SubViewport"] +unique_name_in_owner = true +scale = Vector2(0.1, 0.1) + +[node name="SceneHolder" type="Sprite2D" parent="."] +unique_name_in_owner = true +visible = false +texture = SubResource("ViewportTexture_kra7t") diff --git a/addons/guide/ui/renderers/controllers/controller_renderer.gd b/addons/guide/ui/renderers/controllers/controller_renderer.gd new file mode 100644 index 0000000..96b6fdc --- /dev/null +++ b/addons/guide/ui/renderers/controllers/controller_renderer.gd @@ -0,0 +1,171 @@ +@tool +extends GUIDEIconRenderer + +@export var controller_name_matches:Array[String] = [] +@export var a_button:Texture2D +@export var b_button:Texture2D +@export var x_button:Texture2D +@export var y_button:Texture2D +@export var left_stick:Texture2D +@export var left_stick_click:Texture2D +@export var right_stick:Texture2D +@export var right_stick_click:Texture2D +@export var left_bumper:Texture2D +@export var right_bumper:Texture2D +@export var left_trigger:Texture2D +@export var right_trigger:Texture2D +@export var dpad_up:Texture2D +@export var dpad_left:Texture2D +@export var dpad_right:Texture2D +@export var dpad_down:Texture2D +@export var start:Texture2D +@export var misc1:Texture2D +@export var back:Texture2D + + +@onready var _a_button:TextureRect = %AButton +@onready var _b_button:TextureRect = %BButton +@onready var _x_button:TextureRect = %XButton +@onready var _y_button:TextureRect = %YButton +@onready var _left_stick:TextureRect = %LeftStick +@onready var _left_stick_click:TextureRect = %LeftStickClick +@onready var _right_stick:TextureRect = %RightStick +@onready var _right_stick_click:TextureRect = %RightStickClick +@onready var _left_bumper:Control = %LeftBumper +@onready var _right_bumper:Control = %RightBumper +@onready var _left_trigger:Control = %LeftTrigger +@onready var _right_trigger:TextureRect = %RightTrigger +@onready var _dpad_up:TextureRect = %DpadUp +@onready var _dpad_left:TextureRect = %DpadLeft +@onready var _dpad_right:TextureRect = %DpadRight +@onready var _dpad_down:TextureRect = %DpadDown +@onready var _start:TextureRect = %Start +@onready var _misc1:TextureRect = %Misc1 +@onready var _back:TextureRect = %Back +@onready var _left_right:Control = %LeftRight +@onready var _up_down:Control = %UpDown +@onready var _controls:Control = %Controls +@onready var _directions:Control = %Directions + + +func _ready(): + super() + _a_button.texture = a_button + _b_button.texture = b_button + _x_button.texture = x_button + _y_button.texture = y_button + _left_stick.texture = left_stick + _left_stick_click.texture = left_stick_click + _right_stick.texture = right_stick + _right_stick_click.texture = right_stick_click + _left_bumper.texture = left_bumper + _right_bumper.texture = right_bumper + _left_trigger.texture = left_trigger + _right_trigger.texture = right_trigger + _dpad_up.texture = dpad_up + _dpad_left.texture = dpad_left + _dpad_right.texture = dpad_right + _dpad_down.texture = dpad_down + _start.texture = start + _misc1.texture = misc1 + _back.texture = back + +func supports(input:GUIDEInput) -> bool: + var joy_name = GUIDEInputFormatter._joy_name_for_input(input) + if joy_name == "": + return false + + # Look if the controller name matches one of the supported ones + var haystack = joy_name.to_lower() + for needle in controller_name_matches: + if haystack.contains(needle.to_lower()): + return true + + return false + +func render(input:GUIDEInput) -> void: + for control in _controls.get_children(): + control.visible = false + for direction in _directions.get_children(): + direction.visible = false + _directions.visible = false + + + if input is GUIDEInputJoyAxis1D: + match input.axis: + JOY_AXIS_LEFT_X: + _left_stick.visible = true + _show_left_right() + JOY_AXIS_LEFT_Y: + _left_stick.visible = true + _show_up_down() + JOY_AXIS_RIGHT_X: + _right_stick.visible = true + _show_left_right() + JOY_AXIS_RIGHT_Y: + _right_stick.visible = true + _show_up_down() + JOY_AXIS_TRIGGER_LEFT: + _left_trigger.visible = true + JOY_AXIS_TRIGGER_RIGHT: + _right_trigger.visible = true + + if input is GUIDEInputJoyAxis2D: + # We assume that there is no input mixing horizontal and vertical + # from different sticks into a 2D axis as this would confuse the + # players. + match input.x: + JOY_AXIS_LEFT_X, JOY_AXIS_LEFT_Y: + _left_stick.visible = true + JOY_AXIS_RIGHT_X, JOY_AXIS_RIGHT_Y: + _right_stick.visible = true + + if input is GUIDEInputJoyButton: + match input.button: + JOY_BUTTON_A: + _a_button.visible = true + JOY_BUTTON_B: + _b_button.visible = true + JOY_BUTTON_X: + _x_button.visible = true + JOY_BUTTON_Y: + _y_button.visible = true + JOY_BUTTON_DPAD_LEFT: + _dpad_left.visible = true + JOY_BUTTON_DPAD_RIGHT: + _dpad_right.visible = true + JOY_BUTTON_DPAD_UP: + _dpad_up.visible = true + JOY_BUTTON_DPAD_DOWN: + _dpad_down.visible = true + JOY_BUTTON_LEFT_SHOULDER: + _left_bumper.visible = true + JOY_BUTTON_RIGHT_SHOULDER: + _right_bumper.visible = true + JOY_BUTTON_LEFT_STICK: + _left_stick_click.visible = true + JOY_BUTTON_RIGHT_STICK: + _right_stick_click.visible = true + JOY_BUTTON_RIGHT_STICK: + _right_stick_click.visible = true + JOY_BUTTON_START: + _start.visible = true + JOY_BUTTON_BACK: + _back.visible = true + JOY_BUTTON_MISC1: + _misc1.visible = true + + call("queue_sort") + + +func _show_left_right(): + _directions.visible = true + _left_right.visible = true + +func _show_up_down(): + _directions.visible = true + _up_down.visible = true + + +func cache_key(input:GUIDEInput) -> String: + return "7581f483-bc68-411f-98ad-dc246fd2593a" + input.to_string() + GUIDEInputFormatter._joy_name_for_input(input) diff --git a/addons/guide/ui/renderers/controllers/controller_renderer.tscn b/addons/guide/ui/renderers/controllers/controller_renderer.tscn new file mode 100644 index 0000000..9ab0538 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/controller_renderer.tscn @@ -0,0 +1,135 @@ +[gd_scene load_steps=4 format=3 uid="uid://bsaylcb5ixjxk"] + +[ext_resource type="Script" path="res://addons/guide/ui/renderers/controllers/controller_renderer.gd" id="1_yt13e"] +[ext_resource type="Texture2D" uid="uid://bmgxqbypegjxh" path="res://addons/guide/ui/renderers/textures/arrow_horizontal.svg" id="2_nv2ob"] +[ext_resource type="Texture2D" uid="uid://bu5nlug6uf03w" path="res://addons/guide/ui/renderers/textures/arrow_vertical.svg" id="3_ejti1"] + +[node name="ControllerRenderer" type="MarginContainer"] +offset_right = 100.0 +offset_bottom = 100.0 +size_flags_horizontal = 0 +script = ExtResource("1_yt13e") +priority = -1 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 + +[node name="Controls" type="MarginContainer" parent="HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(100, 100) +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="AButton" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="BButton" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="XButton" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="YButton" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="LeftStick" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="LeftStickClick" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="RightStick" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="RightStickClick" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="LeftBumper" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="RightBumper" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="LeftTrigger" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="RightTrigger" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="DpadUp" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="DpadLeft" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="DpadRight" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="DpadDown" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="Start" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="Misc1" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="Back" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="Directions" type="MarginContainer" parent="HBoxContainer"] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(100, 100) +layout_mode = 2 + +[node name="LeftRight" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("2_nv2ob") +stretch_mode = 5 + +[node name="UpDown" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("3_ejti1") +stretch_mode = 5 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Circle.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Circle.png new file mode 100644 index 0000000..05a89a9 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Circle.png differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Circle.png.import similarity index 63% rename from examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png.import rename to addons/guide/ui/renderers/controllers/playstation/icons/PS5_Circle.png.import index 835818b..9aa8906 100644 --- a/examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png.import +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Circle.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://bobwi3r6aiiqg" -path="res://.godot/imported/tex_metal_corner_inner.png-cdfd7b81c523bc5bb5c7863d7307007e.ctex" +uid="uid://civpcnwgbu5ky" +path="res://.godot/imported/PS5_Circle.png-991ec3d8ff387e8a1997f29928333c68.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png" -dest_files=["res://.godot/imported/tex_metal_corner_inner.png-cdfd7b81c523bc5bb5c7863d7307007e.ctex"] +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Circle.png" +dest_files=["res://.godot/imported/PS5_Circle.png-991ec3d8ff387e8a1997f29928333c68.ctex"] [params] diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Cross.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Cross.png new file mode 100644 index 0000000..395a898 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Cross.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Cross.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Cross.png.import new file mode 100644 index 0000000..f0a694d --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Cross.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfy1rx4d4wjdh" +path="res://.godot/imported/PS5_Cross.png-94e7143faf483eb3d6ca6505fc615cd3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Cross.png" +dest_files=["res://.godot/imported/PS5_Cross.png-94e7143faf483eb3d6ca6505fc615cd3.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad.png new file mode 100644 index 0000000..49e6405 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad.png differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_fill.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad.png.import similarity index 65% rename from examples/sharp_corner_tapering/assets/tex_metal_fill.png.import rename to addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad.png.import index 2b1eb9c..ed99363 100644 --- a/examples/sharp_corner_tapering/assets/tex_metal_fill.png.import +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://bj658oli0klj3" -path="res://.godot/imported/tex_metal_fill.png-307d5ebcedc9e8c4f154a2c09687cb41.ctex" +uid="uid://ubnurptd6ee2" +path="res://.godot/imported/PS5_Dpad.png-ef26d9f78f150d4ab2b9e6bbe325f986.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://examples/sharp_corner_tapering/assets/tex_metal_fill.png" -dest_files=["res://.godot/imported/tex_metal_fill.png-307d5ebcedc9e8c4f154a2c09687cb41.ctex"] +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad.png" +dest_files=["res://.godot/imported/PS5_Dpad.png-ef26d9f78f150d4ab2b9e6bbe325f986.ctex"] [params] diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Down.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Down.png new file mode 100644 index 0000000..a8f893a Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Down.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Down.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Down.png.import new file mode 100644 index 0000000..26ef580 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Down.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vk1vje3280tk" +path="res://.godot/imported/PS5_Dpad_Down.png-ba21ca6e311100c142d2b003152ea1d2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Down.png" +dest_files=["res://.godot/imported/PS5_Dpad_Down.png-ba21ca6e311100c142d2b003152ea1d2.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Left.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Left.png new file mode 100644 index 0000000..2bdc048 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Left.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Left.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Left.png.import new file mode 100644 index 0000000..9a31227 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Left.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bkpw61ctv0fbg" +path="res://.godot/imported/PS5_Dpad_Left.png-bd78cf7c0092facc48bbf8fd7816f7a2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Left.png" +dest_files=["res://.godot/imported/PS5_Dpad_Left.png-bd78cf7c0092facc48bbf8fd7816f7a2.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Right.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Right.png new file mode 100644 index 0000000..b7cd568 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Right.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Right.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Right.png.import new file mode 100644 index 0000000..257b99c --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Right.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dybnayy8y7rxe" +path="res://.godot/imported/PS5_Dpad_Right.png-064b9c5c42d22a9c2be3902ca2e33638.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Right.png" +dest_files=["res://.godot/imported/PS5_Dpad_Right.png-064b9c5c42d22a9c2be3902ca2e33638.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Up.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Up.png new file mode 100644 index 0000000..99180d2 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Up.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Up.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Up.png.import new file mode 100644 index 0000000..bfa2c71 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Up.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvbd876sy2430" +path="res://.godot/imported/PS5_Dpad_Up.png-b8fc9319fe2231915e5e8e21174b1c1c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Up.png" +dest_files=["res://.godot/imported/PS5_Dpad_Up.png-b8fc9319fe2231915e5e8e21174b1c1c.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L1.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L1.png new file mode 100644 index 0000000..07e505a Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L1.png differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_edge.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L1.png.import similarity index 65% rename from examples/sharp_corner_tapering/assets/tex_metal_edge.png.import rename to addons/guide/ui/renderers/controllers/playstation/icons/PS5_L1.png.import index 4e4b107..dd46c43 100644 --- a/examples/sharp_corner_tapering/assets/tex_metal_edge.png.import +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L1.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://b3aqa3bj1osvp" -path="res://.godot/imported/tex_metal_edge.png-5aaf6e458197a953a7afeee0e270fea4.ctex" +uid="uid://cqgpumb0tf5xr" +path="res://.godot/imported/PS5_L1.png-daedbc1549c79d92cbcf68661193a3b8.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://examples/sharp_corner_tapering/assets/tex_metal_edge.png" -dest_files=["res://.godot/imported/tex_metal_edge.png-5aaf6e458197a953a7afeee0e270fea4.ctex"] +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_L1.png" +dest_files=["res://.godot/imported/PS5_L1.png-daedbc1549c79d92cbcf68661193a3b8.ctex"] [params] diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L2.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L2.png new file mode 100644 index 0000000..05f3dd2 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L2.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L2.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L2.png.import new file mode 100644 index 0000000..376d592 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_L2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bhoi6nfung5ye" +path="res://.godot/imported/PS5_L2.png-2ad86a3ad9afd70333db64063ae812ae.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_L2.png" +dest_files=["res://.godot/imported/PS5_L2.png-2ad86a3ad9afd70333db64063ae812ae.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick.png new file mode 100644 index 0000000..0245ff8 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick.png.import new file mode 100644 index 0000000..55a4f30 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c3qet180o0dn6" +path="res://.godot/imported/PS5_Left_Stick.png-472622a0a1752a811747d3e6c02f5438.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick.png" +dest_files=["res://.godot/imported/PS5_Left_Stick.png-472622a0a1752a811747d3e6c02f5438.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick_Click.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick_Click.png new file mode 100644 index 0000000..66e5271 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick_Click.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick_Click.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick_Click.png.import new file mode 100644 index 0000000..84fe65f --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick_Click.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0b1sdadfcnbk" +path="res://.godot/imported/PS5_Left_Stick_Click.png-f837f37222a7c945cd4b672d0d7e3ba1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick_Click.png" +dest_files=["res://.godot/imported/PS5_Left_Stick_Click.png-f837f37222a7c945cd4b672d0d7e3ba1.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Microphone.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Microphone.png new file mode 100644 index 0000000..bb0f331 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Microphone.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Microphone.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Microphone.png.import new file mode 100644 index 0000000..6199d2d --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Microphone.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://eljpu2rrb3k4" +path="res://.godot/imported/PS5_Microphone.png-3a2db423599523aa5c1b828df7d224bc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Microphone.png" +dest_files=["res://.godot/imported/PS5_Microphone.png-3a2db423599523aa5c1b828df7d224bc.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options.png new file mode 100644 index 0000000..3e56fe2 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options.png.import new file mode 100644 index 0000000..b464245 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bkttgyeuecjw" +path="res://.godot/imported/PS5_Options.png-4bd9928e2e3aca6fb17663799d26e7a5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options.png" +dest_files=["res://.godot/imported/PS5_Options.png-4bd9928e2e3aca6fb17663799d26e7a5.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options_Alt.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options_Alt.png new file mode 100644 index 0000000..ca28364 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options_Alt.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options_Alt.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options_Alt.png.import new file mode 100644 index 0000000..cb2f529 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options_Alt.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://byed3fsjbp82u" +path="res://.godot/imported/PS5_Options_Alt.png-4b64997ac577d658c383b1e727319cf5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options_Alt.png" +dest_files=["res://.godot/imported/PS5_Options_Alt.png-4b64997ac577d658c383b1e727319cf5.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R1.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R1.png new file mode 100644 index 0000000..2cff97a Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R1.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R1.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R1.png.import new file mode 100644 index 0000000..3cb7aec --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rwgkfm18pk3l" +path="res://.godot/imported/PS5_R1.png-2f57506c67c952763f228117ce37754b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_R1.png" +dest_files=["res://.godot/imported/PS5_R1.png-2f57506c67c952763f228117ce37754b.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R2.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R2.png new file mode 100644 index 0000000..a13f17f Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R2.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R2.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R2.png.import new file mode 100644 index 0000000..533cfd7 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_R2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://u6ba23igjbj5" +path="res://.godot/imported/PS5_R2.png-9671164f26e8ed5c0f2352c255960e7c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_R2.png" +dest_files=["res://.godot/imported/PS5_R2.png-9671164f26e8ed5c0f2352c255960e7c.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick.png new file mode 100644 index 0000000..85c1556 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick.png.import new file mode 100644 index 0000000..555e054 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bukgaq1m26bw3" +path="res://.godot/imported/PS5_Right_Stick.png-884107fa82c161e8696ba874c711b8d7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick.png" +dest_files=["res://.godot/imported/PS5_Right_Stick.png-884107fa82c161e8696ba874c711b8d7.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick_Click.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick_Click.png new file mode 100644 index 0000000..eecd4e8 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick_Click.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick_Click.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick_Click.png.import new file mode 100644 index 0000000..90f3926 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick_Click.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c4krmros0va1i" +path="res://.godot/imported/PS5_Right_Stick_Click.png-b097f7eaaf3fdd2f3db31ab4d9ef06b4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick_Click.png" +dest_files=["res://.godot/imported/PS5_Right_Stick_Click.png-b097f7eaaf3fdd2f3db31ab4d9ef06b4.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share.png new file mode 100644 index 0000000..d96e698 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share.png.import new file mode 100644 index 0000000..018c729 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bw2h7xxdtp31i" +path="res://.godot/imported/PS5_Share.png-ecf2ad701cb784ee9e69b7052bffc94f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share.png" +dest_files=["res://.godot/imported/PS5_Share.png-ecf2ad701cb784ee9e69b7052bffc94f.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share_Alt.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share_Alt.png new file mode 100644 index 0000000..10941aa Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share_Alt.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share_Alt.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share_Alt.png.import new file mode 100644 index 0000000..5bf9adc --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share_Alt.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwje5248woygn" +path="res://.godot/imported/PS5_Share_Alt.png-f38d2e9e85009e094eb2254e0d890a1d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share_Alt.png" +dest_files=["res://.godot/imported/PS5_Share_Alt.png-f38d2e9e85009e094eb2254e0d890a1d.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Square.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Square.png new file mode 100644 index 0000000..20f6065 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Square.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Square.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Square.png.import new file mode 100644 index 0000000..501b7da --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Square.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dm6vfcwtodame" +path="res://.godot/imported/PS5_Square.png-c0fff0babe3326f24867d317d430c13a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Square.png" +dest_files=["res://.godot/imported/PS5_Square.png-c0fff0babe3326f24867d317d430c13a.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Touch_Pad.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Touch_Pad.png new file mode 100644 index 0000000..1a77d0c Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Touch_Pad.png differ diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Touch_Pad.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Touch_Pad.png.import new file mode 100644 index 0000000..025c11c --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Touch_Pad.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxxkjsl2u83mp" +path="res://.godot/imported/PS5_Touch_Pad.png-b3baca99700ac1cd505b545f684de924.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Touch_Pad.png" +dest_files=["res://.godot/imported/PS5_Touch_Pad.png-b3baca99700ac1cd505b545f684de924.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 diff --git a/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Triangle.png b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Triangle.png new file mode 100644 index 0000000..4950d17 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Triangle.png differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_right.png.import b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Triangle.png.import similarity index 67% rename from examples/sharp_corner_tapering/assets/tex_metal_taper_corner_right.png.import rename to addons/guide/ui/renderers/controllers/playstation/icons/PS5_Triangle.png.import index 7adf36e..0aa199d 100644 --- a/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_right.png.import +++ b/addons/guide/ui/renderers/controllers/playstation/icons/PS5_Triangle.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://cdnfaf3bslk38" -path="res://.godot/imported/tex_metal_taper_corner_right.png-75d13fe99bb8e540489390ee64c63ea5.ctex" +uid="uid://bjjj12v4g82g4" +path="res://.godot/imported/PS5_Triangle.png-6cfcb99a3dd2daba1763b52afa5e6f91.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://examples/sharp_corner_tapering/assets/tex_metal_taper_corner_right.png" -dest_files=["res://.godot/imported/tex_metal_taper_corner_right.png-75d13fe99bb8e540489390ee64c63ea5.ctex"] +source_file="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Triangle.png" +dest_files=["res://.godot/imported/PS5_Triangle.png-6cfcb99a3dd2daba1763b52afa5e6f91.ctex"] [params] diff --git a/addons/guide/ui/renderers/controllers/playstation/playstation_controller_renderer.tscn b/addons/guide/ui/renderers/controllers/playstation/playstation_controller_renderer.tscn new file mode 100644 index 0000000..d4809e0 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/playstation/playstation_controller_renderer.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=21 format=3 uid="uid://bwv1638hcrfni"] + +[ext_resource type="PackedScene" uid="uid://bsaylcb5ixjxk" path="res://addons/guide/ui/renderers/controllers/controller_renderer.tscn" id="1_bq6gh"] +[ext_resource type="Texture2D" uid="uid://cfy1rx4d4wjdh" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Cross.png" id="2_oqi6t"] +[ext_resource type="Texture2D" uid="uid://civpcnwgbu5ky" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Circle.png" id="3_m332j"] +[ext_resource type="Texture2D" uid="uid://dm6vfcwtodame" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Square.png" id="4_dqhg4"] +[ext_resource type="Texture2D" uid="uid://bjjj12v4g82g4" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Triangle.png" id="5_42ocy"] +[ext_resource type="Texture2D" uid="uid://c3qet180o0dn6" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick.png" id="6_wwoxb"] +[ext_resource type="Texture2D" uid="uid://c0b1sdadfcnbk" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Left_Stick_Click.png" id="7_gethe"] +[ext_resource type="Texture2D" uid="uid://bukgaq1m26bw3" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick.png" id="8_u2725"] +[ext_resource type="Texture2D" uid="uid://c4krmros0va1i" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Right_Stick_Click.png" id="9_wfckm"] +[ext_resource type="Texture2D" uid="uid://cqgpumb0tf5xr" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_L1.png" id="10_34ib6"] +[ext_resource type="Texture2D" uid="uid://rwgkfm18pk3l" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_R1.png" id="11_53ury"] +[ext_resource type="Texture2D" uid="uid://bhoi6nfung5ye" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_L2.png" id="12_tyubh"] +[ext_resource type="Texture2D" uid="uid://u6ba23igjbj5" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_R2.png" id="13_pr5lk"] +[ext_resource type="Texture2D" uid="uid://bvbd876sy2430" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Up.png" id="14_h0miw"] +[ext_resource type="Texture2D" uid="uid://bkpw61ctv0fbg" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Left.png" id="15_q5yu5"] +[ext_resource type="Texture2D" uid="uid://dybnayy8y7rxe" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Right.png" id="16_ulk14"] +[ext_resource type="Texture2D" uid="uid://vk1vje3280tk" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Dpad_Down.png" id="17_wm4fj"] +[ext_resource type="Texture2D" uid="uid://bkttgyeuecjw" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Options.png" id="18_eabm3"] +[ext_resource type="Texture2D" uid="uid://eljpu2rrb3k4" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Microphone.png" id="19_oj5w7"] +[ext_resource type="Texture2D" uid="uid://bw2h7xxdtp31i" path="res://addons/guide/ui/renderers/controllers/playstation/icons/PS5_Share.png" id="20_p3s2m"] + +[node name="ControllerRenderer" instance=ExtResource("1_bq6gh")] +controller_name_matches = Array[String](["DualSense", "DualShock", "PlayStation", "PS3", "PS4", "PS5"]) +a_button = ExtResource("2_oqi6t") +b_button = ExtResource("3_m332j") +x_button = ExtResource("4_dqhg4") +y_button = ExtResource("5_42ocy") +left_stick = ExtResource("6_wwoxb") +left_stick_click = ExtResource("7_gethe") +right_stick = ExtResource("8_u2725") +right_stick_click = ExtResource("9_wfckm") +left_bumper = ExtResource("10_34ib6") +right_bumper = ExtResource("11_53ury") +left_trigger = ExtResource("12_tyubh") +right_trigger = ExtResource("13_pr5lk") +dpad_up = ExtResource("14_h0miw") +dpad_left = ExtResource("15_q5yu5") +dpad_right = ExtResource("16_ulk14") +dpad_down = ExtResource("17_wm4fj") +start = ExtResource("18_eabm3") +misc1 = ExtResource("19_oj5w7") +back = ExtResource("20_p3s2m") + +[node name="AButton" parent="HBoxContainer/Controls" index="0"] +texture = ExtResource("2_oqi6t") + +[node name="BButton" parent="HBoxContainer/Controls" index="1"] +texture = ExtResource("3_m332j") + +[node name="XButton" parent="HBoxContainer/Controls" index="2"] +texture = ExtResource("4_dqhg4") + +[node name="YButton" parent="HBoxContainer/Controls" index="3"] +texture = ExtResource("5_42ocy") + +[node name="LeftStick" parent="HBoxContainer/Controls" index="4"] +texture = ExtResource("6_wwoxb") + +[node name="LeftStickClick" parent="HBoxContainer/Controls" index="5"] +texture = ExtResource("7_gethe") + +[node name="RightStick" parent="HBoxContainer/Controls" index="6"] +texture = ExtResource("8_u2725") + +[node name="RightStickClick" parent="HBoxContainer/Controls" index="7"] +texture = ExtResource("9_wfckm") + +[node name="LeftBumper" parent="HBoxContainer/Controls" index="8"] +texture = ExtResource("10_34ib6") + +[node name="RightBumper" parent="HBoxContainer/Controls" index="9"] +texture = ExtResource("11_53ury") + +[node name="LeftTrigger" parent="HBoxContainer/Controls" index="10"] +texture = ExtResource("12_tyubh") + +[node name="RightTrigger" parent="HBoxContainer/Controls" index="11"] +texture = ExtResource("13_pr5lk") + +[node name="DpadUp" parent="HBoxContainer/Controls" index="12"] +texture = ExtResource("14_h0miw") + +[node name="DpadLeft" parent="HBoxContainer/Controls" index="13"] +texture = ExtResource("15_q5yu5") + +[node name="DpadRight" parent="HBoxContainer/Controls" index="14"] +texture = ExtResource("16_ulk14") + +[node name="DpadDown" parent="HBoxContainer/Controls" index="15"] +texture = ExtResource("17_wm4fj") + +[node name="Start" parent="HBoxContainer/Controls" index="16"] +texture = ExtResource("18_eabm3") + +[node name="Misc1" parent="HBoxContainer/Controls" index="17"] +texture = ExtResource("19_oj5w7") + +[node name="Back" parent="HBoxContainer/Controls" index="18"] +texture = ExtResource("20_p3s2m") diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_A.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_A.png new file mode 100644 index 0000000..df756ef Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_A.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_A.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_A.png.import new file mode 100644 index 0000000..309879f --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_A.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cl75ptbm7sfi5" +path="res://.godot/imported/Switch_A.png-f1d58b04f27891568073a11e43627862.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_A.png" +dest_files=["res://.godot/imported/Switch_A.png-f1d58b04f27891568073a11e43627862.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_B.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_B.png new file mode 100644 index 0000000..ea7e743 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_B.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_B.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_B.png.import new file mode 100644 index 0000000..a6de4c9 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_B.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bptn4jygg3p8q" +path="res://.godot/imported/Switch_B.png-fbb8f305e166298807aa18fab0c22a62.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_B.png" +dest_files=["res://.godot/imported/Switch_B.png-fbb8f305e166298807aa18fab0c22a62.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Left.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Left.png new file mode 100644 index 0000000..f90a244 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Left.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Left.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Left.png.import new file mode 100644 index 0000000..4d4974c --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Left.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b0ha1pv08n3fn" +path="res://.godot/imported/Switch_Controller_Left.png-832f94a111c828ab506576e8c22b3c3a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Left.png" +dest_files=["res://.godot/imported/Switch_Controller_Left.png-832f94a111c828ab506576e8c22b3c3a.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Right.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Right.png new file mode 100644 index 0000000..873da7e Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Right.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Right.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Right.png.import new file mode 100644 index 0000000..c3d22d6 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Right.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://qv33ijfxtj1x" +path="res://.godot/imported/Switch_Controller_Right.png-0738167dcf8a308918a4e0351ec370a7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Controller_Right.png" +dest_files=["res://.godot/imported/Switch_Controller_Right.png-0738167dcf8a308918a4e0351ec370a7.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers.png new file mode 100644 index 0000000..b6ee54d Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers.png.import new file mode 100644 index 0000000..f4751a8 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dqfhfnjqwcjpk" +path="res://.godot/imported/Switch_Controllers.png-0ab7b7957a575a33aec8f6138ec1b468.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers.png" +dest_files=["res://.godot/imported/Switch_Controllers.png-0ab7b7957a575a33aec8f6138ec1b468.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers_Separate.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers_Separate.png new file mode 100644 index 0000000..0c019da Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers_Separate.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers_Separate.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers_Separate.png.import new file mode 100644 index 0000000..88af5e1 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers_Separate.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8lsr71y25n8q" +path="res://.godot/imported/Switch_Controllers_Separate.png-8b202bd393de46b2f97712ac19581121.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Controllers_Separate.png" +dest_files=["res://.godot/imported/Switch_Controllers_Separate.png-8b202bd393de46b2f97712ac19581121.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Down.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Down.png new file mode 100644 index 0000000..7b7b2b2 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Down.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Down.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Down.png.import new file mode 100644 index 0000000..77b7d18 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Down.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://qt8r1byskjmu" +path="res://.godot/imported/Switch_Down.png-a8bebe4deb11df0456c90115a2306f62.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Down.png" +dest_files=["res://.godot/imported/Switch_Down.png-a8bebe4deb11df0456c90115a2306f62.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad.png new file mode 100644 index 0000000..12f01eb Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad.png.import new file mode 100644 index 0000000..9d3db24 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxvp4elmagomg" +path="res://.godot/imported/Switch_Dpad.png-9f1893107a829bf94f95a8bcfa879f1c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad.png" +dest_files=["res://.godot/imported/Switch_Dpad.png-9f1893107a829bf94f95a8bcfa879f1c.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Down.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Down.png new file mode 100644 index 0000000..37f6d5b Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Down.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Down.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Down.png.import new file mode 100644 index 0000000..8a8f63f --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Down.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dq2ypo4cx3ucs" +path="res://.godot/imported/Switch_Dpad_Down.png-fda4a0d96c9c1d604adf4addc863361f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Down.png" +dest_files=["res://.godot/imported/Switch_Dpad_Down.png-fda4a0d96c9c1d604adf4addc863361f.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Left.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Left.png new file mode 100644 index 0000000..8efd7a4 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Left.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Left.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Left.png.import new file mode 100644 index 0000000..e6468b6 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Left.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rcrsxqeu6mns" +path="res://.godot/imported/Switch_Dpad_Left.png-7d4e2c9108e5188065fbd9645e1af97e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Left.png" +dest_files=["res://.godot/imported/Switch_Dpad_Left.png-7d4e2c9108e5188065fbd9645e1af97e.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Right.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Right.png new file mode 100644 index 0000000..8b5411d Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Right.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Right.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Right.png.import new file mode 100644 index 0000000..41f76e4 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Right.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dubah62ttpnc0" +path="res://.godot/imported/Switch_Dpad_Right.png-74599bcfe029ca89e967999e956aa664.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Right.png" +dest_files=["res://.godot/imported/Switch_Dpad_Right.png-74599bcfe029ca89e967999e956aa664.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Up.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Up.png new file mode 100644 index 0000000..700a8ba Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Up.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Up.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Up.png.import new file mode 100644 index 0000000..5609977 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Up.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://u6uclokrrbaq" +path="res://.godot/imported/Switch_Dpad_Up.png-38cc365cd950cad00eb7342f63b614a5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Dpad_Up.png" +dest_files=["res://.godot/imported/Switch_Dpad_Up.png-38cc365cd950cad00eb7342f63b614a5.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Home.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Home.png new file mode 100644 index 0000000..9b6733c Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Home.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Home.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Home.png.import new file mode 100644 index 0000000..29e9d4d --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Home.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://uf6oq3wbq11f" +path="res://.godot/imported/Switch_Home.png-31680591ab356324906bfaaeace20e43.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Home.png" +dest_files=["res://.godot/imported/Switch_Home.png-31680591ab356324906bfaaeace20e43.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_LB.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_LB.png new file mode 100644 index 0000000..ddfa3b9 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_LB.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_LB.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_LB.png.import new file mode 100644 index 0000000..f004694 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_LB.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cb6gvej03avm3" +path="res://.godot/imported/Switch_LB.png-fc77289764fd409ac6c0408486b0c16b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_LB.png" +dest_files=["res://.godot/imported/Switch_LB.png-fc77289764fd409ac6c0408486b0c16b.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_LT.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_LT.png new file mode 100644 index 0000000..6942e1f Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_LT.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_LT.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_LT.png.import new file mode 100644 index 0000000..3badb9f --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_LT.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://savy2mhybmun" +path="res://.godot/imported/Switch_LT.png-b154a02af7bcd266253a208d8d610852.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_LT.png" +dest_files=["res://.godot/imported/Switch_LT.png-b154a02af7bcd266253a208d8d610852.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left.png new file mode 100644 index 0000000..fd58439 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left.png.import new file mode 100644 index 0000000..20957cb --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cyjwul8mif4s2" +path="res://.godot/imported/Switch_Left.png-cc76cc1aa00b43ca3e312439715d169a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Left.png" +dest_files=["res://.godot/imported/Switch_Left.png-cc76cc1aa00b43ca3e312439715d169a.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick.png new file mode 100644 index 0000000..d861ca5 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick.png.import new file mode 100644 index 0000000..2a5be36 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cha2jimmsyrsg" +path="res://.godot/imported/Switch_Left_Stick.png-1cc52d3c1e1f259e0115217e02740b99.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick.png" +dest_files=["res://.godot/imported/Switch_Left_Stick.png-1cc52d3c1e1f259e0115217e02740b99.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick_Click.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick_Click.png new file mode 100644 index 0000000..66e5271 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick_Click.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick_Click.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick_Click.png.import new file mode 100644 index 0000000..fc56eb6 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick_Click.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://by1vmleujtq1i" +path="res://.godot/imported/Switch_Left_Stick_Click.png-7992de9526c87e19b6a04a21954e96af.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick_Click.png" +dest_files=["res://.godot/imported/Switch_Left_Stick_Click.png-7992de9526c87e19b6a04a21954e96af.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Minus.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Minus.png new file mode 100644 index 0000000..d32608e Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Minus.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Minus.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Minus.png.import new file mode 100644 index 0000000..9a4233c --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Minus.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bdydqv6vi48ix" +path="res://.godot/imported/Switch_Minus.png-b6cd3147393308196e49ab3a608d1c8a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Minus.png" +dest_files=["res://.godot/imported/Switch_Minus.png-b6cd3147393308196e49ab3a608d1c8a.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Plus.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Plus.png new file mode 100644 index 0000000..f1b0dc4 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Plus.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Plus.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Plus.png.import new file mode 100644 index 0000000..4d470fe --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Plus.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://j3wpcxyxsy2r" +path="res://.godot/imported/Switch_Plus.png-75c2cf5b7056a47425c210b1f60dcdc2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Plus.png" +dest_files=["res://.godot/imported/Switch_Plus.png-75c2cf5b7056a47425c210b1f60dcdc2.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_RB.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_RB.png new file mode 100644 index 0000000..01f137a Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_RB.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_RB.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_RB.png.import new file mode 100644 index 0000000..1c7a578 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_RB.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://s2xm61tj0mfy" +path="res://.godot/imported/Switch_RB.png-3d9fbc66dcc67aee9a5716cef6ece679.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_RB.png" +dest_files=["res://.godot/imported/Switch_RB.png-3d9fbc66dcc67aee9a5716cef6ece679.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_RT.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_RT.png new file mode 100644 index 0000000..6aef3cb Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_RT.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_RT.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_RT.png.import new file mode 100644 index 0000000..2109b91 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_RT.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cccvjq78xw3n4" +path="res://.godot/imported/Switch_RT.png-521dbc557ae52cbe19429b25fbf68d18.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_RT.png" +dest_files=["res://.godot/imported/Switch_RT.png-521dbc557ae52cbe19429b25fbf68d18.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right.png new file mode 100644 index 0000000..f524c6c Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right.png.import new file mode 100644 index 0000000..094f135 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b3os8st4cai36" +path="res://.godot/imported/Switch_Right.png-cd6972267e466e454282edcdee867c3a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Right.png" +dest_files=["res://.godot/imported/Switch_Right.png-cd6972267e466e454282edcdee867c3a.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick.png new file mode 100644 index 0000000..f2c605b Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick.png.import new file mode 100644 index 0000000..5b96fa4 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1jqxuup5llkb" +path="res://.godot/imported/Switch_Right_Stick.png-9a091e8f8aab1b8517e0e63458ce9648.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick.png" +dest_files=["res://.godot/imported/Switch_Right_Stick.png-9a091e8f8aab1b8517e0e63458ce9648.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick_Click.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick_Click.png new file mode 100644 index 0000000..eecd4e8 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick_Click.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick_Click.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick_Click.png.import new file mode 100644 index 0000000..d9492b0 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick_Click.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://denpxaxemjpg3" +path="res://.godot/imported/Switch_Right_Stick_Click.png-73f9b93cd8d68f031b93843441f5ac52.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick_Click.png" +dest_files=["res://.godot/imported/Switch_Right_Stick_Click.png-73f9b93cd8d68f031b93843441f5ac52.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Square.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Square.png new file mode 100644 index 0000000..d0fd432 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Square.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Square.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Square.png.import new file mode 100644 index 0000000..1da9b49 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Square.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cl0owijnhu5pc" +path="res://.godot/imported/Switch_Square.png-e3ed4021db85fe9e3827c68afd31c3ac.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Square.png" +dest_files=["res://.godot/imported/Switch_Square.png-e3ed4021db85fe9e3827c68afd31c3ac.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Up.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Up.png new file mode 100644 index 0000000..352f890 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Up.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Up.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Up.png.import new file mode 100644 index 0000000..e6fe688 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Up.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dxmy0dvee663b" +path="res://.godot/imported/Switch_Up.png-d9db5e9a6fb52c3f8674741ac7a63c50.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Up.png" +dest_files=["res://.godot/imported/Switch_Up.png-d9db5e9a6fb52c3f8674741ac7a63c50.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_X.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_X.png new file mode 100644 index 0000000..bdf86ba Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_X.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_X.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_X.png.import new file mode 100644 index 0000000..eeee651 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_X.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://7c6ie8ef23ox" +path="res://.godot/imported/Switch_X.png-8ff15c2bb86e671b78d91e2041718b60.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_X.png" +dest_files=["res://.godot/imported/Switch_X.png-8ff15c2bb86e671b78d91e2041718b60.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 diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Y.png b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Y.png new file mode 100644 index 0000000..46ac216 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Y.png differ diff --git a/addons/guide/ui/renderers/controllers/switch/icons/Switch_Y.png.import b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Y.png.import new file mode 100644 index 0000000..0ace6f9 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/icons/Switch_Y.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bru7lpc778npo" +path="res://.godot/imported/Switch_Y.png-f47eae5d6991151df29244754a422398.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Y.png" +dest_files=["res://.godot/imported/Switch_Y.png-f47eae5d6991151df29244754a422398.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 diff --git a/addons/guide/ui/renderers/controllers/switch/switch_controller_renderer.tscn b/addons/guide/ui/renderers/controllers/switch/switch_controller_renderer.tscn new file mode 100644 index 0000000..98bc510 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/switch/switch_controller_renderer.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=21 format=3 uid="uid://dlhmh4o43l7pp"] + +[ext_resource type="PackedScene" uid="uid://bsaylcb5ixjxk" path="res://addons/guide/ui/renderers/controllers/controller_renderer.tscn" id="1_mxg2g"] +[ext_resource type="Texture2D" uid="uid://bptn4jygg3p8q" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_B.png" id="2_hj4a5"] +[ext_resource type="Texture2D" uid="uid://cl75ptbm7sfi5" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_A.png" id="3_0hjly"] +[ext_resource type="Texture2D" uid="uid://bru7lpc778npo" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Y.png" id="4_b8ldp"] +[ext_resource type="Texture2D" uid="uid://7c6ie8ef23ox" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_X.png" id="5_qpo6l"] +[ext_resource type="Texture2D" uid="uid://cha2jimmsyrsg" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick.png" id="6_o36fw"] +[ext_resource type="Texture2D" uid="uid://by1vmleujtq1i" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Left_Stick_Click.png" id="7_tn44v"] +[ext_resource type="Texture2D" uid="uid://d1jqxuup5llkb" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick.png" id="8_gfspk"] +[ext_resource type="Texture2D" uid="uid://denpxaxemjpg3" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Right_Stick_Click.png" id="9_ktbic"] +[ext_resource type="Texture2D" uid="uid://cb6gvej03avm3" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_LB.png" id="10_6uo88"] +[ext_resource type="Texture2D" uid="uid://s2xm61tj0mfy" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_RB.png" id="11_xm8m7"] +[ext_resource type="Texture2D" uid="uid://savy2mhybmun" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_LT.png" id="12_y225d"] +[ext_resource type="Texture2D" uid="uid://cccvjq78xw3n4" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_RT.png" id="13_xpnov"] +[ext_resource type="Texture2D" uid="uid://dxmy0dvee663b" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Up.png" id="14_ujug8"] +[ext_resource type="Texture2D" uid="uid://cyjwul8mif4s2" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Left.png" id="15_2efb3"] +[ext_resource type="Texture2D" uid="uid://b3os8st4cai36" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Right.png" id="16_yqxw1"] +[ext_resource type="Texture2D" uid="uid://qt8r1byskjmu" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Down.png" id="17_gfqch"] +[ext_resource type="Texture2D" uid="uid://j3wpcxyxsy2r" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Plus.png" id="18_s5cn6"] +[ext_resource type="Texture2D" uid="uid://cl0owijnhu5pc" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Square.png" id="19_iegd6"] +[ext_resource type="Texture2D" uid="uid://bdydqv6vi48ix" path="res://addons/guide/ui/renderers/controllers/switch/icons/Switch_Minus.png" id="20_kalbc"] + +[node name="ControllerRenderer" instance=ExtResource("1_mxg2g")] +controller_name_matches = Array[String](["Nintendo Switch"]) +a_button = ExtResource("2_hj4a5") +b_button = ExtResource("3_0hjly") +x_button = ExtResource("4_b8ldp") +y_button = ExtResource("5_qpo6l") +left_stick = ExtResource("6_o36fw") +left_stick_click = ExtResource("7_tn44v") +right_stick = ExtResource("8_gfspk") +right_stick_click = ExtResource("9_ktbic") +left_bumper = ExtResource("10_6uo88") +right_bumper = ExtResource("11_xm8m7") +left_trigger = ExtResource("12_y225d") +right_trigger = ExtResource("13_xpnov") +dpad_up = ExtResource("14_ujug8") +dpad_left = ExtResource("15_2efb3") +dpad_right = ExtResource("16_yqxw1") +dpad_down = ExtResource("17_gfqch") +start = ExtResource("18_s5cn6") +misc1 = ExtResource("19_iegd6") +back = ExtResource("20_kalbc") + +[node name="AButton" parent="HBoxContainer/Controls" index="0"] +texture = ExtResource("2_hj4a5") + +[node name="BButton" parent="HBoxContainer/Controls" index="1"] +texture = ExtResource("3_0hjly") + +[node name="XButton" parent="HBoxContainer/Controls" index="2"] +texture = ExtResource("4_b8ldp") + +[node name="YButton" parent="HBoxContainer/Controls" index="3"] +texture = ExtResource("5_qpo6l") + +[node name="LeftStick" parent="HBoxContainer/Controls" index="4"] +texture = ExtResource("6_o36fw") + +[node name="LeftStickClick" parent="HBoxContainer/Controls" index="5"] +texture = ExtResource("7_tn44v") + +[node name="RightStick" parent="HBoxContainer/Controls" index="6"] +texture = ExtResource("8_gfspk") + +[node name="RightStickClick" parent="HBoxContainer/Controls" index="7"] +texture = ExtResource("9_ktbic") + +[node name="LeftBumper" parent="HBoxContainer/Controls" index="8"] +texture = ExtResource("10_6uo88") + +[node name="RightBumper" parent="HBoxContainer/Controls" index="9"] +texture = ExtResource("11_xm8m7") + +[node name="LeftTrigger" parent="HBoxContainer/Controls" index="10"] +texture = ExtResource("12_y225d") + +[node name="RightTrigger" parent="HBoxContainer/Controls" index="11"] +texture = ExtResource("13_xpnov") + +[node name="DpadUp" parent="HBoxContainer/Controls" index="12"] +texture = ExtResource("14_ujug8") + +[node name="DpadLeft" parent="HBoxContainer/Controls" index="13"] +texture = ExtResource("15_2efb3") + +[node name="DpadRight" parent="HBoxContainer/Controls" index="14"] +texture = ExtResource("16_yqxw1") + +[node name="DpadDown" parent="HBoxContainer/Controls" index="15"] +texture = ExtResource("17_gfqch") + +[node name="Start" parent="HBoxContainer/Controls" index="16"] +texture = ExtResource("18_s5cn6") + +[node name="Misc1" parent="HBoxContainer/Controls" index="17"] +texture = ExtResource("19_iegd6") + +[node name="Back" parent="HBoxContainer/Controls" index="18"] +texture = ExtResource("20_kalbc") diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_A.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_A.png new file mode 100644 index 0000000..e22bb29 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_A.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_A.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_A.png.import new file mode 100644 index 0000000..271ef8d --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_A.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cujvw3m7aghgh" +path="res://.godot/imported/XboxSeriesX_A.png-6e6e4943fb226932d525ee72e98fb8ef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_A.png" +dest_files=["res://.godot/imported/XboxSeriesX_A.png-6e6e4943fb226932d525ee72e98fb8ef.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_B.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_B.png new file mode 100644 index 0000000..9312c26 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_B.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_B.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_B.png.import new file mode 100644 index 0000000..4eb3b2b --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_B.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brgqhp87g40l5" +path="res://.godot/imported/XboxSeriesX_B.png-78255eca5094e7bc4b681e33187791ff.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_B.png" +dest_files=["res://.godot/imported/XboxSeriesX_B.png-78255eca5094e7bc4b681e33187791ff.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad.png new file mode 100644 index 0000000..d66bd81 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad.png.import new file mode 100644 index 0000000..177a232 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://j5kp5tnwtysq" +path="res://.godot/imported/XboxSeriesX_Dpad.png-4bf4aa5e92bab139204438b5ac2b303d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad.png" +dest_files=["res://.godot/imported/XboxSeriesX_Dpad.png-4bf4aa5e92bab139204438b5ac2b303d.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Down.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Down.png new file mode 100644 index 0000000..93478ee Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Down.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Down.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Down.png.import new file mode 100644 index 0000000..33030ff --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Down.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1fgf8ia7q4vo" +path="res://.godot/imported/XboxSeriesX_Dpad_Down.png-04b87c5546afa2b93f9116f73733624b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Down.png" +dest_files=["res://.godot/imported/XboxSeriesX_Dpad_Down.png-04b87c5546afa2b93f9116f73733624b.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Left.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Left.png new file mode 100644 index 0000000..e1e3dfd Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Left.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Left.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Left.png.import new file mode 100644 index 0000000..4a746df --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Left.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqtskbk6l8v7w" +path="res://.godot/imported/XboxSeriesX_Dpad_Left.png-8d74fbe74c1e93968cbcbaa007feb182.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Left.png" +dest_files=["res://.godot/imported/XboxSeriesX_Dpad_Left.png-8d74fbe74c1e93968cbcbaa007feb182.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Right.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Right.png new file mode 100644 index 0000000..2cabaef Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Right.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Right.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Right.png.import new file mode 100644 index 0000000..4dc009f --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Right.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gsilbr1bntic" +path="res://.godot/imported/XboxSeriesX_Dpad_Right.png-e6fc74a1f6107eff3516a80369cf5807.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Right.png" +dest_files=["res://.godot/imported/XboxSeriesX_Dpad_Right.png-e6fc74a1f6107eff3516a80369cf5807.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Up.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Up.png new file mode 100644 index 0000000..a466bad Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Up.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Up.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Up.png.import new file mode 100644 index 0000000..a3ae1e8 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Up.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://boc4an5lj12lp" +path="res://.godot/imported/XboxSeriesX_Dpad_Up.png-d339224a22eaf2e00e885d73c907a138.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Up.png" +dest_files=["res://.godot/imported/XboxSeriesX_Dpad_Up.png-d339224a22eaf2e00e885d73c907a138.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LB.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LB.png new file mode 100644 index 0000000..f6c414b Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LB.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LB.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LB.png.import new file mode 100644 index 0000000..99b6409 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LB.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://uwqbgrkqv7qc" +path="res://.godot/imported/XboxSeriesX_LB.png-50df36f6ecf745654f01aae04e5a8a67.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LB.png" +dest_files=["res://.godot/imported/XboxSeriesX_LB.png-50df36f6ecf745654f01aae04e5a8a67.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LT.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LT.png new file mode 100644 index 0000000..526816c Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LT.png differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_left.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LT.png.import similarity index 65% rename from examples/sharp_corner_tapering/assets/tex_metal_taper_corner_left.png.import rename to addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LT.png.import index 5315f40..7b6737d 100644 --- a/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_left.png.import +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LT.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://jc3g5qsmnpdd" -path="res://.godot/imported/tex_metal_taper_corner_left.png-735fbf01b6fc0725b32a91fb24aae5d5.ctex" +uid="uid://c1rw1hnlt3dlt" +path="res://.godot/imported/XboxSeriesX_LT.png-4c80e87d7c8bd0e2d11025799541d6ae.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://examples/sharp_corner_tapering/assets/tex_metal_taper_corner_left.png" -dest_files=["res://.godot/imported/tex_metal_taper_corner_left.png-735fbf01b6fc0725b32a91fb24aae5d5.ctex"] +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LT.png" +dest_files=["res://.godot/imported/XboxSeriesX_LT.png-4c80e87d7c8bd0e2d11025799541d6ae.ctex"] [params] diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick.png new file mode 100644 index 0000000..de49dc6 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick.png.import new file mode 100644 index 0000000..66a1fbd --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://wol4p4f32lfr" +path="res://.godot/imported/XboxSeriesX_Left_Stick.png-c81470e6e08de714ca5029e194422ef3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick.png" +dest_files=["res://.godot/imported/XboxSeriesX_Left_Stick.png-c81470e6e08de714ca5029e194422ef3.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick_Click.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick_Click.png new file mode 100644 index 0000000..ad0428f Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick_Click.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick_Click.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick_Click.png.import new file mode 100644 index 0000000..bc1a37b --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick_Click.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0xpc73ovry50" +path="res://.godot/imported/XboxSeriesX_Left_Stick_Click.png-583c878cd8832ec16d9d309381418b44.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick_Click.png" +dest_files=["res://.godot/imported/XboxSeriesX_Left_Stick_Click.png-583c878cd8832ec16d9d309381418b44.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Menu.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Menu.png new file mode 100644 index 0000000..190780e Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Menu.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Menu.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Menu.png.import new file mode 100644 index 0000000..6ff0007 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Menu.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://y70m84f40jkk" +path="res://.godot/imported/XboxSeriesX_Menu.png-b5260eb2af6d939947fd11289117ab1c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Menu.png" +dest_files=["res://.godot/imported/XboxSeriesX_Menu.png-b5260eb2af6d939947fd11289117ab1c.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RB.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RB.png new file mode 100644 index 0000000..5dcfc6d Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RB.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RB.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RB.png.import new file mode 100644 index 0000000..44914e1 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RB.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://5j0mm7ydxc5b" +path="res://.godot/imported/XboxSeriesX_RB.png-8b5fe7ad52beb7dc8003e7331b18e18b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RB.png" +dest_files=["res://.godot/imported/XboxSeriesX_RB.png-8b5fe7ad52beb7dc8003e7331b18e18b.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RT.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RT.png new file mode 100644 index 0000000..8004286 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RT.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RT.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RT.png.import new file mode 100644 index 0000000..8f521dc --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RT.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dvsukgwjjn78x" +path="res://.godot/imported/XboxSeriesX_RT.png-e4f797c7b4ec150868ad67aaecd7e6bc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RT.png" +dest_files=["res://.godot/imported/XboxSeriesX_RT.png-e4f797c7b4ec150868ad67aaecd7e6bc.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick.png new file mode 100644 index 0000000..866be1c Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick.png.import new file mode 100644 index 0000000..8da437a --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c1p7p5qpqxqfn" +path="res://.godot/imported/XboxSeriesX_Right_Stick.png-9c5f7904babde376c469263f16a00eac.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick.png" +dest_files=["res://.godot/imported/XboxSeriesX_Right_Stick.png-9c5f7904babde376c469263f16a00eac.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick_Click.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick_Click.png new file mode 100644 index 0000000..de08508 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick_Click.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick_Click.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick_Click.png.import new file mode 100644 index 0000000..cf66afe --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick_Click.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://pmymadotp1l0" +path="res://.godot/imported/XboxSeriesX_Right_Stick_Click.png-7cd7984c348fb4db2998472d7b950c6a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick_Click.png" +dest_files=["res://.godot/imported/XboxSeriesX_Right_Stick_Click.png-7cd7984c348fb4db2998472d7b950c6a.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Share.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Share.png new file mode 100644 index 0000000..66d9f95 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Share.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Share.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Share.png.import new file mode 100644 index 0000000..cf906c6 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Share.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8b2oomlnf5tt" +path="res://.godot/imported/XboxSeriesX_Share.png-39f960085afed02792af365e2b9c52a6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Share.png" +dest_files=["res://.godot/imported/XboxSeriesX_Share.png-39f960085afed02792af365e2b9c52a6.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_View.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_View.png new file mode 100644 index 0000000..066086a Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_View.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_View.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_View.png.import new file mode 100644 index 0000000..b2f81ab --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_View.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b5wc83dex8igr" +path="res://.godot/imported/XboxSeriesX_View.png-4584623e9f69c92b5f7aa502e1647455.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_View.png" +dest_files=["res://.godot/imported/XboxSeriesX_View.png-4584623e9f69c92b5f7aa502e1647455.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_X.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_X.png new file mode 100644 index 0000000..e944b3e Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_X.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_X.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_X.png.import new file mode 100644 index 0000000..b461388 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_X.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dqnryo1s6qi45" +path="res://.godot/imported/XboxSeriesX_X.png-5f1df66dbbce24929b4c3ab5307e19e3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_X.png" +dest_files=["res://.godot/imported/XboxSeriesX_X.png-5f1df66dbbce24929b4c3ab5307e19e3.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Y.png b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Y.png new file mode 100644 index 0000000..cf4a997 Binary files /dev/null and b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Y.png differ diff --git a/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Y.png.import b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Y.png.import new file mode 100644 index 0000000..b0c08db --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Y.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bx76tv1exmv0p" +path="res://.godot/imported/XboxSeriesX_Y.png-a7cca5057748346da0259b111678f72f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Y.png" +dest_files=["res://.godot/imported/XboxSeriesX_Y.png-a7cca5057748346da0259b111678f72f.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 diff --git a/addons/guide/ui/renderers/controllers/xbox/xbox_controller_renderer.tscn b/addons/guide/ui/renderers/controllers/xbox/xbox_controller_renderer.tscn new file mode 100644 index 0000000..d27adc9 --- /dev/null +++ b/addons/guide/ui/renderers/controllers/xbox/xbox_controller_renderer.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=21 format=3 uid="uid://b0dr5w7b7spvo"] + +[ext_resource type="PackedScene" uid="uid://bsaylcb5ixjxk" path="res://addons/guide/ui/renderers/controllers/controller_renderer.tscn" id="1_5pcnq"] +[ext_resource type="Texture2D" uid="uid://cujvw3m7aghgh" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_A.png" id="2_kd0r1"] +[ext_resource type="Texture2D" uid="uid://brgqhp87g40l5" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_B.png" id="3_oebii"] +[ext_resource type="Texture2D" uid="uid://dqnryo1s6qi45" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_X.png" id="4_dgucg"] +[ext_resource type="Texture2D" uid="uid://bx76tv1exmv0p" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Y.png" id="5_nbb1e"] +[ext_resource type="Texture2D" uid="uid://wol4p4f32lfr" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick.png" id="6_wb84l"] +[ext_resource type="Texture2D" uid="uid://c0xpc73ovry50" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Left_Stick_Click.png" id="7_en4bp"] +[ext_resource type="Texture2D" uid="uid://c1p7p5qpqxqfn" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick.png" id="8_3a0jg"] +[ext_resource type="Texture2D" uid="uid://pmymadotp1l0" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Right_Stick_Click.png" id="9_vu674"] +[ext_resource type="Texture2D" uid="uid://uwqbgrkqv7qc" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LB.png" id="10_4dsgt"] +[ext_resource type="Texture2D" uid="uid://5j0mm7ydxc5b" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RB.png" id="11_3efc4"] +[ext_resource type="Texture2D" uid="uid://c1rw1hnlt3dlt" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_LT.png" id="12_bylwu"] +[ext_resource type="Texture2D" uid="uid://dvsukgwjjn78x" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_RT.png" id="13_viufm"] +[ext_resource type="Texture2D" uid="uid://boc4an5lj12lp" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Up.png" id="14_2uufq"] +[ext_resource type="Texture2D" uid="uid://bqtskbk6l8v7w" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Left.png" id="15_52cih"] +[ext_resource type="Texture2D" uid="uid://gsilbr1bntic" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Right.png" id="16_j6krd"] +[ext_resource type="Texture2D" uid="uid://d1fgf8ia7q4vo" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Dpad_Down.png" id="17_03a3w"] +[ext_resource type="Texture2D" uid="uid://y70m84f40jkk" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Menu.png" id="18_qlpxc"] +[ext_resource type="Texture2D" uid="uid://b8b2oomlnf5tt" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_Share.png" id="19_24yjp"] +[ext_resource type="Texture2D" uid="uid://b5wc83dex8igr" path="res://addons/guide/ui/renderers/controllers/xbox/icons/XboxSeriesX_View.png" id="20_0bc5x"] + +[node name="ControllerRenderer" instance=ExtResource("1_5pcnq")] +controller_name_matches = Array[String](["xbox", "xinput"]) +a_button = ExtResource("2_kd0r1") +b_button = ExtResource("3_oebii") +x_button = ExtResource("4_dgucg") +y_button = ExtResource("5_nbb1e") +left_stick = ExtResource("6_wb84l") +left_stick_click = ExtResource("7_en4bp") +right_stick = ExtResource("8_3a0jg") +right_stick_click = ExtResource("9_vu674") +left_bumper = ExtResource("10_4dsgt") +right_bumper = ExtResource("11_3efc4") +left_trigger = ExtResource("12_bylwu") +right_trigger = ExtResource("13_viufm") +dpad_up = ExtResource("14_2uufq") +dpad_left = ExtResource("15_52cih") +dpad_right = ExtResource("16_j6krd") +dpad_down = ExtResource("17_03a3w") +start = ExtResource("18_qlpxc") +misc1 = ExtResource("19_24yjp") +back = ExtResource("20_0bc5x") + +[node name="AButton" parent="HBoxContainer/Controls" index="0"] +texture = ExtResource("2_kd0r1") + +[node name="BButton" parent="HBoxContainer/Controls" index="1"] +texture = ExtResource("3_oebii") + +[node name="XButton" parent="HBoxContainer/Controls" index="2"] +texture = ExtResource("4_dgucg") + +[node name="YButton" parent="HBoxContainer/Controls" index="3"] +texture = ExtResource("5_nbb1e") + +[node name="LeftStick" parent="HBoxContainer/Controls" index="4"] +texture = ExtResource("6_wb84l") + +[node name="LeftStickClick" parent="HBoxContainer/Controls" index="5"] +texture = ExtResource("7_en4bp") + +[node name="RightStick" parent="HBoxContainer/Controls" index="6"] +texture = ExtResource("8_3a0jg") + +[node name="RightStickClick" parent="HBoxContainer/Controls" index="7"] +texture = ExtResource("9_vu674") + +[node name="LeftBumper" parent="HBoxContainer/Controls" index="8"] +texture = ExtResource("10_4dsgt") + +[node name="RightBumper" parent="HBoxContainer/Controls" index="9"] +texture = ExtResource("11_3efc4") + +[node name="LeftTrigger" parent="HBoxContainer/Controls" index="10"] +texture = ExtResource("12_bylwu") + +[node name="RightTrigger" parent="HBoxContainer/Controls" index="11"] +texture = ExtResource("13_viufm") + +[node name="DpadUp" parent="HBoxContainer/Controls" index="12"] +texture = ExtResource("14_2uufq") + +[node name="DpadLeft" parent="HBoxContainer/Controls" index="13"] +texture = ExtResource("15_52cih") + +[node name="DpadRight" parent="HBoxContainer/Controls" index="14"] +texture = ExtResource("16_j6krd") + +[node name="DpadDown" parent="HBoxContainer/Controls" index="15"] +texture = ExtResource("17_03a3w") + +[node name="Start" parent="HBoxContainer/Controls" index="16"] +texture = ExtResource("18_qlpxc") + +[node name="Misc1" parent="HBoxContainer/Controls" index="17"] +texture = ExtResource("19_24yjp") + +[node name="Back" parent="HBoxContainer/Controls" index="18"] +texture = ExtResource("20_0bc5x") diff --git a/addons/guide/ui/renderers/joy/icons/button_empty.png b/addons/guide/ui/renderers/joy/icons/button_empty.png new file mode 100644 index 0000000..800bee0 Binary files /dev/null and b/addons/guide/ui/renderers/joy/icons/button_empty.png differ diff --git a/addons/guide/ui/renderers/joy/icons/button_empty.png.import b/addons/guide/ui/renderers/joy/icons/button_empty.png.import new file mode 100644 index 0000000..e2bc208 --- /dev/null +++ b/addons/guide/ui/renderers/joy/icons/button_empty.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://veqjcwokdukw" +path="res://.godot/imported/button_empty.png-123d9e156dcc9c2e5ff33e4ffbcd7884.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/joy/icons/button_empty.png" +dest_files=["res://.godot/imported/button_empty.png-123d9e156dcc9c2e5ff33e4ffbcd7884.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 diff --git a/addons/guide/ui/renderers/joy/icons/stick_empty.png b/addons/guide/ui/renderers/joy/icons/stick_empty.png new file mode 100644 index 0000000..ae363d2 Binary files /dev/null and b/addons/guide/ui/renderers/joy/icons/stick_empty.png differ diff --git a/addons/guide/ui/renderers/joy/icons/stick_empty.png.import b/addons/guide/ui/renderers/joy/icons/stick_empty.png.import new file mode 100644 index 0000000..8d805df --- /dev/null +++ b/addons/guide/ui/renderers/joy/icons/stick_empty.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://do001o6aysaxo" +path="res://.godot/imported/stick_empty.png-10fa96eb31f6946670d6998f8648c1db.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/joy/icons/stick_empty.png" +dest_files=["res://.godot/imported/stick_empty.png-10fa96eb31f6946670d6998f8648c1db.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 diff --git a/addons/guide/ui/renderers/joy/joy_renderer.gd b/addons/guide/ui/renderers/joy/joy_renderer.gd new file mode 100644 index 0000000..92bdec1 --- /dev/null +++ b/addons/guide/ui/renderers/joy/joy_renderer.gd @@ -0,0 +1,69 @@ +@tool +extends GUIDEIconRenderer + +@onready var _stick:Control = %Stick +@onready var _button:Control = %Button +@onready var _text:Control = %Text +@onready var _directions:Control = %Directions +@onready var _horizontal:Control = %Horizontal +@onready var _vertical:Control = %Vertical + + + +func supports(input:GUIDEInput) -> bool: + return input is GUIDEInputJoyBase + +func render(input:GUIDEInput) -> void: + _stick.visible = false + _button.visible = false + _directions.visible = false + _horizontal.visible = false + _vertical.visible = false + _text.text = "" + + + if input is GUIDEInputJoyAxis1D: + _stick.visible = true + match input.axis: + JOY_AXIS_LEFT_X: + _directions.visible = true + _text.text = "1" + _horizontal.visible = true + JOY_AXIS_RIGHT_X: + _directions.visible = true + _text.text = "2" + _horizontal.visible = true + JOY_AXIS_LEFT_Y: + _directions.visible = true + _text.text = "1" + _vertical.visible = true + JOY_AXIS_RIGHT_Y: + _directions.visible = true + _text.text = "2" + _vertical.visible = true + JOY_AXIS_TRIGGER_LEFT: + _text.text = "3" + JOY_AXIS_TRIGGER_RIGHT: + _text.text = "4" + + + + if input is GUIDEInputJoyAxis2D: + _stick.visible = true + match input.x: + JOY_AXIS_LEFT_X, JOY_AXIS_LEFT_Y: + _text.text = "1" + JOY_AXIS_RIGHT_X, JOY_AXIS_RIGHT_Y: + _text.text = "2" + _: + # well we don't know really what this is but what can we do. + _text.text = str(input.x + input.y) + + if input is GUIDEInputJoyButton: + _button.visible = true + _text.text = str(input.button) + + call("queue_sort") + +func cache_key(input:GUIDEInput) -> String: + return "a9ced629-de65-4c31-9de0-8e4cbf88a2e0" + input.to_string() diff --git a/addons/guide/ui/renderers/joy/joy_renderer.tscn b/addons/guide/ui/renderers/joy/joy_renderer.tscn new file mode 100644 index 0000000..a1dd98e --- /dev/null +++ b/addons/guide/ui/renderers/joy/joy_renderer.tscn @@ -0,0 +1,63 @@ +[gd_scene load_steps=7 format=3 uid="uid://c6sqf8rur1wss"] + +[ext_resource type="Script" path="res://addons/guide/ui/renderers/joy/joy_renderer.gd" id="1_u7brn"] +[ext_resource type="Texture2D" uid="uid://do001o6aysaxo" path="res://addons/guide/ui/renderers/joy/icons/stick_empty.png" id="2_23u2k"] +[ext_resource type="Texture2D" uid="uid://veqjcwokdukw" path="res://addons/guide/ui/renderers/joy/icons/button_empty.png" id="3_7qfbp"] +[ext_resource type="FontFile" uid="uid://cu8bvod6tnnwr" path="res://addons/guide/ui/renderers/keyboard/Lato-Black.ttf" id="4_otp86"] +[ext_resource type="Texture2D" uid="uid://bmgxqbypegjxh" path="res://addons/guide/ui/renderers/textures/arrow_horizontal.svg" id="5_81uyo"] +[ext_resource type="Texture2D" uid="uid://bu5nlug6uf03w" path="res://addons/guide/ui/renderers/textures/arrow_vertical.svg" id="6_syx8c"] + +[node name="JoyRenderer" type="MarginContainer"] +offset_right = 100.0 +offset_bottom = 100.0 +size_flags_horizontal = 0 +script = ExtResource("1_u7brn") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Controls" type="MarginContainer" parent="HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(100, 100) +layout_mode = 2 + +[node name="Stick" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("2_23u2k") +stretch_mode = 4 + +[node name="Button" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("3_7qfbp") +stretch_mode = 4 + +[node name="Text" type="Label" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 4 +theme_override_colors/font_color = Color(0.843137, 0.843137, 0.843137, 1) +theme_override_fonts/font = ExtResource("4_otp86") +theme_override_font_sizes/font_size = 50 +text = "1" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="Directions" type="MarginContainer" parent="HBoxContainer"] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(100, 100) +layout_mode = 2 + +[node name="Horizontal" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("5_81uyo") +stretch_mode = 4 + +[node name="Vertical" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("6_syx8c") +stretch_mode = 4 diff --git a/addons/guide/ui/renderers/keyboard/Lato-Black.ttf b/addons/guide/ui/renderers/keyboard/Lato-Black.ttf new file mode 100644 index 0000000..4340502 Binary files /dev/null and b/addons/guide/ui/renderers/keyboard/Lato-Black.ttf differ diff --git a/addons/guide/ui/renderers/keyboard/Lato-Black.ttf.import b/addons/guide/ui/renderers/keyboard/Lato-Black.ttf.import new file mode 100644 index 0000000..f2b96dd --- /dev/null +++ b/addons/guide/ui/renderers/keyboard/Lato-Black.ttf.import @@ -0,0 +1,34 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://cu8bvod6tnnwr" +path="res://.godot/imported/Lato-Black.ttf-dd70fb4540a062e6fd25f6b3cb73f785.fontdata" + +[deps] + +source_file="res://addons/guide/ui/renderers/keyboard/Lato-Black.ttf" +dest_files=["res://.godot/imported/Lato-Black.ttf-dd70fb4540a062e6fd25f6b3cb73f785.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/addons/guide/ui/renderers/keyboard/icons/Blank_White_Normal.png b/addons/guide/ui/renderers/keyboard/icons/Blank_White_Normal.png new file mode 100644 index 0000000..beee975 Binary files /dev/null and b/addons/guide/ui/renderers/keyboard/icons/Blank_White_Normal.png differ diff --git a/addons/guide/ui/renderers/keyboard/icons/Blank_White_Normal.png.import b/addons/guide/ui/renderers/keyboard/icons/Blank_White_Normal.png.import new file mode 100644 index 0000000..99d4b10 --- /dev/null +++ b/addons/guide/ui/renderers/keyboard/icons/Blank_White_Normal.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b3x586os8uuwb" +path="res://.godot/imported/Blank_White_Normal.png-71b5933a92dfdd83fd323e35be33b3b2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/keyboard/icons/Blank_White_Normal.png" +dest_files=["res://.godot/imported/Blank_White_Normal.png-71b5933a92dfdd83fd323e35be33b3b2.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 diff --git a/addons/guide/ui/renderers/keyboard/key_renderer.gd b/addons/guide/ui/renderers/keyboard/key_renderer.gd new file mode 100644 index 0000000..3facf61 --- /dev/null +++ b/addons/guide/ui/renderers/keyboard/key_renderer.gd @@ -0,0 +1,17 @@ +@tool +extends GUIDEIconRenderer + +@onready var _label:Label = %Label + +func supports(input:GUIDEInput) -> bool: + return input is GUIDEInputKey + +func render(input:GUIDEInput) -> void: + var key:Key = input.key + var label_key:Key = DisplayServer.keyboard_get_label_from_physical(key) + _label.text = OS.get_keycode_string(label_key).strip_edges() + size = Vector2.ZERO + call("queue_sort") + +func cache_key(input:GUIDEInput) -> String: + return "ed6923d5-4115-44bd-b35e-2c4102ffc83e" + input.to_string() diff --git a/addons/guide/ui/renderers/keyboard/key_renderer.tscn b/addons/guide/ui/renderers/keyboard/key_renderer.tscn new file mode 100644 index 0000000..eacb5b9 --- /dev/null +++ b/addons/guide/ui/renderers/keyboard/key_renderer.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=4 format=3 uid="uid://toty2e3yx26l"] + +[ext_resource type="Script" path="res://addons/guide/ui/renderers/keyboard/key_renderer.gd" id="1_tm2sd"] +[ext_resource type="Texture2D" uid="uid://b3x586os8uuwb" path="res://addons/guide/ui/renderers/keyboard/icons/Blank_White_Normal.png" id="2_myc15"] +[ext_resource type="FontFile" uid="uid://cu8bvod6tnnwr" path="res://addons/guide/ui/renderers/keyboard/Lato-Black.ttf" id="3_d3uds"] + +[node name="KeyRenderer" type="MarginContainer"] +custom_minimum_size = Vector2(100, 100) +offset_right = 267.0 +offset_bottom = 100.0 +size_flags_horizontal = 0 +size_flags_vertical = 0 +script = ExtResource("1_tm2sd") + +[node name="NinePatchRect" type="NinePatchRect" parent="."] +layout_mode = 2 +texture = ExtResource("2_myc15") +region_rect = Rect2(10, 10, 80, 80) +patch_margin_left = 29 +patch_margin_top = 30 +patch_margin_right = 29 +patch_margin_bottom = 29 + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +theme_override_constants/margin_left = 30 +theme_override_constants/margin_right = 30 + +[node name="Label" type="Label" parent="MarginContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_colors/font_color = Color(0.25098, 0.25098, 0.25098, 1) +theme_override_fonts/font = ExtResource("3_d3uds") +theme_override_font_sizes/font_size = 45 +text = "Long Long Long" +horizontal_alignment = 1 diff --git a/addons/guide/ui/renderers/misc/action_renderer.gd b/addons/guide/ui/renderers/misc/action_renderer.gd new file mode 100644 index 0000000..c39f8a6 --- /dev/null +++ b/addons/guide/ui/renderers/misc/action_renderer.gd @@ -0,0 +1,11 @@ +@tool +extends GUIDEIconRenderer + +func supports(input:GUIDEInput) -> bool: + return input is GUIDEInputAction + +func render(input:GUIDEInput) -> void: + pass + +func cache_key(input:GUIDEInput) -> String: + return "0ecd6608-ba3c-4fc2-83f7-ad61736f1106" # we only have one output, so same cache key diff --git a/addons/guide/ui/renderers/misc/action_renderer.tscn b/addons/guide/ui/renderers/misc/action_renderer.tscn new file mode 100644 index 0000000..88cb452 --- /dev/null +++ b/addons/guide/ui/renderers/misc/action_renderer.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=3 format=3 uid="uid://ortn6jb3wljf"] + +[ext_resource type="Script" path="res://addons/guide/ui/renderers/misc/action_renderer.gd" id="1_140q4"] +[ext_resource type="Texture2D" uid="uid://diwkvjkss2ie" path="res://addons/guide/ui/renderers/textures/action.svg" id="2_uqvia"] + +[node name="ActionRenderer" type="MarginContainer"] +offset_right = 512.0 +offset_bottom = 512.0 +size_flags_horizontal = 0 +script = ExtResource("1_140q4") + +[node name="Action" type="TextureRect" parent="."] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("2_uqvia") +stretch_mode = 4 diff --git a/addons/guide/ui/renderers/misc/fallback_renderer.gd b/addons/guide/ui/renderers/misc/fallback_renderer.gd new file mode 100644 index 0000000..4fa78e1 --- /dev/null +++ b/addons/guide/ui/renderers/misc/fallback_renderer.gd @@ -0,0 +1,11 @@ +@tool +extends GUIDEIconRenderer + +func supports(input:GUIDEInput) -> bool: + return true + +func render(input:GUIDEInput) -> void: + pass + +func cache_key(input:GUIDEInput) -> String: + return "2e130e8b-d5b3-478c-af65-53415adfd6bb" # we only have one output, so same cache key diff --git a/addons/guide/ui/renderers/misc/fallback_renderer.tscn b/addons/guide/ui/renderers/misc/fallback_renderer.tscn new file mode 100644 index 0000000..106c8d8 --- /dev/null +++ b/addons/guide/ui/renderers/misc/fallback_renderer.tscn @@ -0,0 +1,20 @@ +[gd_scene load_steps=3 format=3 uid="uid://bqf4yoind3a82"] + +[ext_resource type="Script" path="res://addons/guide/ui/renderers/misc/fallback_renderer.gd" id="1_mgm3k"] +[ext_resource type="FontFile" uid="uid://cu8bvod6tnnwr" path="res://addons/guide/ui/renderers/keyboard/Lato-Black.ttf" id="2_5hk8u"] + +[node name="FallbackRenderer" type="MarginContainer"] +offset_right = 512.0 +offset_bottom = 512.0 +size_flags_horizontal = 0 +script = ExtResource("1_mgm3k") +priority = 100 + +[node name="Label" type="Label" parent="."] +custom_minimum_size = Vector2(512, 512) +layout_mode = 2 +theme_override_fonts/font = ExtResource("2_5hk8u") +theme_override_font_sizes/font_size = 350 +text = "?" +horizontal_alignment = 1 +vertical_alignment = 1 diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Cursor.png b/addons/guide/ui/renderers/mouse/icons/Mouse_Cursor.png new file mode 100644 index 0000000..8d52353 Binary files /dev/null and b/addons/guide/ui/renderers/mouse/icons/Mouse_Cursor.png differ diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Cursor.png.import b/addons/guide/ui/renderers/mouse/icons/Mouse_Cursor.png.import new file mode 100644 index 0000000..21c5623 --- /dev/null +++ b/addons/guide/ui/renderers/mouse/icons/Mouse_Cursor.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ci7icm3q4l1sg" +path="res://.godot/imported/Mouse_Cursor.png-d260e60db8690d81bb10201ace09e70f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/mouse/icons/Mouse_Cursor.png" +dest_files=["res://.godot/imported/Mouse_Cursor.png-d260e60db8690d81bb10201ace09e70f.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 diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Left_Key_Light.png b/addons/guide/ui/renderers/mouse/icons/Mouse_Left_Key_Light.png new file mode 100644 index 0000000..22983fa Binary files /dev/null and b/addons/guide/ui/renderers/mouse/icons/Mouse_Left_Key_Light.png differ diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Left_Key_Light.png.import b/addons/guide/ui/renderers/mouse/icons/Mouse_Left_Key_Light.png.import new file mode 100644 index 0000000..e6fb06e --- /dev/null +++ b/addons/guide/ui/renderers/mouse/icons/Mouse_Left_Key_Light.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vvgpheda22ew" +path="res://.godot/imported/Mouse_Left_Key_Light.png-8c9c47fe23d850a53ee5b259032ff1e7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/mouse/icons/Mouse_Left_Key_Light.png" +dest_files=["res://.godot/imported/Mouse_Left_Key_Light.png-8c9c47fe23d850a53ee5b259032ff1e7.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 diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Middle_Key_Light.png b/addons/guide/ui/renderers/mouse/icons/Mouse_Middle_Key_Light.png new file mode 100644 index 0000000..d3298c1 Binary files /dev/null and b/addons/guide/ui/renderers/mouse/icons/Mouse_Middle_Key_Light.png differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png.import b/addons/guide/ui/renderers/mouse/icons/Mouse_Middle_Key_Light.png.import similarity index 63% rename from examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png.import rename to addons/guide/ui/renderers/mouse/icons/Mouse_Middle_Key_Light.png.import index 10587db..74951c7 100644 --- a/examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png.import +++ b/addons/guide/ui/renderers/mouse/icons/Mouse_Middle_Key_Light.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://bc34cuc50as8f" -path="res://.godot/imported/tex_metal_corner_outer.png-6ea6aecab21ef2cdfa9c20ae8389ee06.ctex" +uid="uid://bmj244x0jn7v2" +path="res://.godot/imported/Mouse_Middle_Key_Light.png-d1b621d65964bf35e881bf5a749d0470.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png" -dest_files=["res://.godot/imported/tex_metal_corner_outer.png-6ea6aecab21ef2cdfa9c20ae8389ee06.ctex"] +source_file="res://addons/guide/ui/renderers/mouse/icons/Mouse_Middle_Key_Light.png" +dest_files=["res://.godot/imported/Mouse_Middle_Key_Light.png-d1b621d65964bf35e881bf5a749d0470.ctex"] [params] diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Right_Key_Light.png b/addons/guide/ui/renderers/mouse/icons/Mouse_Right_Key_Light.png new file mode 100644 index 0000000..8106df7 Binary files /dev/null and b/addons/guide/ui/renderers/mouse/icons/Mouse_Right_Key_Light.png differ diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Right_Key_Light.png.import b/addons/guide/ui/renderers/mouse/icons/Mouse_Right_Key_Light.png.import new file mode 100644 index 0000000..f44ea7f --- /dev/null +++ b/addons/guide/ui/renderers/mouse/icons/Mouse_Right_Key_Light.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8bsyguf4qw6f" +path="res://.godot/imported/Mouse_Right_Key_Light.png-f1130bc98a1b33064099609790f7efff.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/mouse/icons/Mouse_Right_Key_Light.png" +dest_files=["res://.godot/imported/Mouse_Right_Key_Light.png-f1130bc98a1b33064099609790f7efff.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 diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_1_Light.png b/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_1_Light.png new file mode 100644 index 0000000..2011ef0 Binary files /dev/null and b/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_1_Light.png differ diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_1_Light.png.import b/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_1_Light.png.import new file mode 100644 index 0000000..8bf18da --- /dev/null +++ b/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_1_Light.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqxly0g8pftxa" +path="res://.godot/imported/Mouse_Side_Key_1_Light.png-1e0810994bec8c12ac686f4c33006236.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_1_Light.png" +dest_files=["res://.godot/imported/Mouse_Side_Key_1_Light.png-1e0810994bec8c12ac686f4c33006236.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 diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_2_Light.png b/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_2_Light.png new file mode 100644 index 0000000..a2fd2a0 Binary files /dev/null and b/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_2_Light.png differ diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_2_Light.png.import b/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_2_Light.png.import new file mode 100644 index 0000000..65b8da2 --- /dev/null +++ b/addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_2_Light.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://je8rm7jk2nxd" +path="res://.godot/imported/Mouse_Side_Key_2_Light.png-3a47028a83b486166e55c8b465b98934.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_2_Light.png" +dest_files=["res://.godot/imported/Mouse_Side_Key_2_Light.png-3a47028a83b486166e55c8b465b98934.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 diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Simple_Key_Light.png b/addons/guide/ui/renderers/mouse/icons/Mouse_Simple_Key_Light.png new file mode 100644 index 0000000..7891ea4 Binary files /dev/null and b/addons/guide/ui/renderers/mouse/icons/Mouse_Simple_Key_Light.png differ diff --git a/addons/guide/ui/renderers/mouse/icons/Mouse_Simple_Key_Light.png.import b/addons/guide/ui/renderers/mouse/icons/Mouse_Simple_Key_Light.png.import new file mode 100644 index 0000000..4799ca4 --- /dev/null +++ b/addons/guide/ui/renderers/mouse/icons/Mouse_Simple_Key_Light.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b3uxk5agbpmab" +path="res://.godot/imported/Mouse_Simple_Key_Light.png-0d9fe3a005ffb8a731da9e9c204556cb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/mouse/icons/Mouse_Simple_Key_Light.png" +dest_files=["res://.godot/imported/Mouse_Simple_Key_Light.png-0d9fe3a005ffb8a731da9e9c204556cb.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 diff --git a/addons/guide/ui/renderers/mouse/mouse_renderer.gd b/addons/guide/ui/renderers/mouse/mouse_renderer.gd new file mode 100644 index 0000000..2671a99 --- /dev/null +++ b/addons/guide/ui/renderers/mouse/mouse_renderer.gd @@ -0,0 +1,87 @@ +@tool +extends GUIDEIconRenderer + +@onready var _controls:Control = %Controls +@onready var _mouse_left:Control = %MouseLeft +@onready var _mouse_right:Control = %MouseRight +@onready var _mouse_middle:Control = %MouseMiddle +@onready var _mouse_side_a:Control = %MouseSideA +@onready var _mouse_side_b:Control = %MouseSideB +@onready var _mouse_blank:Control = %MouseBlank +@onready var _mouse_cursor:Control = %MouseCursor + + +@onready var _directions:Control = %Directions +@onready var _left:Control = %Left +@onready var _right:Control = %Right +@onready var _up:Control = %Up +@onready var _down:Control = %Down +@onready var _horizontal:Control = %Horizontal +@onready var _vertical:Control = %Vertical + + + +func supports(input:GUIDEInput) -> bool: + return input is GUIDEInputMouseButton or \ + input is GUIDEInputMouseAxis1D or \ + input is GUIDEInputMouseAxis2D or \ + input is GUIDEInputMousePosition + + +func render(input:GUIDEInput) -> void: + for child in _controls.get_children(): + child.visible = false + for child in _directions.get_children(): + child.visible = false + + _directions.visible = false + + if input is GUIDEInputMouseButton: + match input.button: + MOUSE_BUTTON_LEFT: + _mouse_left.visible = true + MOUSE_BUTTON_RIGHT: + _mouse_right.visible = true + MOUSE_BUTTON_MIDDLE: + _mouse_middle.visible = true + MOUSE_BUTTON_WHEEL_UP: + _directions.visible = true + _up.visible = true + _mouse_middle.visible = true + MOUSE_BUTTON_WHEEL_DOWN: + _directions.visible = true + _down.visible = true + _mouse_middle.visible = true + MOUSE_BUTTON_WHEEL_LEFT: + _directions.visible = true + _left.visible = true + _mouse_middle.visible = true + MOUSE_BUTTON_WHEEL_RIGHT: + _directions.visible = true + _right.visible = true + _mouse_middle.visible = true + MOUSE_BUTTON_XBUTTON1: + _mouse_side_a.visible = true + MOUSE_BUTTON_XBUTTON2: + _mouse_side_b.visible = true + + if input is GUIDEInputMouseAxis1D: + if input.axis == GUIDEInputMouseAxis1D.GUIDEInputMouseAxis.X: + _mouse_blank.visible = true + _directions.visible = true + _horizontal.visible = true + else: + _mouse_blank.visible = true + _directions.visible = true + _vertical.visible = true + + if input is GUIDEInputMouseAxis2D: + _mouse_blank.visible = true + + if input is GUIDEInputMousePosition: + _mouse_cursor.visible = true + + call("queue_sort") + +func cache_key(input:GUIDEInput) -> String: + return "7e27520a-b6d8-4451-858d-e94330c82e85" + input.to_string() diff --git a/addons/guide/ui/renderers/mouse/mouse_renderer.tscn b/addons/guide/ui/renderers/mouse/mouse_renderer.tscn new file mode 100644 index 0000000..7e51e7d --- /dev/null +++ b/addons/guide/ui/renderers/mouse/mouse_renderer.tscn @@ -0,0 +1,124 @@ +[gd_scene load_steps=15 format=3 uid="uid://bfl6dbw21xqs1"] + +[ext_resource type="Script" path="res://addons/guide/ui/renderers/mouse/mouse_renderer.gd" id="1_amutf"] +[ext_resource type="Texture2D" uid="uid://vvgpheda22ew" path="res://addons/guide/ui/renderers/mouse/icons/Mouse_Left_Key_Light.png" id="2_6vk7n"] +[ext_resource type="Texture2D" uid="uid://b8bsyguf4qw6f" path="res://addons/guide/ui/renderers/mouse/icons/Mouse_Right_Key_Light.png" id="3_aaqrj"] +[ext_resource type="Texture2D" uid="uid://bmj244x0jn7v2" path="res://addons/guide/ui/renderers/mouse/icons/Mouse_Middle_Key_Light.png" id="4_gprek"] +[ext_resource type="Texture2D" uid="uid://bqxly0g8pftxa" path="res://addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_1_Light.png" id="6_adi64"] +[ext_resource type="Texture2D" uid="uid://1swh072gtbb4" path="res://addons/guide/ui/renderers/textures/arrow_left.svg" id="6_fo4h0"] +[ext_resource type="Texture2D" uid="uid://je8rm7jk2nxd" path="res://addons/guide/ui/renderers/mouse/icons/Mouse_Side_Key_2_Light.png" id="7_bbgo7"] +[ext_resource type="Texture2D" uid="uid://cjvs04qsrj8ap" path="res://addons/guide/ui/renderers/textures/arrow_right.svg" id="7_t242p"] +[ext_resource type="Texture2D" uid="uid://ni6lsbx1d2hf" path="res://addons/guide/ui/renderers/textures/arrow_up.svg" id="8_a7prs"] +[ext_resource type="Texture2D" uid="uid://ci7icm3q4l1sg" path="res://addons/guide/ui/renderers/mouse/icons/Mouse_Cursor.png" id="8_g4vq6"] +[ext_resource type="Texture2D" uid="uid://oq2vvwgbdsh7" path="res://addons/guide/ui/renderers/textures/arrow_down.svg" id="9_dfyjd"] +[ext_resource type="Texture2D" uid="uid://bmgxqbypegjxh" path="res://addons/guide/ui/renderers/textures/arrow_horizontal.svg" id="12_xdqh7"] +[ext_resource type="Texture2D" uid="uid://b3uxk5agbpmab" path="res://addons/guide/ui/renderers/mouse/icons/Mouse_Simple_Key_Light.png" id="13_1bw2l"] +[ext_resource type="Texture2D" uid="uid://bu5nlug6uf03w" path="res://addons/guide/ui/renderers/textures/arrow_vertical.svg" id="13_yoogt"] + +[node name="MouseRenderer" type="MarginContainer"] +offset_right = 100.0 +offset_bottom = 100.0 +size_flags_horizontal = 0 +script = ExtResource("1_amutf") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 + +[node name="Controls" type="MarginContainer" parent="HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(100, 100) +layout_mode = 2 + +[node name="MouseBlank" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("13_1bw2l") +stretch_mode = 4 + +[node name="MouseLeft" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("2_6vk7n") +stretch_mode = 4 + +[node name="MouseRight" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("3_aaqrj") +stretch_mode = 4 + +[node name="MouseMiddle" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("4_gprek") +stretch_mode = 4 + +[node name="MouseSideA" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("6_adi64") +stretch_mode = 4 + +[node name="MouseSideB" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("7_bbgo7") +stretch_mode = 4 + +[node name="MouseCursor" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("8_g4vq6") +stretch_mode = 4 + +[node name="Directions" type="MarginContainer" parent="HBoxContainer"] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(100, 100) +layout_mode = 2 + +[node name="Left" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("6_fo4h0") +stretch_mode = 4 + +[node name="Right" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("7_t242p") +stretch_mode = 4 + +[node name="Up" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("8_a7prs") +stretch_mode = 4 + +[node name="Down" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("9_dfyjd") +stretch_mode = 4 + +[node name="Horizontal" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("12_xdqh7") +stretch_mode = 4 + +[node name="Vertical" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("13_yoogt") +stretch_mode = 4 diff --git a/addons/guide/ui/renderers/textures/action.svg b/addons/guide/ui/renderers/textures/action.svg new file mode 100644 index 0000000..1da724c --- /dev/null +++ b/addons/guide/ui/renderers/textures/action.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/addons/guide/ui/renderers/textures/action.svg.import b/addons/guide/ui/renderers/textures/action.svg.import new file mode 100644 index 0000000..7c0aa8d --- /dev/null +++ b/addons/guide/ui/renderers/textures/action.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://diwkvjkss2ie" +path="res://.godot/imported/action.svg-6100da2ab8ea5d289c6e91ccdfb53aca.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/textures/action.svg" +dest_files=["res://.godot/imported/action.svg-6100da2ab8ea5d289c6e91ccdfb53aca.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/ui/renderers/textures/arrow_all_directions.svg b/addons/guide/ui/renderers/textures/arrow_all_directions.svg new file mode 100644 index 0000000..c0053b6 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_all_directions.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/guide/ui/renderers/textures/arrow_all_directions.svg.import b/addons/guide/ui/renderers/textures/arrow_all_directions.svg.import new file mode 100644 index 0000000..20bd950 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_all_directions.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dwb1h8sfsccyy" +path="res://.godot/imported/arrow_all_directions.svg-c87a4938e66e69435ad57c677b38771f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/textures/arrow_all_directions.svg" +dest_files=["res://.godot/imported/arrow_all_directions.svg-c87a4938e66e69435ad57c677b38771f.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/ui/renderers/textures/arrow_down.svg b/addons/guide/ui/renderers/textures/arrow_down.svg new file mode 100644 index 0000000..b1a193a --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_down.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/guide/ui/renderers/textures/arrow_down.svg.import b/addons/guide/ui/renderers/textures/arrow_down.svg.import new file mode 100644 index 0000000..f624ed8 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_down.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://oq2vvwgbdsh7" +path="res://.godot/imported/arrow_down.svg-88a3b47c68c37638cef21944ad9cda50.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/textures/arrow_down.svg" +dest_files=["res://.godot/imported/arrow_down.svg-88a3b47c68c37638cef21944ad9cda50.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/ui/renderers/textures/arrow_horizontal.svg b/addons/guide/ui/renderers/textures/arrow_horizontal.svg new file mode 100644 index 0000000..ae0146f --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_horizontal.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/guide/ui/renderers/textures/arrow_horizontal.svg.import b/addons/guide/ui/renderers/textures/arrow_horizontal.svg.import new file mode 100644 index 0000000..8975345 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_horizontal.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bmgxqbypegjxh" +path="res://.godot/imported/arrow_horizontal.svg-5fd469f78a3e46cba20723a7b243bca1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/textures/arrow_horizontal.svg" +dest_files=["res://.godot/imported/arrow_horizontal.svg-5fd469f78a3e46cba20723a7b243bca1.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/ui/renderers/textures/arrow_left.svg b/addons/guide/ui/renderers/textures/arrow_left.svg new file mode 100644 index 0000000..9f94969 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_left.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/guide/ui/renderers/textures/arrow_left.svg.import b/addons/guide/ui/renderers/textures/arrow_left.svg.import new file mode 100644 index 0000000..2b22128 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_left.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://1swh072gtbb4" +path="res://.godot/imported/arrow_left.svg-2a189e6eec3713a64220cf9427e1f45c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/textures/arrow_left.svg" +dest_files=["res://.godot/imported/arrow_left.svg-2a189e6eec3713a64220cf9427e1f45c.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/ui/renderers/textures/arrow_right.svg b/addons/guide/ui/renderers/textures/arrow_right.svg new file mode 100644 index 0000000..7516511 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_right.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/guide/ui/renderers/textures/arrow_right.svg.import b/addons/guide/ui/renderers/textures/arrow_right.svg.import new file mode 100644 index 0000000..2b784e3 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_right.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cjvs04qsrj8ap" +path="res://.godot/imported/arrow_right.svg-83b2fe427227f253ed212a8b1c56acb4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/textures/arrow_right.svg" +dest_files=["res://.godot/imported/arrow_right.svg-83b2fe427227f253ed212a8b1c56acb4.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/ui/renderers/textures/arrow_up.svg b/addons/guide/ui/renderers/textures/arrow_up.svg new file mode 100644 index 0000000..8b37520 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_up.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/guide/ui/renderers/textures/arrow_up.svg.import b/addons/guide/ui/renderers/textures/arrow_up.svg.import new file mode 100644 index 0000000..83e63ee --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_up.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ni6lsbx1d2hf" +path="res://.godot/imported/arrow_up.svg-56e16fd95d307eb9666c8ac4e78e2b97.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/textures/arrow_up.svg" +dest_files=["res://.godot/imported/arrow_up.svg-56e16fd95d307eb9666c8ac4e78e2b97.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/ui/renderers/textures/arrow_vertical.svg b/addons/guide/ui/renderers/textures/arrow_vertical.svg new file mode 100644 index 0000000..2bf3493 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_vertical.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/guide/ui/renderers/textures/arrow_vertical.svg.import b/addons/guide/ui/renderers/textures/arrow_vertical.svg.import new file mode 100644 index 0000000..7d87170 --- /dev/null +++ b/addons/guide/ui/renderers/textures/arrow_vertical.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bu5nlug6uf03w" +path="res://.godot/imported/arrow_vertical.svg-17983361d36ac9313b8d80f7240cf6aa.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/textures/arrow_vertical.svg" +dest_files=["res://.godot/imported/arrow_vertical.svg-17983361d36ac9313b8d80f7240cf6aa.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/guide/ui/renderers/touch/icons/touch_1_finger.png b/addons/guide/ui/renderers/touch/icons/touch_1_finger.png new file mode 100644 index 0000000..86ef0be Binary files /dev/null and b/addons/guide/ui/renderers/touch/icons/touch_1_finger.png differ diff --git a/addons/guide/ui/renderers/touch/icons/touch_1_finger.png.import b/addons/guide/ui/renderers/touch/icons/touch_1_finger.png.import new file mode 100644 index 0000000..15f71ab --- /dev/null +++ b/addons/guide/ui/renderers/touch/icons/touch_1_finger.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c5nwnp5cjny7m" +path="res://.godot/imported/touch_1_finger.png-c21ed1a6c694f6c9460ef451efcf36e2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/touch/icons/touch_1_finger.png" +dest_files=["res://.godot/imported/touch_1_finger.png-c21ed1a6c694f6c9460ef451efcf36e2.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 diff --git a/addons/guide/ui/renderers/touch/icons/touch_2_fingers.png b/addons/guide/ui/renderers/touch/icons/touch_2_fingers.png new file mode 100644 index 0000000..354ff8d Binary files /dev/null and b/addons/guide/ui/renderers/touch/icons/touch_2_fingers.png differ diff --git a/addons/guide/ui/renderers/touch/icons/touch_2_fingers.png.import b/addons/guide/ui/renderers/touch/icons/touch_2_fingers.png.import new file mode 100644 index 0000000..5e7dfd6 --- /dev/null +++ b/addons/guide/ui/renderers/touch/icons/touch_2_fingers.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bllhe78a1yo6" +path="res://.godot/imported/touch_2_fingers.png-f5e5340b938b807b9249837228cb3c96.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/touch/icons/touch_2_fingers.png" +dest_files=["res://.godot/imported/touch_2_fingers.png-f5e5340b938b807b9249837228cb3c96.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 diff --git a/addons/guide/ui/renderers/touch/icons/touch_3_fingers.png b/addons/guide/ui/renderers/touch/icons/touch_3_fingers.png new file mode 100644 index 0000000..09a07d9 Binary files /dev/null and b/addons/guide/ui/renderers/touch/icons/touch_3_fingers.png differ diff --git a/addons/guide/ui/renderers/touch/icons/touch_3_fingers.png.import b/addons/guide/ui/renderers/touch/icons/touch_3_fingers.png.import new file mode 100644 index 0000000..180b468 --- /dev/null +++ b/addons/guide/ui/renderers/touch/icons/touch_3_fingers.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwhqf2nmm5q1w" +path="res://.godot/imported/touch_3_fingers.png-1b0a5171a90b9f0d4adf18b2d204fed6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/touch/icons/touch_3_fingers.png" +dest_files=["res://.godot/imported/touch_3_fingers.png-1b0a5171a90b9f0d4adf18b2d204fed6.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 diff --git a/addons/guide/ui/renderers/touch/icons/touch_4_fingers.png b/addons/guide/ui/renderers/touch/icons/touch_4_fingers.png new file mode 100644 index 0000000..288c40c Binary files /dev/null and b/addons/guide/ui/renderers/touch/icons/touch_4_fingers.png differ diff --git a/addons/guide/ui/renderers/touch/icons/touch_4_fingers.png.import b/addons/guide/ui/renderers/touch/icons/touch_4_fingers.png.import new file mode 100644 index 0000000..02e6cd4 --- /dev/null +++ b/addons/guide/ui/renderers/touch/icons/touch_4_fingers.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cjw5m42gufghr" +path="res://.godot/imported/touch_4_fingers.png-feb0257c01dc7e2234eb7bd7feabd57d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/touch/icons/touch_4_fingers.png" +dest_files=["res://.godot/imported/touch_4_fingers.png-feb0257c01dc7e2234eb7bd7feabd57d.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 diff --git a/addons/guide/ui/renderers/touch/icons/touch_rotate.png b/addons/guide/ui/renderers/touch/icons/touch_rotate.png new file mode 100644 index 0000000..6c1af5b Binary files /dev/null and b/addons/guide/ui/renderers/touch/icons/touch_rotate.png differ diff --git a/addons/guide/ui/renderers/touch/icons/touch_rotate.png.import b/addons/guide/ui/renderers/touch/icons/touch_rotate.png.import new file mode 100644 index 0000000..0975cd0 --- /dev/null +++ b/addons/guide/ui/renderers/touch/icons/touch_rotate.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxj4t5vjx7o3w" +path="res://.godot/imported/touch_rotate.png-22fc9d2b74759b3c29981107fa4d935b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/touch/icons/touch_rotate.png" +dest_files=["res://.godot/imported/touch_rotate.png-22fc9d2b74759b3c29981107fa4d935b.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 diff --git a/addons/guide/ui/renderers/touch/icons/touch_zoom.png b/addons/guide/ui/renderers/touch/icons/touch_zoom.png new file mode 100644 index 0000000..37e0cb8 Binary files /dev/null and b/addons/guide/ui/renderers/touch/icons/touch_zoom.png differ diff --git a/addons/guide/ui/renderers/touch/icons/touch_zoom.png.import b/addons/guide/ui/renderers/touch/icons/touch_zoom.png.import new file mode 100644 index 0000000..73bc5e3 --- /dev/null +++ b/addons/guide/ui/renderers/touch/icons/touch_zoom.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cutplj0nhphk" +path="res://.godot/imported/touch_zoom.png-6fb619cb5fcce5feede2a4a5f40428ee.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/guide/ui/renderers/touch/icons/touch_zoom.png" +dest_files=["res://.godot/imported/touch_zoom.png-6fb619cb5fcce5feede2a4a5f40428ee.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 diff --git a/addons/guide/ui/renderers/touch/touch_renderer.gd b/addons/guide/ui/renderers/touch/touch_renderer.gd new file mode 100644 index 0000000..ad2284e --- /dev/null +++ b/addons/guide/ui/renderers/touch/touch_renderer.gd @@ -0,0 +1,73 @@ +@tool +extends GUIDEIconRenderer + +const GUIDEInputTouchBase = preload("../../../inputs/guide_input_touch_base.gd") + +@onready var _controls:Control = %Controls +@onready var _1_finger:Control = %T1Finger +@onready var _2_finger:Control = %T2Fingers +@onready var _3_finger:Control = %T3Fingers +@onready var _4_finger:Control = %T4Fingers +@onready var _rotate:Control = %Rotate +@onready var _zoom:Control = %Zoom + + +@onready var _directions:Control = %Directions +@onready var _horizontal:Control = %Horizontal +@onready var _vertical:Control = %Vertical +@onready var _axis2d:Control = %Axis2D + + + +func supports(input:GUIDEInput) -> bool: + return input is GUIDEInputTouchAxis1D or \ + input is GUIDEInputTouchAxis2D or \ + input is GUIDEInputTouchPosition or \ + input is GUIDEInputTouchAngle or \ + input is GUIDEInputTouchDistance + + + +func render(input:GUIDEInput) -> void: + for child in _controls.get_children(): + child.visible = false + for child in _directions.get_children(): + child.visible = false + + _directions.visible = false + + if input is GUIDEInputTouchBase: + match input.finger_count: + 2: + _2_finger.visible = true + 3: + _3_finger.visible = true + 4: + _4_finger.visible = true + _: + # we have no icons for more than 4 fingers, so everything else gets + # the 1 finger icon + _1_finger.visible = true + + if input is GUIDEInputTouchAxis2D: + _directions.visible = true + _axis2d.visible = true + + if input is GUIDEInputTouchAxis1D: + _directions.visible = true + match input.axis: + GUIDEInputTouchAxis1D.GUIDEInputTouchAxis.X: + _horizontal.visible = true + GUIDEInputTouchAxis1D.GUIDEInputTouchAxis.X: + _vertical.visible = true + + if input is GUIDEInputTouchDistance: + _zoom.visible = true + + if input is GUIDEInputTouchAngle: + _rotate.visible = true + + call("queue_sort") + +func cache_key(input:GUIDEInput) -> String: + return "1f4c5082-d419-465f-aba8-f889caaff335" + input.to_string() diff --git a/addons/guide/ui/renderers/touch/touch_renderer.tscn b/addons/guide/ui/renderers/touch/touch_renderer.tscn new file mode 100644 index 0000000..b54a0e8 --- /dev/null +++ b/addons/guide/ui/renderers/touch/touch_renderer.tscn @@ -0,0 +1,93 @@ +[gd_scene load_steps=11 format=3 uid="uid://ykuou1deo5ub"] + +[ext_resource type="Script" path="res://addons/guide/ui/renderers/touch/touch_renderer.gd" id="1_heixj"] +[ext_resource type="Texture2D" uid="uid://c5nwnp5cjny7m" path="res://addons/guide/ui/renderers/touch/icons/touch_1_finger.png" id="2_4mplc"] +[ext_resource type="Texture2D" uid="uid://bllhe78a1yo6" path="res://addons/guide/ui/renderers/touch/icons/touch_2_fingers.png" id="3_0dcqu"] +[ext_resource type="Texture2D" uid="uid://bwhqf2nmm5q1w" path="res://addons/guide/ui/renderers/touch/icons/touch_3_fingers.png" id="4_mgq0v"] +[ext_resource type="Texture2D" uid="uid://cjw5m42gufghr" path="res://addons/guide/ui/renderers/touch/icons/touch_4_fingers.png" id="5_qoicp"] +[ext_resource type="Texture2D" uid="uid://bxj4t5vjx7o3w" path="res://addons/guide/ui/renderers/touch/icons/touch_rotate.png" id="6_4jaqi"] +[ext_resource type="Texture2D" uid="uid://cutplj0nhphk" path="res://addons/guide/ui/renderers/touch/icons/touch_zoom.png" id="7_gvy7l"] +[ext_resource type="Texture2D" uid="uid://bmgxqbypegjxh" path="res://addons/guide/ui/renderers/textures/arrow_horizontal.svg" id="8_m5om5"] +[ext_resource type="Texture2D" uid="uid://dwb1h8sfsccyy" path="res://addons/guide/ui/renderers/textures/arrow_all_directions.svg" id="9_5gr2q"] +[ext_resource type="Texture2D" uid="uid://bu5nlug6uf03w" path="res://addons/guide/ui/renderers/textures/arrow_vertical.svg" id="10_4vghq"] + +[node name="TouchRenderer" type="MarginContainer"] +offset_right = 100.0 +offset_bottom = 100.0 +size_flags_horizontal = 0 +script = ExtResource("1_heixj") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 + +[node name="Controls" type="MarginContainer" parent="HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(100, 100) +layout_mode = 2 + +[node name="T1Finger" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("2_4mplc") +stretch_mode = 4 + +[node name="T2Fingers" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("3_0dcqu") +stretch_mode = 4 + +[node name="T3Fingers" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("4_mgq0v") +stretch_mode = 4 + +[node name="T4Fingers" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("5_qoicp") +stretch_mode = 4 + +[node name="Rotate" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("6_4jaqi") +stretch_mode = 4 + +[node name="Zoom" type="TextureRect" parent="HBoxContainer/Controls"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = ExtResource("7_gvy7l") +stretch_mode = 4 + +[node name="Directions" type="MarginContainer" parent="HBoxContainer"] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(100, 100) +layout_mode = 2 + +[node name="Horizontal" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("8_m5om5") +stretch_mode = 4 + +[node name="Vertical" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("10_4vghq") +stretch_mode = 4 + +[node name="Axis2D" type="TextureRect" parent="HBoxContainer/Directions"] +unique_name_in_owner = true +layout_mode = 2 +texture = ExtResource("9_5gr2q") +stretch_mode = 4 diff --git a/addons/guide/ui/text_providers/controllers/controller_text_provider.gd b/addons/guide/ui/text_providers/controllers/controller_text_provider.gd new file mode 100644 index 0000000..3a569ee --- /dev/null +++ b/addons/guide/ui/text_providers/controllers/controller_text_provider.gd @@ -0,0 +1,115 @@ +extends GUIDETextProvider + +func _init(): + priority = -1 + +func _controller_names() -> Array[String]: + return [] + +func _a_button_name() -> String: + return "A" + +func _b_button_name() -> String: + return "B" + +func _x_button_name() -> String: + return "X" + +func _y_button_name() -> String: + return "Y" + +func _left_bumper_name() -> String: + return "LB" + +func _right_bumper_name() -> String: + return "RB" + +func _left_trigger_name() -> String: + return "LT" + +func _right_trigger_name() -> String: + return "RT" + +func _back_button_name() -> String: + return "Back" + +func _misc_1_button_name() -> String: + return "Misc 1" + +func _start_button_name() -> String: + return "Start" + + +func supports(input:GUIDEInput) -> bool: + var controller_name = GUIDEInputFormatter._joy_name_for_input(input) + if controller_name == "": + return false + + var haystack = controller_name.to_lower() + for needle in _controller_names(): + if haystack.contains(needle.to_lower()): + return true + + return false + +func _format(input:String) -> String: + return "[%s]" % [input] + + +func get_text(input:GUIDEInput) -> String: + if input is GUIDEInputJoyAxis1D: + match input.axis: + JOY_AXIS_LEFT_X: + return _format(tr("Left Stick Horizontal")) + JOY_AXIS_LEFT_Y: + return _format(tr("Left Stick Vertical")) + JOY_AXIS_RIGHT_X: + return _format(tr("Right Stick Horizontal")) + JOY_AXIS_RIGHT_Y: + return _format(tr("Right Stick Vertical")) + JOY_AXIS_TRIGGER_LEFT: + return _format(tr(_left_trigger_name())) + JOY_AXIS_TRIGGER_RIGHT: + return _format(tr(_right_trigger_name())) + + if input is GUIDEInputJoyAxis2D: + match input.x: + JOY_AXIS_LEFT_X, JOY_AXIS_LEFT_Y: + return _format(tr("Left Stick")) + JOY_AXIS_RIGHT_X, JOY_AXIS_RIGHT_Y: + return _format(tr("Right Stick")) + + if input is GUIDEInputJoyButton: + match input.button: + JOY_BUTTON_A: + return _format(tr(_a_button_name())) + JOY_BUTTON_B: + return _format(tr(_b_button_name())) + JOY_BUTTON_X: + return _format(tr(_x_button_name())) + JOY_BUTTON_Y: + return _format(tr(_y_button_name())) + JOY_BUTTON_DPAD_LEFT: + return _format(tr("DPAD Left")) + JOY_BUTTON_DPAD_RIGHT: + return _format(tr("DPAD Right")) + JOY_BUTTON_DPAD_UP: + return _format(tr("DPAD Up")) + JOY_BUTTON_DPAD_DOWN: + return _format(tr("DPAD Down")) + JOY_BUTTON_LEFT_SHOULDER: + return _format(tr(_left_bumper_name())) + JOY_BUTTON_RIGHT_SHOULDER: + return _format(tr(_right_bumper_name())) + JOY_BUTTON_LEFT_STICK: + return _format(tr("Left Stick")) + JOY_BUTTON_RIGHT_STICK: + return _format(tr("Right Stick")) + JOY_BUTTON_BACK: + return _format(tr(_back_button_name())) + JOY_BUTTON_MISC1: + return _format(tr(_misc_1_button_name())) + JOY_BUTTON_START: + return _format(tr(_start_button_name())) + + return _format("??") diff --git a/addons/guide/ui/text_providers/controllers/playstation/playstation_controller_text_provider.gd b/addons/guide/ui/text_providers/controllers/playstation/playstation_controller_text_provider.gd new file mode 100644 index 0000000..786f145 --- /dev/null +++ b/addons/guide/ui/text_providers/controllers/playstation/playstation_controller_text_provider.gd @@ -0,0 +1,37 @@ +extends "res://addons/guide/ui/text_providers/controllers/controller_text_provider.gd" + +func _controller_names() -> Array[String]: + return ["DualSense", "DualShock", "Playstation", "PS3", "PS4", "PS5"] + +func _a_button_name() -> String: + return "Cross" + +func _b_button_name() -> String: + return "Circle" + +func _x_button_name() -> String: + return "Square" + +func _y_button_name() -> String: + return "Triangle" + +func _left_bumper_name() -> String: + return "L1" + +func _right_bumper_name() -> String: + return "R1" + +func _left_trigger_name() -> String: + return "L2" + +func _right_trigger_name() -> String: + return "R2" + +func _back_button_name() -> String: + return "Share" + +func _misc_1_button_name() -> String: + return "Microphone" + +func _start_button_name() -> String: + return "Options" diff --git a/addons/guide/ui/text_providers/controllers/switch/switch_controller_text_provider.gd b/addons/guide/ui/text_providers/controllers/switch/switch_controller_text_provider.gd new file mode 100644 index 0000000..97fbe5d --- /dev/null +++ b/addons/guide/ui/text_providers/controllers/switch/switch_controller_text_provider.gd @@ -0,0 +1,37 @@ +extends "res://addons/guide/ui/text_providers/controllers/controller_text_provider.gd" + +func _controller_names() -> Array[String]: + return ["Nintendo Switch"] + +func _a_button_name() -> String: + return "B" + +func _b_button_name() -> String: + return "A" + +func _x_button_name() -> String: + return "Y" + +func _y_button_name() -> String: + return "X" + +func _left_bumper_name() -> String: + return "L" + +func _right_bumper_name() -> String: + return "R" + +func _left_trigger_name() -> String: + return "ZL" + +func _right_trigger_name() -> String: + return "ZR" + +func _back_button_name() -> String: + return "-" + +func _misc_1_button_name() -> String: + return "Square" + +func _start_button_name() -> String: + return "+" diff --git a/addons/guide/ui/text_providers/controllers/xbox/xbox_controller_text_provider.gd b/addons/guide/ui/text_providers/controllers/xbox/xbox_controller_text_provider.gd new file mode 100644 index 0000000..1d044d7 --- /dev/null +++ b/addons/guide/ui/text_providers/controllers/xbox/xbox_controller_text_provider.gd @@ -0,0 +1,37 @@ +extends "res://addons/guide/ui/text_providers/controllers/controller_text_provider.gd" + +func _controller_names() -> Array[String]: + return ["XInput", "XBox"] + +func _a_button_name() -> String: + return "A" + +func _b_button_name() -> String: + return "B" + +func _x_button_name() -> String: + return "X" + +func _y_button_name() -> String: + return "Y" + +func _left_bumper_name() -> String: + return "LB" + +func _right_bumper_name() -> String: + return "RB" + +func _left_trigger_name() -> String: + return "LT" + +func _right_trigger_name() -> String: + return "RT" + +func _back_button_name() -> String: + return "View" + +func _misc_1_button_name() -> String: + return "Share" + +func _start_button_name() -> String: + return "Menu" diff --git a/addons/guide/ui/text_providers/default_text_provider.gd b/addons/guide/ui/text_providers/default_text_provider.gd new file mode 100644 index 0000000..c9ce6af --- /dev/null +++ b/addons/guide/ui/text_providers/default_text_provider.gd @@ -0,0 +1,141 @@ +extends GUIDETextProvider + +var _is_on_desktop:bool = false + +func _init(): + priority = 0 + _is_on_desktop = OS.has_feature("linuxbsd") or OS.has_feature("macos") or OS.has_feature("windows") + +func supports(input:GUIDEInput) -> bool: + return true + + +func _format(input:String) -> String: + return "[%s]" % [input] + + +func get_text(input:GUIDEInput) -> String: + if input is GUIDEInputKey: + var result:PackedStringArray = [] + if input.control: + var ctrl = GUIDEInputKey.new() + ctrl.key = KEY_CTRL + result.append(get_text(ctrl)) + if input.alt: + var alt = GUIDEInputKey.new() + alt.key = KEY_ALT + result.append(get_text(alt)) + if input.shift: + var shift = GUIDEInputKey.new() + shift.key = KEY_SHIFT + result.append(get_text(shift)) + if input.meta: + var meta = GUIDEInputKey.new() + meta.key = KEY_META + result.append(get_text(meta)) + + var the_key = input.key + + # if we are on desktop, translate the physical keycode into the actual label + # this is not supported on mobile, so we have to check + if _is_on_desktop: + the_key = DisplayServer.keyboard_get_label_from_physical(input.key) + + + result.append(_format(OS.get_keycode_string(the_key))) + return "+".join(result) + + if input is GUIDEInputMouseAxis1D: + match input.axis: + GUIDEInputMouseAxis1D.GUIDEInputMouseAxis.X: + return _format(tr("Mouse Left/Right")) + GUIDEInputMouseAxis1D.GUIDEInputMouseAxis.Y: + return _format(tr("Mouse Up/Down")) + + if input is GUIDEInputMouseAxis2D: + return _format(tr("Mouse")) + + if input is GUIDEInputMouseButton: + match input.button: + MOUSE_BUTTON_LEFT: + return _format(tr("Left Mouse Button")) + MOUSE_BUTTON_RIGHT: + return _format(tr("Right Mouse Button")) + MOUSE_BUTTON_MIDDLE: + return _format(tr("Middle Mouse Button")) + MOUSE_BUTTON_WHEEL_UP: + return _format(tr("Mouse Wheel Up")) + MOUSE_BUTTON_WHEEL_DOWN: + return _format(tr("Mouse Wheel Down")) + MOUSE_BUTTON_WHEEL_LEFT: + return _format(tr("Mouse Wheel Left")) + MOUSE_BUTTON_WHEEL_RIGHT: + return _format(tr("Mouse Wheel Right")) + MOUSE_BUTTON_XBUTTON1: + return _format(tr("Mouse Side 1")) + MOUSE_BUTTON_XBUTTON2: + return _format(tr("Mouse Side 2")) + + if input is GUIDEInputJoyAxis1D: + match input.axis: + JOY_AXIS_LEFT_X: + return _format(tr("Stick 1 Horizontal")) + JOY_AXIS_LEFT_Y: + return _format(tr("Stick 1 Vertical")) + JOY_AXIS_RIGHT_X: + return _format(tr("Stick 2 Horizontal")) + JOY_AXIS_RIGHT_Y: + return _format(tr("Stick 2 Vertical")) + JOY_AXIS_TRIGGER_LEFT: + return _format(tr("Axis 3")) + JOY_AXIS_TRIGGER_RIGHT: + return _format(tr("Axis 4")) + + if input is GUIDEInputJoyAxis2D: + match input.x: + JOY_AXIS_LEFT_X, JOY_AXIS_LEFT_Y: + return _format(tr("Stick 1")) + JOY_AXIS_RIGHT_X, JOY_AXIS_RIGHT_Y: + return _format(tr("Stick 2")) + + if input is GUIDEInputJoyButton: + return _format(tr("Joy %s") % [input.button]) + + + if input is GUIDEInputAction: + return _format(tr("Action %s") % ["?" if input.action == null else input.action._editor_name()]) + + if input is GUIDEInputAny: + var parts:Array[String] = [] + if input.joy: + parts.append(tr("Joy Button")) + if input.mouse: + parts.append(tr("Mouse Button")) + if input.keyboard: + parts.append(tr("Key")) + + return _format(tr("Any %s") % [ "/".join(parts) ] ) + + if input is GUIDEInputMousePosition: + return _format(tr("Mouse Position")) + + if input is GUIDEInputTouchPosition: + return _format(tr("Touch Position %s") % [input.finger_index if input.finger_index >= 0 else "Average"]) + + if input is GUIDEInputTouchAngle: + return _format(tr("Touch Angle")) + + if input is GUIDEInputTouchDistance: + return _format(tr("Touch Distance")) + + if input is GUIDEInputTouchAxis1D: + match input.axis: + GUIDEInputTouchAxis1D.GUIDEInputTouchAxis.X: + _format(tr("Touch Left/Right %s") % [input.finger_index if input.finger_index >= 0 else "Average"]) + GUIDEInputTouchAxis1D.GUIDEInputTouchAxis.Y: + _format(tr("Touch Up/Down %s") % [input.finger_index if input.finger_index >= 0 else "Average"]) + + if input is GUIDEInputTouchAxis2D: + return _format(tr("Touch Axis 2D %s") % [input.finger_index if input.finger_index >= 0 else "Average"]) + + return _format("??") diff --git a/examples/edge_shader/edge_shader.gdshader b/examples/edge_shader/edge_shader.gdshader deleted file mode 100644 index a2def85..0000000 --- a/examples/edge_shader/edge_shader.gdshader +++ /dev/null @@ -1,16 +0,0 @@ -shader_type canvas_item; -/** - * This shader fixes normal textures looking wrong when used with SmartShape2D. - * See: https://github.com/SirRamEsq/SmartShape2D/blob/master/addons/rmsmartshape/documentation/Normals.md - */ - -varying mat2 NORMAL_MATRIX; - -void vertex() { - NORMAL_MATRIX = mat2(COLOR.rg, COLOR.ba) * 2.0 - mat2(vec2(1.0), vec2(1.0)); -} - -void fragment() { - NORMAL.xy = NORMAL_MATRIX * NORMAL.xy; - COLOR = texture(TEXTURE, UV); -} diff --git a/examples/edge_shader/material_edge_shader.tres b/examples/edge_shader/material_edge_shader.tres deleted file mode 100644 index 0bda5c4..0000000 --- a/examples/edge_shader/material_edge_shader.tres +++ /dev/null @@ -1,6 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://dpec5hjpflmri"] - -[ext_resource type="Shader" path="res://examples/edge_shader/edge_shader.gdshader" id="1_akl0v"] - -[resource] -shader = ExtResource("1_akl0v") diff --git a/examples/sharp_corner_tapering/assets/mat_edge_metal.tres b/examples/sharp_corner_tapering/assets/mat_edge_metal.tres deleted file mode 100644 index aacc59b..0000000 --- a/examples/sharp_corner_tapering/assets/mat_edge_metal.tres +++ /dev/null @@ -1,22 +0,0 @@ -[gd_resource type="Resource" script_class="SS2D_Material_Edge" load_steps=7 format=3 uid="uid://c8q2nrxnbopbb"] - -[ext_resource type="Script" path="res://addons/rmsmartshape/materials/edge_material.gd" id="1_lbfns"] -[ext_resource type="Texture2D" uid="uid://b3aqa3bj1osvp" path="res://examples/sharp_corner_tapering/assets/tex_metal_edge.png" id="2_bmjh3"] -[ext_resource type="Texture2D" uid="uid://bobwi3r6aiiqg" path="res://examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png" id="3_n1i1s"] -[ext_resource type="Texture2D" uid="uid://bc34cuc50as8f" path="res://examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png" id="4_ml2u7"] -[ext_resource type="Texture2D" uid="uid://jc3g5qsmnpdd" path="res://examples/sharp_corner_tapering/assets/tex_metal_taper_corner_left.png" id="5_244mn"] -[ext_resource type="Texture2D" uid="uid://cdnfaf3bslk38" path="res://examples/sharp_corner_tapering/assets/tex_metal_taper_corner_right.png" id="6_1c2na"] - -[resource] -script = ExtResource("1_lbfns") -textures = Array[Texture2D]([ExtResource("2_bmjh3")]) -textures_corner_outer = Array[Texture2D]([ExtResource("4_ml2u7")]) -textures_corner_inner = Array[Texture2D]([ExtResource("3_n1i1s")]) -textures_taper_left = Array[Texture2D]([]) -textures_taper_right = Array[Texture2D]([]) -textures_taper_corner_left = Array[Texture2D]([ExtResource("5_244mn")]) -textures_taper_corner_right = Array[Texture2D]([ExtResource("6_1c2na")]) -randomize_texture = false -use_corner_texture = true -use_taper_texture = false -fit_mode = 0 diff --git a/examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png b/examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png deleted file mode 100644 index 6adcf60..0000000 Binary files a/examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png and /dev/null differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png b/examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png deleted file mode 100644 index 1dcc88a..0000000 Binary files a/examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png and /dev/null differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_edge.png b/examples/sharp_corner_tapering/assets/tex_metal_edge.png deleted file mode 100644 index cab72a4..0000000 Binary files a/examples/sharp_corner_tapering/assets/tex_metal_edge.png and /dev/null differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_fill.png b/examples/sharp_corner_tapering/assets/tex_metal_fill.png deleted file mode 100644 index d8a5619..0000000 Binary files a/examples/sharp_corner_tapering/assets/tex_metal_fill.png and /dev/null differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_left.png b/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_left.png deleted file mode 100644 index 17ab69d..0000000 Binary files a/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_left.png and /dev/null differ diff --git a/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_right.png b/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_right.png deleted file mode 100644 index 3d06df9..0000000 Binary files a/examples/sharp_corner_tapering/assets/tex_metal_taper_corner_right.png and /dev/null differ diff --git a/examples/sharp_corner_tapering/sharp_corner_tapering.tscn b/examples/sharp_corner_tapering/sharp_corner_tapering.tscn deleted file mode 100644 index ecbfeb0..0000000 --- a/examples/sharp_corner_tapering/sharp_corner_tapering.tscn +++ /dev/null @@ -1,315 +0,0 @@ -[gd_scene load_steps=46 format=3 uid="uid://cl71flny1scun"] - -[ext_resource type="Script" path="res://addons/rmsmartshape/shapes/shape.gd" id="1_5hlge"] -[ext_resource type="Script" path="res://addons/rmsmartshape/vertex_properties.gd" id="2_yp1d2"] -[ext_resource type="Script" path="res://addons/rmsmartshape/shapes/point.gd" id="3_edpr6"] -[ext_resource type="Script" path="res://addons/rmsmartshape/shapes/point_array.gd" id="4_udfgv"] -[ext_resource type="Texture2D" uid="uid://bj658oli0klj3" path="res://examples/sharp_corner_tapering/assets/tex_metal_fill.png" id="6_ry0x0"] -[ext_resource type="Script" path="res://addons/rmsmartshape/materials/shape_material.gd" id="7_ncdby"] -[ext_resource type="Resource" uid="uid://c8q2nrxnbopbb" path="res://examples/sharp_corner_tapering/assets/mat_edge_metal.tres" id="8_uwntg"] -[ext_resource type="Script" path="res://addons/rmsmartshape/normal_range.gd" id="9_tqu3h"] -[ext_resource type="Script" path="res://addons/rmsmartshape/materials/edge_material.gd" id="10_55l7o"] -[ext_resource type="Script" path="res://addons/rmsmartshape/materials/edge_material_metadata.gd" id="10_umoay"] -[ext_resource type="Texture2D" uid="uid://b3aqa3bj1osvp" path="res://examples/sharp_corner_tapering/assets/tex_metal_edge.png" id="11_jc4po"] -[ext_resource type="Texture2D" uid="uid://bobwi3r6aiiqg" path="res://examples/sharp_corner_tapering/assets/tex_metal_corner_inner.png" id="12_va43u"] -[ext_resource type="Texture2D" uid="uid://bc34cuc50as8f" path="res://examples/sharp_corner_tapering/assets/tex_metal_corner_outer.png" id="13_f7yxr"] - -[sub_resource type="Resource" id="Resource_2r7x3"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_vpbfx"] -script = ExtResource("3_edpr6") -position = Vector2(83.365, 45.3257) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_2r7x3") - -[sub_resource type="Resource" id="Resource_a0g7n"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_w5cbt"] -script = ExtResource("3_edpr6") -position = Vector2(263.601, 615.758) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_a0g7n") - -[sub_resource type="Resource" id="Resource_h14mo"] -script = ExtResource("2_yp1d2") -texture_idx = -4 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_j5l1j"] -script = ExtResource("3_edpr6") -position = Vector2(1026.77, 577.75) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_h14mo") - -[sub_resource type="Resource" id="Resource_ukuig"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_324cb"] -script = ExtResource("3_edpr6") -position = Vector2(731.167, 13.1754) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_ukuig") - -[sub_resource type="Resource" id="Resource_wasbm"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_p3ja8"] -script = ExtResource("3_edpr6") -position = Vector2(83.365, 45.3257) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_wasbm") - -[sub_resource type="Resource" id="Resource_1fh62"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_qjb65"] -script = ExtResource("3_edpr6") -position = Vector2(742.381, 447.381) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_1fh62") - -[sub_resource type="Resource" id="Resource_o8bfq"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_w1ohc"] -script = ExtResource("3_edpr6") -position = Vector2(641.411, 322.256) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_o8bfq") - -[sub_resource type="Resource" id="Resource_tp3up"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_tlf23"] -script = ExtResource("3_edpr6") -position = Vector2(1133.09, 291.15) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_tp3up") - -[sub_resource type="Resource" id="Resource_6u83i"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_86kx1"] -script = ExtResource("3_edpr6") -position = Vector2(546.956, 94.6283) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_6u83i") - -[sub_resource type="Resource" id="Resource_kysxg"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_eqyck"] -script = ExtResource("3_edpr6") -position = Vector2(293.278, 51.6277) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_kysxg") - -[sub_resource type="Resource" id="Resource_egpc8"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_1wyqg"] -script = ExtResource("3_edpr6") -position = Vector2(871.022, 351.231) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_egpc8") - -[sub_resource type="Resource" id="Resource_baip5"] -script = ExtResource("2_yp1d2") -texture_idx = 0 -flip = false -width = 1.0 - -[sub_resource type="Resource" id="Resource_2owaw"] -script = ExtResource("3_edpr6") -position = Vector2(239.115, 334.66) -point_in = Vector2(0, 0) -point_out = Vector2(0, 0) -properties = SubResource("Resource_baip5") - -[sub_resource type="Resource" id="Resource_o2w6y"] -script = ExtResource("4_udfgv") -_points = { -0: SubResource("Resource_vpbfx"), -1: SubResource("Resource_w5cbt"), -2: SubResource("Resource_j5l1j"), -3: SubResource("Resource_324cb"), -4: SubResource("Resource_p3ja8"), -6: SubResource("Resource_qjb65"), -8: SubResource("Resource_w1ohc"), -9: SubResource("Resource_tlf23"), -10: SubResource("Resource_86kx1"), -11: SubResource("Resource_eqyck"), -12: SubResource("Resource_1wyqg"), -13: SubResource("Resource_2owaw") -} -_point_order = PackedInt32Array(4, 11, 8, 10, 3, 12, 9, 2, 6, 1, 13, 0) -_constraints = { -Vector2i(0, 4): 15 -} -_next_key = 14 -_material_overrides = {} -tessellation_stages = 5 -tessellation_tolerance = 4.0 -curve_bake_interval = 20.0 - -[sub_resource type="Resource" id="Resource_42qh7"] -script = ExtResource("9_tqu3h") -begin = 0.0 -distance = 360.0 -edgeRendering = Vector2(0, 0) - -[sub_resource type="Resource" id="Resource_t7ed3"] -script = ExtResource("10_umoay") -edge_material = ExtResource("8_uwntg") -normal_range = SubResource("Resource_42qh7") -weld = true -taper_sharp_corners = true -render = true -z_index = 0 -z_as_relative = true -offset = 0.0 - -[sub_resource type="Resource" id="Resource_07ymf"] -script = ExtResource("7_ncdby") -_edge_meta_materials = Array[ExtResource("10_umoay")]([SubResource("Resource_t7ed3")]) -fill_textures = Array[Texture2D]([ExtResource("6_ry0x0")]) -fill_texture_z_index = -10 -fill_texture_show_behind_parent = false -fill_texture_scale = 1.0 -fill_texture_absolute_position = false -fill_texture_absolute_rotation = false -fill_texture_offset = Vector2(0, 0) -fill_texture_angle_offset = 0.0 -fill_mesh_offset = 0.0 -render_offset = 0.0 - -[sub_resource type="Resource" id="Resource_ma2v2"] -script = ExtResource("10_55l7o") -textures = Array[Texture2D]([ExtResource("11_jc4po")]) -textures_corner_outer = Array[Texture2D]([ExtResource("13_f7yxr")]) -textures_corner_inner = Array[Texture2D]([ExtResource("12_va43u")]) -textures_taper_left = Array[Texture2D]([]) -textures_taper_right = Array[Texture2D]([]) -textures_taper_corner_left = Array[Texture2D]([]) -textures_taper_corner_right = Array[Texture2D]([]) -randomize_texture = false -use_corner_texture = true -use_taper_texture = true -fit_mode = 0 - -[sub_resource type="Resource" id="Resource_atqmo"] -script = ExtResource("9_tqu3h") -begin = 0.0 -distance = 360.0 -edgeRendering = Vector2(0, 0) - -[sub_resource type="Resource" id="Resource_vboqn"] -script = ExtResource("10_umoay") -edge_material = SubResource("Resource_ma2v2") -normal_range = SubResource("Resource_atqmo") -weld = true -taper_sharp_corners = false -render = true -z_index = 0 -z_as_relative = true -offset = 0.0 - -[sub_resource type="Resource" id="Resource_xsfev"] -script = ExtResource("7_ncdby") -_edge_meta_materials = Array[ExtResource("10_umoay")]([SubResource("Resource_vboqn")]) -fill_textures = Array[Texture2D]([ExtResource("6_ry0x0")]) -fill_texture_z_index = -10 -fill_texture_show_behind_parent = false -fill_texture_scale = 1.0 -fill_texture_absolute_position = false -fill_texture_absolute_rotation = false -fill_texture_offset = Vector2(0, 0) -fill_texture_angle_offset = 0.0 -fill_mesh_offset = 0.0 -render_offset = 0.0 - -[node name="Node2D" type="Node2D"] - -[node name="WithTapering" type="Node2D" parent="."] -texture_repeat = 2 -position = Vector2(-30, 228) -scale = Vector2(0.65, 0.65) -script = ExtResource("1_5hlge") -_points = SubResource("Resource_o2w6y") -shape_material = SubResource("Resource_07ymf") - -[node name="WithoutTapering" type="Node2D" parent="."] -texture_repeat = 2 -position = Vector2(400, 10) -scale = Vector2(0.65, 0.65) -script = ExtResource("1_5hlge") -_points = SubResource("Resource_o2w6y") -shape_material = SubResource("Resource_xsfev") - -[node name="Message" type="Label" parent="."] -offset_left = 33.0 -offset_top = 82.0 -offset_right = 434.0 -offset_bottom = 190.0 -theme_override_font_sizes/font_size = 24 -text = "NOTE: Sharp corner tapering can -cause issues when used on shapes -with curved geometry" - -[node name="With" type="Label" parent="."] -offset_left = 275.0 -offset_top = 454.0 -offset_right = 503.0 -offset_bottom = 477.0 -text = "Sharp Corner Tapering" - -[node name="Without" type="Label" parent="."] -offset_left = 666.0 -offset_top = 237.0 -offset_right = 907.0 -offset_bottom = 260.0 -text = "No Sharp Corner Tapering" diff --git a/fonts/PressStart2P-Regular.ttf b/fonts/PressStart2P-Regular.ttf new file mode 100644 index 0000000..2442aff Binary files /dev/null and b/fonts/PressStart2P-Regular.ttf differ diff --git a/fonts/PressStart2P-Regular.ttf.import b/fonts/PressStart2P-Regular.ttf.import new file mode 100644 index 0000000..b1ca4c1 --- /dev/null +++ b/fonts/PressStart2P-Regular.ttf.import @@ -0,0 +1,34 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://xm0vbusjr7b7" +path="res://.godot/imported/PressStart2P-Regular.ttf-c7d83f2c4bd295d4c960a93a703ae2b2.fontdata" + +[deps] + +source_file="res://fonts/PressStart2P-Regular.ttf" +dest_files=["res://.godot/imported/PressStart2P-Regular.ttf-c7d83f2c4bd295d4c960a93a703ae2b2.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/objects/cage.tscn b/objects/cage.tscn index 93845f0..640b766 100644 --- a/objects/cage.tscn +++ b/objects/cage.tscn @@ -15,6 +15,7 @@ physics_layer_0/collision_layer = 1 sources/0 = SubResource("TileSetAtlasSource_aivtb") [node name="Cage" type="Node2D"] +z_index = 2 scale = Vector2(2, 2) [node name="TileMapLayer" type="TileMapLayer" parent="."] diff --git a/objects/child.tscn b/objects/child.tscn index 633671d..3c16ec7 100644 --- a/objects/child.tscn +++ b/objects/child.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=9 format=3 uid="uid://d0s2abysa86rq"] +[gd_scene load_steps=10 format=3 uid="uid://d0s2abysa86rq"] [ext_resource type="Texture2D" uid="uid://b7gp0gqvkv8j4" path="res://sprites/MrBrick_base.png" id="1_jcisc"] [ext_resource type="Texture2D" uid="uid://jl1gwqchhpdc" path="res://sprites/left_eye.png" id="2_8jrbi"] [ext_resource type="Texture2D" uid="uid://iiawtnwmeny3" path="res://sprites/right_eye.png" id="3_k41y7"] [ext_resource type="Texture2D" uid="uid://8h05rd26t66q" path="res://sprites/lollipop.png" id="4_vq1oq"] +[ext_resource type="Texture2D" uid="uid://dpbpjffbdbovp" path="res://sprites/cap.png" id="5_m7x6t"] [ext_resource type="Script" path="res://scripts/components/collectable.gd" id="5_wc3ym"] [ext_resource type="Resource" uid="uid://b6apusc0jmi3x" path="res://resources/collectables/child.tres" id="6_vmvuo"] [ext_resource type="AudioStream" uid="uid://drfr0wlgkhkdq" path="res://sfx/child_pickup.wav" id="7_j8eyh"] @@ -40,6 +41,10 @@ position = Vector2(3, 1) rotation = 0.785398 texture = ExtResource("4_vq1oq") +[node name="Cap" type="Sprite2D" parent="Root"] +position = Vector2(4, -18) +texture = ExtResource("5_m7x6t") + [node name="CollectableComponent" type="Node" parent="." node_paths=PackedStringArray("area2d", "sfx")] script = ExtResource("5_wc3ym") area2d = NodePath("..") diff --git a/project.godot b/project.godot index 8895a83..264060b 100644 --- a/project.godot +++ b/project.godot @@ -28,6 +28,7 @@ config/icon="res://icon.svg" GameManager="*res://objects/game_manager.tscn" PhantomCameraManager="*res://addons/phantom_camera/scripts/managers/phantom_camera_manager.gd" +GUIDE="*res://addons/guide/guide.gd" [display] @@ -46,7 +47,7 @@ project/assembly_name="Mr. Brick Adventures" [editor_plugins] -enabled=PackedStringArray("res://addons/phantom_camera/plugin.cfg", "res://addons/rmsmartshape/plugin.cfg") +enabled=PackedStringArray("res://addons/guide/plugin.cfg", "res://addons/phantom_camera/plugin.cfg") [global_group] diff --git a/sprites/cap.png b/sprites/cap.png new file mode 100644 index 0000000..0821231 Binary files /dev/null and b/sprites/cap.png differ diff --git a/addons/godot-rapier2d/logo_square_2d.png.import b/sprites/cap.png.import similarity index 66% rename from addons/godot-rapier2d/logo_square_2d.png.import rename to sprites/cap.png.import index 35dc183..3dd19b0 100644 --- a/addons/godot-rapier2d/logo_square_2d.png.import +++ b/sprites/cap.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://d1iwpd5epp8u6" -path="res://.godot/imported/logo_square_2d.png-ee7cb55fd9c4d1815ce7e83cd5401198.ctex" +uid="uid://dpbpjffbdbovp" +path="res://.godot/imported/cap.png-129e6e9f426ec3391fbd49f80f263310.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://addons/godot-rapier2d/logo_square_2d.png" -dest_files=["res://.godot/imported/logo_square_2d.png-ee7cb55fd9c4d1815ce7e83cd5401198.ctex"] +source_file="res://sprites/cap.png" +dest_files=["res://.godot/imported/cap.png-129e6e9f426ec3391fbd49f80f263310.ctex"] [params] diff --git a/sprites/ui/gdb-keyboard-2.png b/sprites/ui/gdb-keyboard-2.png new file mode 100644 index 0000000..da9dd18 Binary files /dev/null and b/sprites/ui/gdb-keyboard-2.png differ diff --git a/sprites/ui/gdb-keyboard-2.png.import b/sprites/ui/gdb-keyboard-2.png.import new file mode 100644 index 0000000..04f0128 --- /dev/null +++ b/sprites/ui/gdb-keyboard-2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bolnn3e0u8d5a" +path="res://.godot/imported/gdb-keyboard-2.png-e4700488c574704d1c341bd05b453580.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://sprites/ui/gdb-keyboard-2.png" +dest_files=["res://.godot/imported/gdb-keyboard-2.png-e4700488c574704d1c341bd05b453580.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 diff --git a/sprites/ui/gdb-playstation-3.png b/sprites/ui/gdb-playstation-3.png new file mode 100644 index 0000000..1750b6a Binary files /dev/null and b/sprites/ui/gdb-playstation-3.png differ diff --git a/sprites/ui/gdb-playstation-3.png.import b/sprites/ui/gdb-playstation-3.png.import new file mode 100644 index 0000000..9355a8d --- /dev/null +++ b/sprites/ui/gdb-playstation-3.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8gwdsf8gptjf" +path="res://.godot/imported/gdb-playstation-3.png-1052be9ad0b0e4e3aceaf539c8b22a36.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://sprites/ui/gdb-playstation-3.png" +dest_files=["res://.godot/imported/gdb-playstation-3.png-1052be9ad0b0e4e3aceaf539c8b22a36.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 diff --git a/sprites/ui/gdb-xbox-2.png b/sprites/ui/gdb-xbox-2.png new file mode 100644 index 0000000..49dcd12 Binary files /dev/null and b/sprites/ui/gdb-xbox-2.png differ diff --git a/sprites/ui/gdb-xbox-2.png.import b/sprites/ui/gdb-xbox-2.png.import new file mode 100644 index 0000000..a587c2d --- /dev/null +++ b/sprites/ui/gdb-xbox-2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqq1u0ignemi5" +path="res://.godot/imported/gdb-xbox-2.png-894d57920d16ff5da033d2acef32774b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://sprites/ui/gdb-xbox-2.png" +dest_files=["res://.godot/imported/gdb-xbox-2.png-894d57920d16ff5da033d2acef32774b.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