[
  {
    "path": ".gitattributes",
    "content": "# Normalize EOL for all files that Git considers text files.\n* text=auto eol=lf\n\n# Only include the addons folder when downloading from the Asset Library.\n/**        export-ignore\n/addons    !export-ignore\n/addons/** !export-ignore"
  },
  {
    "path": ".gitignore",
    "content": "# Godot 4+ specific ignores\n.godot/\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (C) 2023 Claudio Z. (cloudofoz)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "![Version](https://img.shields.io/badge/Godot-v4.5-informational) ![License](https://img.shields.io/github/license/cloudofoz/godot-deformablemesh)\n\n<img src=\"addons/deformablemesh/dm_icon_deformable_mesh.svg\" width=\"64\" align=\"left\"/>\n\n## godot-deformablemesh\n**This addon allows to deform 3D meshes using a stack of customizable deformers at run-time**\n\n<br clear=\"left\" />\n\n<p align=\"center\">\n   <img src=\"media/dm_screen_v04_1.gif\" height=\"270\" />\n  <img src=\"media/dm_screen_v03_1.gif\" height=\"270\" />\n  <img src=\"media/dm_example_scene_scr.jpg\" height=\"270\" /> \n</p>\n\n## Main Features\n\nUse the default deformers:\n- `SphericalDeformer` <img src=\"addons/deformablemesh/dm_icon_spherical_deformer.svg\" width=\"20\"/>  \n- `StandardDeformer` <img src=\"addons/deformablemesh/dm_icon_std_deformer.svg\" width=\"20\"/> (Bend, Twist, and Taper)  \n- `DragDeformer` <img src=\"addons/deformablemesh/dm_icon_drag_deformer.svg\" width=\"20\"/> (In **Rest Pose Mode**, position the deformer, toggle it off, and deform the mesh by moving the node.)\n\n<br>\n\nOr **easily create your own** by extending the base class and overriding just a couple of methods in `dm_deformer.gd`.\n\n\n## Getting Started\n\n1. Download the [repository](https://github.com/cloudofoz/godot-deformablemesh/archive/refs/heads/main.zip) or download the *previous version* of the addon from the AssetLib in Godot ([link](https://godotengine.org/asset-library/asset/1794)).\n\n2. Import the **addons** folder into your project.\n\n3. Activate `DeformableMesh` under *Project > Project Settings > Plugins.*\n\n<p align=\"center\">\n  <img src=\"media/dm_getting_started_00.jpg\" />\n</p>\n\n4. Add a *deformer* node to the scene.\n\n<p align=\"center\">\n  <img src=\"media/dm_getting_started_01.jpg\" />\n</p>\n\n5. Add a `DeformableMeshInstance3D` node to the scene.\n\n<p align=\"center\">\n  <img src=\"media/dm_getting_started_02.jpg\" />\n</p>\n\n6. Set the *mesh resource* you want to deform in the **Original Mesh** property.\n\n<p align=\"center\">\n  <img src=\"media/dm_getting_started_03.jpg\" />\n</p>\n\n7. Link the *deformer node* you created before to the list of **Deformers** that will affect this mesh in the property panel.\n\n<p align=\"center\">\n  <img src=\"media/dm_getting_started_04.jpg\" />\n</p>\n\n7. Tweak the *deformer* properties to achieve the desired result.\n\n<p align=\"center\">\n  <img src=\"media/dm_getting_started_05.jpg\" />\n</p>\n\n## Example Project\n\n1. [**You can download here**](media/dm_example_scene.zip) an example project that shows the basic functionalities of `DeformableMesh`.\n2. Unzip the file\n3. Import the project with Godot Engine 4+\n4. Open the scene `dm_example_scene_v030.tscn` (if it's not already opened)\n\nYou can now try tweaking the deformer parameters. \nSome effects are also controlled by the positions and the rotations of the deformer nodes.\n\n`DeformableMesh` can apply multiple deformers like in a stack, so the order is important to achieve the correct effect.\nYou need also to specify the correct deformation axis (for some effects like bending, but it's not important with spherical deformers).\n\n## Known Limitations\n\n- This addon is designed with simplicity and versatility as primary goals, making it well-suited for simple, standard use cases. However, it is not optimized for specialized use cases, such as higher-density meshes (and, in some cases, multiple surfaces, which may also impact performance) in performance-critical applications. Users are encouraged to thoroughly test the addon to ensure it meets their specific requirements.\n\n- While other deformers support deforming multiple meshes at once, a `DragDeformer` can only be tied to a single mesh at a time.\n\n## Credits\nI wish to thank the community for any contribution or feedback. Special thanks to:\n\n- **Kevin Loustau**, for sparking the idea behind the `DragDeformer` feature.\n\n\n## Changelog\n\n**v0.40**\n\n- **Add**: `DragDeformer` node.\n- **Add**: `_on_end_update()` overridable method for the deformer base class.\n- **Fix**: Removing a deformer now correctly unregisters the linked event listeners.\n- **Fix**: `_on_begin_update()` is now called only once, even with multiple surfaces.\n\n[**v0.30**](https://github.com/cloudofoz/godot-deformablemesh/releases/tag/v0.30)\n\n- **Add**: `StandardDeformer` (Bend, Twist, and Taper).\n- **Remove**: `BendDeformer` (now included as part of `StandardDeformer`).\n- **Improve**: Deformer selection list.\n\n[**v0.20**](https://github.com/cloudofoz/godot-deformablemesh/releases/tag/v0.20)\n\n- **Add**: Bend deformers.\n- **Add**: Base class to easily create custom deformers.\n- **Refactor**: Codebase and minor improvements.\n\n[**v0.10**](https://github.com/cloudofoz/godot-deformablemesh/tree/v0.1)\n\n- **First release**\n\n\n## License\n\n[MIT License](/LICENSE.md)\n"
  },
  {
    "path": "addons/deformablemesh/dm_debug_sphere_material.tres",
    "content": "[gd_resource type=\"StandardMaterial3D\" format=3 uid=\"uid://dwqr7ia23sngt\"]\n\n[resource]\ndepth_draw_mode = 2\nno_depth_test = true\nshading_mode = 0\ndiffuse_mode = 3\ndisable_ambient_light = true\nalbedo_color = Color(0.14902, 1, 0.713726, 1)\n"
  },
  {
    "path": "addons/deformablemesh/dm_debug_sphere_mesh.tres",
    "content": "[gd_resource type=\"ArrayMesh\" load_steps=2 format=4 uid=\"uid://b3o4hmiksh4it\"]\n\n[ext_resource type=\"Material\" uid=\"uid://dwqr7ia23sngt\" path=\"res://addons/deformablemesh/dm_debug_sphere_material.tres\" id=\"1_d8wbp\"]\n\n[resource]\n_surfaces = [{\n\"aabb\": AABB(-0.990686, 0, -0.997669, 1.9907, 1e-05, 1.99534),\n\"format\": 34359738369,\n\"material\": ExtResource(\"1_d8wbp\"),\n\"primitive\": 2,\n\"uv_scale\": Vector4(0, 0, 0, 0),\n\"vertex_count\": 24,\n\"vertex_data\": PackedByteArray(\"AACAPwAAAAAAAAAAv4F2PwAAAADNIoo+O7taPwAAAAB0AwU/zrsuPwAAAAARGDs/pY3rPgAAAAByTGM/xlZQPgAAAABBpXo/rsKLvQAAAAA4Z38/V3WrvgAAAAADOHE/UqETvwAAAADwJFE/BJVGvwAAAAD7jiE/XM5qvwAAAAA6+8s+mJ19vwAAAABFbws+mJ19vwAAAABFbwu+XM5qvwAAAAA6+8u+BJVGvwAAAAD7jiG/UqETvwAAAADwJFG/V3WrvgAAAAADOHG/rsKLvQAAAAA4Z3+/xlZQPgAAAABBpXq/pY3rPgAAAAByTGO/zrsuPwAAAAARGDu/O7taPwAAAAB0AwW/v4F2PwAAAADNIoq+AACAPwAAAAAAMI2l\")\n}, {\n\"aabb\": AABB(-4.37114e-08, -0.990686, -0.997669, 1e-05, 1.9907, 1.99534),\n\"format\": 34359738369,\n\"material\": ExtResource(\"1_d8wbp\"),\n\"primitive\": 2,\n\"uv_scale\": Vector4(0, 0, 0, 0),\n\"vertex_count\": 24,\n\"vertex_data\": PackedByteArray(\"Lr07swAAgD8AAAAA8cY0s7+Bdj/NIoo+aGggszu7Wj90AwU/UCQAs867Lj8RGDs/ib6ssqWN6z5yTGM/WMkYssZWUD5BpXo/+vxMMa7Ci704Z38/1np7Mld1q74DOHE/34fYMlKhE7/wJFE/mqERMwSVRr/7jiE/QjIsM1zOar86+8s+if05M5idfb9Fbws+if05M5idfb9Fbwu+QjIsM1zOar86+8u+mqERMwSVRr/7jiG/34fYMlKhE7/wJFG/1np7Mld1q74DOHG/+vxMMa7Ci704Z3+/WMkYssZWUD5BpXq/ib6ssqWN6z5yTGO/UCQAs867Lj8RGDu/aGggszu7Wj90AwW/8cY0s7+Bdj/NIoq+Lr07swAAgD8AMI2l\")\n}, {\n\"aabb\": AABB(-0.990686, -0.997669, -4.36095e-08, 1.9907, 1.99534, 1.00436e-05),\n\"format\": 34359738369,\n\"material\": ExtResource(\"1_d8wbp\"),\n\"primitive\": 2,\n\"uv_scale\": Vector4(0, 0, 0, 0),\n\"vertex_count\": 24,\n\"vertex_data\": PackedByteArray(\"AACAPwAAAAAAAAAAv4F2P80iij4Bm0qyO7taP3QDBT+iF8OyzrsuPxEYOz/XNAmzpY3rPnJMYz/QsCazxlZQPkGlej/wzzezrsKLvThnfz8jTTuzV3WrvgM4cT8s5jCzUqETv/AkUT+JYBmzBJVGv/uOIT+q9eyyXM5qvzr7yz5Al5WymJ19v0VvCz6jgsyxmJ19v0VvC76jgswxXM5qvzr7y75Al5UyBJVGv/uOIb+q9ewyUqETv/AkUb+JYBkzV3WrvgM4cb8s5jAzrsKLvThnf78jTTszxlZQPkGler/wzzczpY3rPnJMY7/QsCYzzrsuPxEYO7/XNAkzO7taP3QDBb+iF8Myv4F2P80iir4Bm0oyAACAPwAwjaXMFE8Z\")\n}]\n"
  },
  {
    "path": "addons/deformablemesh/dm_deformable_mesh.gd",
    "content": "# Copyright (C) 2023-2024 Claudio Z. (cloudofoz)\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n@tool\nextends MeshInstance3D\n\n#---------------------------------------------------------------------------------------------------\n# CONSTANTS\n#---------------------------------------------------------------------------------------------------\n\nconst SurfaceData = preload(\"dm_surface_data.gd\")\n\nconst Deformer = preload(\"dm_deformer.gd\")\n\n#---------------------------------------------------------------------------------------------------\n# PUBLIC VARIABLES\n#---------------------------------------------------------------------------------------------------\n@export_category(\"Deformable Mesh\")\n\n## Original mesh resource to be deformed\n@export var original_mesh: Mesh = null:\n\tset(value):\n\t\tif(original_mesh):\n\t\t\toriginal_mesh.changed.disconnect(dm_init_surfaces)\n\t\toriginal_mesh = value\n\t\tif(!original_mesh): return\n\t\toriginal_mesh.changed.connect(dm_init_surfaces)\n\t\tdm_init_surfaces()\n\n## Array of deformer node paths that affects this mesh.\n@onready @export var deformers: Array[Deformer]:\n\tset(value):\n\t\tdeformers = value\n\t\tdm_find_deformers()\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE VARIABLES\n#---------------------------------------------------------------------------------------------------\n\nvar dm_surfaces = [SurfaceData];\nvar dm_need_update: bool = false\nvar dm_deformers: Array[Deformer]\n\n#---------------------------------------------------------------------------------------------------\n# VIRTUAL METHODS\n#---------------------------------------------------------------------------------------------------\n\nfunc _init():\n\tset_notify_transform(true)\n\tdm_clean_deformers()\n\nfunc _ready():\n\tdm_find_deformers()\n\nfunc _process(_delta):\n\tif(dm_need_update):\n\t\tdm_update()\n\nfunc _notification(what):\n\tmatch what:\n\t\tNOTIFICATION_TRANSFORM_CHANGED:\n\t\t\tdm_need_update = true\n\t\tNOTIFICATION_ENTER_WORLD:\n\t\t\tdm_find_deformers()\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE METHODS\n#---------------------------------------------------------------------------------------------------\n\nfunc dm_init_surfaces():\n\tif(!original_mesh): return\n\tmesh = ArrayMesh.new()\n\tvar surface_count = original_mesh.get_surface_count()\n\tdm_surfaces.clear()\n\tfor i in range(surface_count):\n\t\tvar s = SurfaceData.new()\n\t\ts.create_from_surface(original_mesh, i)\n\t\tdm_surfaces.push_back(s)\n\tdm_update()\n\nfunc dm_update():\n\tif(dm_surfaces.size() < 1): return\n\tif(!mesh): return\n\tfor deformer in dm_deformers:\n\t\tif(!deformer.visible): continue\n\t\tdeformer._on_begin_update(self)\n\tmesh.clear_surfaces()\n\tfor sidx in range(dm_surfaces.size()):\n\t\tvar s = dm_surfaces[sidx] \n\t\tif(!s): continue\n\t\ts.update_surface(dm_deformers, self)\n\t\ts.commit_to_surface(mesh)\n\t\tmesh.surface_set_material(sidx, original_mesh.surface_get_material(sidx))\n\tdm_need_update = false\n\tfor deformer in dm_deformers:\n\t\tif(!deformer.visible): continue\n\t\tdeformer._on_end_update()\n\nfunc dm_clean_deformers():\n\t#dm_deformers.clear()\n\twhile not dm_deformers.is_empty():\n\t\tvar deformer = dm_deformers.back()\n\t\tdeformer.on_deformer_updated.disconnect(_on_deformer_updated)\n\t\tdeformer.on_deformer_removed.disconnect(_on_deformer_removed)\n\t\tdm_deformers.pop_back()\n\nfunc dm_add_deformer(deformer: Deformer) -> void:\n\tdm_deformers.push_back(deformer)\n\tif(!deformer.on_deformer_updated.is_connected(_on_deformer_updated)):\n\t\tdeformer.on_deformer_updated.connect(_on_deformer_updated)\n\tif(!deformer.on_deformer_removed.is_connected(_on_deformer_removed)):\n\t\tdeformer.on_deformer_removed.connect(_on_deformer_removed)\n\nfunc dm_rem_deformer(deformer: Deformer) -> void:\n\tvar didx = dm_deformers.find(deformer)\n\tif(didx > -1): dm_deformers.remove_at(didx)\n\tif(deformer.on_deformer_updated.is_connected(_on_deformer_updated)):\n\t\tdeformer.on_deformer_updated.disconnect(_on_deformer_updated)\n\tif(deformer.on_deformer_removed.is_connected(_on_deformer_removed)):\n\t\tdeformer.on_deformer_removed.disconnect(_on_deformer_removed)\n\nfunc dm_find_deformers():\n\tif(!is_inside_tree()): return\n\tdm_clean_deformers()\n\tfor d in deformers:\n\t\tif(d && !dm_deformers.has(d)):\n\t\t\tdm_add_deformer(d)\n\t\telse:\n\t\t\tvar didx = deformers.find(d)\n\t\t\tdeformers[didx] = null\n\t\t\tnotify_property_list_changed()\n\tdm_need_update = true\n\n#---------------------------------------------------------------------------------------------------\n# CALLBACKS\n#---------------------------------------------------------------------------------------------------\n\nfunc _on_deformer_updated(deformer: Deformer):\n\tvar i = dm_deformers.find(deformer)\n\tif( i == -1 ): dm_add_deformer(deformer)\n\tdm_need_update = true\n\nfunc _on_deformer_removed(deformer: Deformer):\n\tdm_rem_deformer(deformer)\n\tdm_need_update = true\n\n#---------------------------------------------------------------------------------------------------\n# KNOWN BUGS / LIMITATIONS\n#---------------------------------------------------------------------------------------------------\n\n#BUG:        Error message when deleting node referenced through NodePath property or metadata #75168 \n#\t         https://github.com/godotengine/godot/issues/75168\n#LIMITATION: A deformer is currently only selectable from the scene tree\n#LIMITATION: A deformable mesh is currently limited by one UV set\n"
  },
  {
    "path": "addons/deformablemesh/dm_deformable_mesh.gd.uid",
    "content": "uid://iakvtj364g6q\n"
  },
  {
    "path": "addons/deformablemesh/dm_deformer.gd",
    "content": "# Copyright (C) 2023-2024 Claudio Z. (cloudofoz)\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n@tool\nextends MeshInstance3D\n\n## This base class is useful to create your own deformers for the deformable meshes.\n##\n## Basic usage: extend this class and override these two methods:\n##\n##        ## This method is called once before updating vertices.\n##        ## It's useful if you want to capture some information from the mesh that is going to\n##        ## to be modified. (for ex. the deformer position local to that istance)\n##        func _on_begin_update(DeformableMeshInstance3D) -> void\n##\n##        ## This method is called for every vertex of the mesh. It takes the current vertex\n##        ## position and returns the new vertex position\n##        func _on_update_vertex(Vector3) -> Vector3\nclass_name DM_Deformer\n\n#---------------------------------------------------------------------------------------------------\n# CONSTANTS\n#---------------------------------------------------------------------------------------------------\n\nconst DeformableMeshInstance3D = preload(\"dm_deformable_mesh.gd\")\n\nconst DebugSphereMesh = preload(\"dm_debug_sphere_mesh.tres\")\n\n#---------------------------------------------------------------------------------------------------\n# SIGNALS\n#---------------------------------------------------------------------------------------------------\n\nsignal on_deformer_updated(deformer)\n\nsignal on_deformer_removed(deformer)\n\n#---------------------------------------------------------------------------------------------------\n# PUBLIC VARIABLES\n#---------------------------------------------------------------------------------------------------\n@export_category(\"Deformer\")\n\n## A debug mesh to show in the editor with this node\n@export var debug_mesh: Mesh = DebugSphereMesh\n\n## Draws the deformer mesh (only visible in editor mode)\n@export var show_debug_mesh: bool = true:\n\tset(value):\n\t\tshow_debug_mesh = value\n\t\tmesh = debug_mesh if value else null\n\n#---------------------------------------------------------------------------------------------------\n# CALLBACKS\n#---------------------------------------------------------------------------------------------------\n\nfunc _on_user_changed_mesh():\n\tif(show_debug_mesh && mesh != debug_mesh):\n\t\tmesh = debug_mesh\n\n#---------------------------------------------------------------------------------------------------\n# VIRTUAL METHODS\n#---------------------------------------------------------------------------------------------------\n\n## Override this method to set up initial parameters in the deformer.\n## Called once before every deformable mesh update.\nfunc _on_begin_update(deformable: DeformableMeshInstance3D) -> void:\n\tpass\n\n## This is the main method to override for every type of deformer.\n## The default behaviour will leave the vertex unchanged.\n## It's called for every vertex of the deformable mesh.\nfunc _on_update_vertex(mesh_vertex: Vector3) -> Vector3:\n\treturn mesh_vertex\n\n## Override this method to perform final operations in the deformer.\n## Called once after every deformable mesh update is finished.\nfunc _on_end_update() -> void:\n\tpass\n\nfunc _init():\n\tset_notify_transform(true)\n\tif(!self.visibility_changed.is_connected(dm_update_deformables)):\n\t\tself.visibility_changed.connect(dm_update_deformables)\n\tif(Engine.is_editor_hint()):\n\t\tif(!property_list_changed.is_connected(_on_user_changed_mesh)):\n\t\t\tproperty_list_changed.connect(_on_user_changed_mesh)\n\nfunc _ready():\n\tif(Engine.is_editor_hint()):\n\t\tif(show_debug_mesh):\n\t\t\tmesh = debug_mesh\n#\t\t\tscale = Vector3(radius, radius, radius) #TODO: Fix\n\telse: \tshow_debug_mesh = false\n\tdm_update_deformables()\n\nfunc _notification(what):\n\tmatch what:\n\t\tNOTIFICATION_TRANSFORM_CHANGED:\n\t\t\tdm_update_deformables()\n\nfunc _exit_tree():\n\ton_deformer_removed.emit(self)\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE METHODS\n#---------------------------------------------------------------------------------------------------\n\nfunc dm_update_deformables():   \n\tif(!is_inside_tree()): return\n\ton_deformer_updated.emit(self)\n"
  },
  {
    "path": "addons/deformablemesh/dm_deformer.gd.uid",
    "content": "uid://bi1bdmhkk4kui\n"
  },
  {
    "path": "addons/deformablemesh/dm_drag_deformer.gd",
    "content": "# Copyright (C) 2024 Claudio Z. (cloudofoz)\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n@tool\nextends \"dm_deformer.gd\"\n\n#---------------------------------------------------------------------------------------------------\n# PUBLIC VARIABLES\n#---------------------------------------------------------------------------------------------------\n@export_category(\"Drag Deformer\")\n\n## Radius of the sphere affecting the mesh deformation.\n@export var radius: float = 1.5:\n\tset(value):\n\t\tradius = value\n\t\tdm_update_deformables()\n\t\tself.scale = Vector3(radius, radius, radius)\n\n## Falloff of the deformation effect, decreasing with distance from the center.\n@export_exp_easing(\"attenuation\") var attenuation: float = 1.0:\n\tset(value):\n\t\tattenuation = value\n\t\tdm_update_deformables()\n\n## Strength of the deformation effect.\n@export_range(0, 2.0, 0.1, \"or_greater\") var strength: float = 1:\n\tset(value):\n\t\tstrength = value\n\t\tdm_update_deformables()\n\n## Toggle the Rest Pose Mode.\n## Enables setting the deformer position at which there is no deformation.\n## When disabled, deformation is calculated from the rest pose.\n@export var rest_pose: bool = true:\n\tset(value):\n\t\tif value == rest_pose:\n\t\t\treturn\n\t\trest_pose = value\n\t\tif not rest_pose:\n\t\t\tdm_compute_rest_distances = true\n\t\t\tdm_update_deformables()\n\t\t# Move the deformer to its rest position\n\t\telif is_instance_valid(dm_active_deformable):\n\t\t\tself.global_position = dm_active_deformable.to_global(dm_rest_pos)\n\tget:\n\t\treturn rest_pose\n\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE VARIABLES\n#---------------------------------------------------------------------------------------------------\n\nvar dm_delta_translation: Vector3\n\nvar dm_rest_pos: Vector3\n\nvar dm_rest_distances: PackedFloat32Array\n\nvar dm_active_deformable: DeformableMeshInstance3D\n\nvar dm_active_mesh: Mesh\n\nvar dm_compute_rest_distances: bool = false\n\nvar dm_vertex_index: int\n\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE METHODS\n#---------------------------------------------------------------------------------------------------\n\nfunc dm_needs_computation(d: DeformableMeshInstance3D) -> bool:\n\t# Check if the active deformable is different from the current one.\n\tif dm_active_deformable != d:\n\t\t# If the current deformer is associated with a different mesh, remove it.\n\t\tif dm_active_deformable != null and dm_active_deformable.deformers.find(self) != -1:\n\t\t\td.deformers.remove_at(d.deformers.find(self))\n\t\t\td.dm_find_deformers()\n\t\t\tpush_warning(\"A DragDeformer can support only one mesh at a time.\")\n\t\treturn true\n\t\n\t# Check if the active mesh has changed.\n\tif dm_active_mesh != d.original_mesh:\n\t\treturn true\n\t\n\t# Check if rest distances need initialization.\n\tif dm_rest_distances.is_empty():\n\t\treturn true\n\t\n\t# No recomputation is needed.\n\treturn false\n\n\n#---------------------------------------------------------------------------------------------------\n# VIRTUAL METHODS\n#---------------------------------------------------------------------------------------------------\n\nfunc _ready():\n\tdm_rest_pos = self.get_meta(\"dm_rest_pos\", Vector3(0,0,0))\n\tsuper._ready()\n\n\nfunc _on_end_update() -> void:\n\t# If the rest distances were computed during this frame, force a refresh.\n\t# This ensures the meshes are correctly deformed immediately after loading\n\t# a scene, avoiding the need to move the deformer to trigger the update.\n\tif dm_compute_rest_distances:\n\t\tdm_compute_rest_distances = false\n\t\tdm_update_deformables()\n\n\nfunc _on_begin_update(d: DeformableMeshInstance3D) -> void:\n\t# When rest pose is active, only the rest position is stored,\n\t# and no deformation occurs.\n\tif rest_pose:\n\t\tdm_rest_pos = d.to_local(self.global_position)\n\t\tself.set_meta(\"dm_rest_pos\", dm_rest_pos)\n\t\treturn\n\t\t\n\t# Clear previous data if recomputation of distances is needed.\n\tif dm_compute_rest_distances or dm_needs_computation(d):\n\t\tdm_active_deformable = d\n\t\tdm_active_mesh = d.original_mesh\n\t\tdm_rest_distances.clear()\n\t\tdm_compute_rest_distances = true\n\t\treturn\n\t\t\n\t# Otherwise, compute the deformation translation vector.\n\tdm_vertex_index = 0\n\tdm_delta_translation = d.to_local(self.global_position) - dm_rest_pos\n\n\nfunc _on_update_vertex(v: Vector3) -> Vector3:\n\t# If in rest pose mode, return the vertex unchanged.\n\tif rest_pose:\n\t\treturn v\t\n\n\t# Compute and store rest distances if needed, without deforming the vertex.\n\tif dm_compute_rest_distances:\n\t\tvar d = dm_rest_pos.distance_to(v)\n\t\tdm_rest_distances.push_back(d)\n\t\treturn v\n\n\t# Retrieve the rest distance for the current vertex.\n\tvar rest_distance = dm_rest_distances[dm_vertex_index]\n\tdm_vertex_index += 1\n\n\tvar delta_radius = radius - rest_distance\n\tif delta_radius > 0.0:\n\t\t# Apply deformation using an eased interpolation factor.\n\t\tvar t = strength * ease(delta_radius / radius, attenuation)\n\t\tv += dm_delta_translation * t\n\t\n\treturn v\n"
  },
  {
    "path": "addons/deformablemesh/dm_drag_deformer.gd.uid",
    "content": "uid://btbnin5d1s6y0\n"
  },
  {
    "path": "addons/deformablemesh/dm_spherical_deformer.gd",
    "content": "# Copyright (C) 2023-2024 Claudio Z. (cloudofoz)\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n@tool\nextends \"dm_deformer.gd\"\n\n#---------------------------------------------------------------------------------------------------\n# PUBLIC VARIABLES\n#---------------------------------------------------------------------------------------------------\n@export_category(\"Spherical Deformer\")\n\n## Radius of the deformation sphere.\n@export var radius: float = 1.5:\n\tset(value):\n\t\tradius = value\n\t\tdm_update_deformables()\n\t\tself.scale = Vector3(radius, radius, radius)\n\n## Strength of the deformation.\n@export var strength: float = 1.5:\n\tset(value):\n\t\tstrength = value\n\t\tdm_update_deformables()\n\n## Falloff of the deformation, based on distance from the center.\n@export_exp_easing(\"attenuation\") var attenuation: float = 1.0:\n\tset(value):\n\t\tattenuation = value\n\t\tdm_update_deformables()\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE VARIABLES\n#---------------------------------------------------------------------------------------------------\n\nvar dm_deformable_local_pos: Vector3\n\n#---------------------------------------------------------------------------------------------------\n# VIRTUAL METHODS\n#---------------------------------------------------------------------------------------------------\n\nfunc _on_begin_update(d: DeformableMeshInstance3D) -> void:\n\tdm_deformable_local_pos = d.to_local(self.global_position)\n\nfunc _on_update_vertex(v: Vector3) -> Vector3:\n\tvar d = dm_deformable_local_pos.distance_to(v)\n\tvar delta = radius - d\n\tif(delta <= 0): return v\n\tvar k = strength * ease(delta / radius, attenuation)  \n\tvar n = (dm_deformable_local_pos - v).normalized()\n\tv -= n * k\n\treturn v\n"
  },
  {
    "path": "addons/deformablemesh/dm_spherical_deformer.gd.uid",
    "content": "uid://y1tsa0v2pepl\n"
  },
  {
    "path": "addons/deformablemesh/dm_std_deformer.gd",
    "content": "# Copyright (C) 2023-2024 Claudio Z. (cloudofoz)\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n@tool\nextends \"dm_deformer.gd\"\n\n#---------------------------------------------------------------------------------------------------\n# CONSTANTS\n#---------------------------------------------------------------------------------------------------\n\nconst dm_eps = 0.0001\n\nconst dm_ref_axis = [Vector3.MODEL_LEFT, Vector3.MODEL_TOP, Vector3.MODEL_FRONT]\n\n#---------------------------------------------------------------------------------------------------\n# PUBLIC VARIABLES\n#---------------------------------------------------------------------------------------------------\n@export_category(\"Standard Deformer\")\n\n## Deformer Type\n@export_enum(\"Bend:0\", \"Twist:1\", \"Taper:2\") \nvar type = 0:\n\tset(value):\n\t\ttype = value\n\t\tdm_update_deformables()\n\n## Main deformation axis.\n@export_enum(\"X:0\", \"Y:1\", \"Z:2\") \nvar main_axis = 1:\n\tset(value):\n\t\tmain_axis = value\n\t\tif value == second_axis:\n\t\t\tif is_node_ready():\n\t\t\t\tpush_warning(\"Main axis has to be different from the secondary axis\")\n\t\t\tdm_axis_internal_update = true\n\t\t\tsecond_axis = ( value + 1 ) % 3\n\t\t\tdm_axis_internal_update = false\n\t\tdm_third_axis = dm_find_third_axis(main_axis, second_axis)\n\t\tdm_update_deformables()\n\n# Secondary axis.\n@export_enum(\"X:0\", \"Y:1\", \"Z:2\") \nvar second_axis = 0:\n\tset(value):\n\t\tif value != main_axis:\n\t\t\tsecond_axis = value\n\t\telse:\n\t\t\tif is_node_ready():\n\t\t\t\tpush_warning(\"Secondary axis has to be different from the main axis\")\n\t\t\tsecond_axis = ( value + 1 ) % 3\n\t\tif !dm_axis_internal_update:\n\t\t\tdm_third_axis = dm_find_third_axis(main_axis, second_axis)\n\t\t\tdm_update_deformables()\n\n@export_subgroup(\"Blend - Twist\", \"bending_\")\n\n## Bending / Twisting angle\n@export_range(-360, +360, 5, \"degrees\",  \"or_greater\", \"or_less\")\nvar bending_angle: int = 35:\n\tset(value):\n\t\tbending_angle = value\n\t\tdm_bending_angle = deg_to_rad(value) if abs(value) >= dm_eps else dm_eps\n\t\tdm_update_deformables()\n\n@export_subgroup(\"Taper\", \"taper_\")\n\n# Taper Factor\n@export_range(-2.0, 2.0, 0.25, \"or_greater\", \"or_less\")\nvar taper_factor: float = 0:\n\tset(value):\n\t\ttaper_factor = value\n\t\tdm_update_deformables()\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE VARIABLES\n#---------------------------------------------------------------------------------------------------\n\nvar dm_axis_internal_update: bool = false\n\nvar dm_third_axis: float    = 2\n\nvar dm_bending_angle: float = deg_to_rad(bending_angle)\n\nvar dm_radius: float\n\nvar dm_local_pos: Vector3\n\nvar dm_length: float\n\n#---------------------------------------------------------------------------------------------------\n# STATIC METHODS\n#---------------------------------------------------------------------------------------------------\n\nstatic func dm_vsub(v1: Vector3, v2: Vector3, i: int) -> float:\n\treturn abs(v1[i] - v2[i])\n\t\nstatic func dm_find_third_axis(a: int, b: int) -> int:\n\tfor c in range(3):\n\t\tif c != a && c != b: \n\t\t\treturn c\n\treturn -1\n\n#---------------------------------------------------------------------------------------------------\n# VIRTUAL METHODS\n#---------------------------------------------------------------------------------------------------\n\nfunc _on_begin_update(d: DeformableMeshInstance3D) -> void:\n\tvar aabb = d.original_mesh.get_aabb()\n\tdm_local_pos = d.to_local(self.global_position)\n\t\n\tdm_length = aabb.size[main_axis]\n\tdm_radius = dm_length / dm_bending_angle\n\nfunc _on_update_vertex(v: Vector3) -> Vector3:\n\tmatch(type):\n\t\t0: return dm_bend_deform(v)\n\t\t1: return dm_twist_deform(v)\n\t\t2: return dm_taper_deform(v)\n\treturn v\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE METHODS\n#---------------------------------------------------------------------------------------------------\n\nfunc dm_bend_deform(v: Vector3) -> Vector3:\n\tvar p = v.rotated(dm_ref_axis[main_axis], self.rotation[main_axis])\n\tvar alpha = dm_bending_angle * ( p[main_axis] - dm_local_pos[main_axis] ) / dm_length\n\tvar r = dm_radius + p[second_axis]\n\tvar out: Vector3\n\tout[main_axis] = r * sin(alpha) + dm_local_pos[main_axis]\n\tout[second_axis] = r * cos(alpha) - dm_radius\n\tout[dm_third_axis] = p[dm_third_axis]\n\treturn out\n\nfunc dm_twist_deform(v: Vector3) -> Vector3:\n\tvar alpha = dm_bending_angle * ( v[main_axis] - dm_local_pos[main_axis] ) / dm_length\n\tvar p = v.rotated(dm_ref_axis[main_axis], alpha)\n\treturn p\n\nfunc dm_taper_deform(v: Vector3) -> Vector3:\n\tvar h = dm_length - dm_local_pos[main_axis] if v[main_axis] >= dm_local_pos[main_axis] else dm_local_pos[main_axis]\n\tvar f = taper_factor * (v[main_axis]- dm_local_pos[main_axis]) / h\n\t\n\tvar sec_axis_pos = v[second_axis] + v[second_axis] * f\n\tif sign(sec_axis_pos) != sign(v[second_axis]): sec_axis_pos = 0\n\tvar trd_axis_pos = v[dm_third_axis] + v[dm_third_axis] * f\n\tif sign(trd_axis_pos) != sign(v[dm_third_axis]): trd_axis_pos = 0\n\t\n\tv[second_axis] = sec_axis_pos\n\tv[dm_third_axis] = trd_axis_pos\n\treturn v\n"
  },
  {
    "path": "addons/deformablemesh/dm_std_deformer.gd.uid",
    "content": "uid://c0qauxqxaunnv\n"
  },
  {
    "path": "addons/deformablemesh/dm_surface_data.gd",
    "content": "# Copyright (C) 2023-2024 Claudio Z. (cloudofoz)\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n@tool\nextends Object\n\n#---------------------------------------------------------------------------------------------------\n# CONSTANTS\n#---------------------------------------------------------------------------------------------------\n\nconst Deformer = preload(\"dm_deformer.gd\")\n\nconst DeformableMeshInstance3D = preload(\"dm_deformable_mesh.gd\")\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE VARIABLES\n#---------------------------------------------------------------------------------------------------\n\nvar dm_vpos: PackedVector3Array\nvar dm_uvcoords: PackedVector2Array\nvar dm_indices: PackedInt32Array\nvar dm_st: SurfaceTool = null\n\nvar dm_has_indices: bool = true\nvar dm_has_uv: bool = true\n\n#---------------------------------------------------------------------------------------------------\n# PRIVATE METHODS\n#---------------------------------------------------------------------------------------------------\n\n#---------------------------------------------------------------------------------------------------\n# PUBLIC METHODS\n#---------------------------------------------------------------------------------------------------\n\n## Uses specified surface of given mesh to pupulate data of SurfaceData\nfunc create_from_surface(mesh: Mesh, surface_index: int):\n\tassert(mesh && surface_index >= 0)\n\tif(!self.dm_st): self.dm_st = SurfaceTool.new()\n\telse: self.dm_mesh_data.clear()\n\tvar dm_arrays = mesh.surface_get_arrays(surface_index)\n\tdm_vpos = dm_arrays[Mesh.ARRAY_VERTEX]\n\tif dm_arrays[Mesh.ARRAY_INDEX]:\n\t\tdm_indices = dm_arrays[Mesh.ARRAY_INDEX]\n\telse: dm_has_indices = false\n\tif dm_arrays[Mesh.ARRAY_TEX_UV]:\n\t\tdm_uvcoords = dm_arrays[Mesh.ARRAY_TEX_UV]\n\telse: dm_has_uv = false\n\n## Generate a deformed mesh surface from an array of deformers\nfunc update_surface(deformers: Array[Deformer], deformable: DeformableMeshInstance3D) -> void:\n\tassert(dm_st)\n\tvar vcount = dm_vpos.size()\n\tvar icount = dm_indices.size()\n\tdm_st.clear()\n\tdm_st.begin(Mesh.PRIMITIVE_TRIANGLES)\n\tfor vidx in range(vcount):\n\t\tvar v = dm_vpos[vidx]\n\t\tfor deformer in deformers:\n\t\t\tif(!deformer.visible): continue\n\t\t\tv = deformer._on_update_vertex(v)\n\t\tif dm_has_uv:\n\t\t\tdm_st.set_uv(dm_uvcoords[vidx])\n\t\tdm_st.add_vertex(v)\n\tif dm_has_indices:\n\t\tfor idx in range(icount):\n\t\t\tdm_st.add_index(dm_indices[idx])\n\n## Adds a new surface to a specified mesh with edited data\nfunc commit_to_surface(mesh: ArrayMesh):\n\tassert(mesh && dm_st)\n\tdm_st.generate_normals()\n\tmesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, dm_st.commit_to_arrays())\n"
  },
  {
    "path": "addons/deformablemesh/dm_surface_data.gd.uid",
    "content": "uid://dlrcubdpvkf5o\n"
  },
  {
    "path": "addons/deformablemesh/plugin.cfg",
    "content": "[plugin]\n\nname=\"DeformableMesh\"\ndescription=\"This addon enables real-time deformation of 3D meshes using customizable deformers. This version includes the following deformer nodes: SphericalDeformer, SimpleDeformer (bend, twist, taper) and DragDeformer.\"\nauthor=\"cloudofoz\"\nversion=\"0.40\"\nscript=\"plugin.gd\"\n"
  },
  {
    "path": "addons/deformablemesh/plugin.gd",
    "content": "# Copyright (C) 2023-2024 Claudio Z. (cloudofoz)\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n@tool\nextends EditorPlugin\n\n\nfunc _enter_tree() -> void:\n\tadd_custom_type(\"DragDeformer\", \"MeshInstance3D\", preload(\"dm_drag_deformer.gd\"), preload(\"dm_icon_drag_deformer.svg\"))\n\tadd_custom_type(\"SphericalDeformer\", \"MeshInstance3D\", preload(\"dm_spherical_deformer.gd\"), preload(\"dm_icon_spherical_deformer.svg\"))\n\tadd_custom_type(\"StandardDeformer\", \"MeshInstance3D\", preload(\"dm_std_deformer.gd\"), preload(\"dm_icon_std_deformer.svg\"))\n\tadd_custom_type(\"DeformableMeshInstance3D\", \"MeshInstance3D\", preload(\"dm_deformable_mesh.gd\"), preload(\"dm_icon_deformable_mesh.svg\"))\n\n\nfunc _exit_tree() -> void:\n\tremove_custom_type(\"DragDeformer\")\n\tremove_custom_type(\"SphericalDeformer\")\n\tremove_custom_type(\"StandardDeformer\")\n\tremove_custom_type(\"DeformableMeshInstance3D\")\n"
  },
  {
    "path": "addons/deformablemesh/plugin.gd.uid",
    "content": "uid://coabw0coyhvo6\n"
  }
]