├── .gitattributes ├── .gitignore ├── LICENSE ├── addons └── csg_toolkit │ ├── csg_toolkit.gd │ ├── demo │ ├── DemoWorld.tscn │ ├── new_shader_material.tres │ └── red.material │ ├── plugin.cfg │ ├── res │ ├── demo-image.png │ ├── demo-image.png.import │ ├── icon.png │ ├── icon.png.import │ ├── icons │ │ ├── box.svg │ │ ├── box.svg.import │ │ ├── config.svg │ │ ├── config.svg.import │ │ ├── cyliner.svg │ │ ├── cyliner.svg.import │ │ ├── empty-material.svg │ │ ├── empty-material.svg.import │ │ ├── intersection.svg │ │ ├── intersection.svg.import │ │ ├── mesh.svg │ │ ├── mesh.svg.import │ │ ├── polygon.svg │ │ ├── polygon.svg.import │ │ ├── sphere.svg │ │ ├── sphere.svg.import │ │ ├── subtraction.svg │ │ ├── subtraction.svg.import │ │ ├── torus.svg │ │ ├── torus.svg.import │ │ ├── union.svg │ │ └── union.svg.import │ ├── image.png.import │ └── operation_group.tres │ ├── scenes │ ├── config_window.tscn │ ├── csg_force_refresh_button.tscn │ └── csg_toolkit_bar.tscn │ └── scripts │ ├── config_window.gd │ ├── csg_force_refresh_button.gd │ ├── csg_repeater_3d.gd │ ├── csg_spreader_3d.gd │ ├── csg_toolkit_bar.gd │ └── csg_toolkit_config.gd ├── project.godot └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOL for all files that Git considers text files. 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Godot 4+ specific ignores 2 | .godot/ 3 | .builds/ 4 | addons/csg_toolkit/csg_toolkit_config.cfg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 LuckyTeapot / IIFabixn (Fabian Becker) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /addons/csg_toolkit/csg_toolkit.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name CsgToolkit extends EditorPlugin 3 | @onready var config: CsgTkConfig: 4 | get: 5 | return get_tree().root.get_node_or_null(AUTOLOAD_NAME) as CsgTkConfig 6 | var dock: CSGToolkitBar 7 | var repeater_refresh_button: CSGForceUpdateButton 8 | const AUTOLOAD_NAME = "CsgToolkitAutoload" 9 | static var csg_plugin_path 10 | func _enter_tree(): 11 | # Config 12 | add_autoload_singleton(AUTOLOAD_NAME, "res://addons/csg_toolkit/scripts/csg_toolkit_config.gd") 13 | csg_plugin_path = get_path() 14 | # Nodes 15 | add_custom_type("CSGRepeater3D", "CSGCombiner3D", preload("res://addons/csg_toolkit/scripts/csg_repeater_3d.gd"), null) 16 | add_custom_type("CSGSpreader3D", "CSGCombiner3D", preload("res://addons/csg_toolkit/scripts/csg_spreader_3d.gd"), null) 17 | # Toolkit bar 18 | var dockScene = preload("res://addons/csg_toolkit/scenes/csg_toolkit_bar.tscn") 19 | dock = dockScene.instantiate() 20 | # Repeater Button 21 | var force_update_button = preload("res://addons/csg_toolkit/scenes/csg_force_refresh_button.tscn") 22 | repeater_refresh_button = force_update_button.instantiate() 23 | # mesh converter button 24 | add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_SIDE_LEFT, dock) 25 | add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, repeater_refresh_button) 26 | 27 | func _exit_tree(): 28 | remove_custom_type("CSGRepeater3D") 29 | remove_custom_type("CSGSpreader3D") 30 | 31 | remove_autoload_singleton(AUTOLOAD_NAME) 32 | remove_control_from_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_SIDE_LEFT, dock) 33 | remove_control_from_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, repeater_refresh_button) 34 | dock.free() 35 | -------------------------------------------------------------------------------- /addons/csg_toolkit/demo/DemoWorld.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://bltlelosbn4ky"] 2 | 3 | [ext_resource type="Script" path="res://addons/csg_toolkit/scripts/csg_spreader_3d.gd" id="1_oripl"] 4 | [ext_resource type="Script" path="res://addons/csg_toolkit/scripts/csg_repeater_3d.gd" id="2_fsnkg"] 5 | 6 | [node name="DemoWorld" type="Node3D"] 7 | 8 | [node name="CSGSpreader3D" type="CSGCombiner3D" parent="."] 9 | script = ExtResource("1_oripl") 10 | template_node_path = NodePath("CSGRepeater3D") 11 | allow_rotation = true 12 | 13 | [node name="CSGRepeater3D" type="CSGCombiner3D" parent="CSGSpreader3D"] 14 | script = ExtResource("2_fsnkg") 15 | template_node_path = NodePath("CSGCombiner3D") 16 | repeat = Vector3(2, 3, 1) 17 | spacing = Vector3(2, 1.5, 1) 18 | 19 | [node name="CSGCombiner3D" type="CSGCombiner3D" parent="CSGSpreader3D/CSGRepeater3D"] 20 | 21 | [node name="CSGBox3D" type="CSGBox3D" parent="CSGSpreader3D/CSGRepeater3D/CSGCombiner3D"] 22 | 23 | [node name="CSGBox3D" type="CSGBox3D" parent="CSGSpreader3D/CSGRepeater3D/CSGCombiner3D/CSGBox3D"] 24 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.318927, 0.602158, -0.501595) 25 | -------------------------------------------------------------------------------- /addons/csg_toolkit/demo/new_shader_material.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" format=3 uid="uid://bvlrolerfilhd"] 2 | 3 | [resource] 4 | -------------------------------------------------------------------------------- /addons/csg_toolkit/demo/red.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IIFabixn/CSG_Toolkit/197fc895cd9ee61497b55717ffa5bc3faec4a01f/addons/csg_toolkit/demo/red.material -------------------------------------------------------------------------------- /addons/csg_toolkit/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="CSG Toolkit - Enhance Your Blockout Speed" 4 | description="Enhance your blockout workflow with the CSG Toolkit. This tool adds quick access buttons to the left toolbar for easy addition of CSG nodes. By pressing SHIFT, you can efficiently add the selected CSG as a child node. The toolkit also automatically preselects operations, streamlining your process. Additionally, shortcuts are available for CSG nodes or children of CSG combiners, further boosting your productivity." 5 | author="LuckyTepot" 6 | version="1.6.0" 7 | script="csg_toolkit.gd" 8 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/demo-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IIFabixn/CSG_Toolkit/197fc895cd9ee61497b55717ffa5bc3faec4a01f/addons/csg_toolkit/res/demo-image.png -------------------------------------------------------------------------------- /addons/csg_toolkit/res/demo-image.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://d3biubbsy5rmr" 6 | path="res://.godot/imported/demo-image.png-239231e5e25f0563a6646f0443acfa4e.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/csg_toolkit/res/demo-image.png" 14 | dest_files=["res://.godot/imported/demo-image.png-239231e5e25f0563a6646f0443acfa4e.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IIFabixn/CSG_Toolkit/197fc895cd9ee61497b55717ffa5bc3faec4a01f/addons/csg_toolkit/res/icon.png -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://c10bvkyvb2xdd" 6 | path="res://.godot/imported/icon.png-4ba3e0a5d510aafd8e055683d8699174.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/csg_toolkit/res/icon.png" 14 | dest_files=["res://.godot/imported/icon.png-4ba3e0a5d510aafd8e055683d8699174.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/box.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/box.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cjxx30pcamj36" 6 | path="res://.godot/imported/box.svg-24afd61c89464af4af9f4d845ca57b9a.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/csg_toolkit/res/icons/box.svg" 15 | dest_files=["res://.godot/imported/box.svg-24afd61c89464af4af9f4d845ca57b9a.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=true 39 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/config.svg: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/config.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://clgooji83dl4u" 6 | path="res://.godot/imported/config.svg-dd635575de604576026d414163f67266.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/csg_toolkit/res/icons/config.svg" 14 | dest_files=["res://.godot/imported/config.svg-dd635575de604576026d414163f67266.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/cyliner.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/cyliner.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dioxt3oaqvsi3" 6 | path="res://.godot/imported/cyliner.svg-50489df51cf1e8dde56b511c63cd2437.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/csg_toolkit/res/icons/cyliner.svg" 15 | dest_files=["res://.godot/imported/cyliner.svg-50489df51cf1e8dde56b511c63cd2437.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=true 39 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/empty-material.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/empty-material.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cg5jbylrlg00x" 6 | path="res://.godot/imported/empty-material.svg-3f6f61e9606d6bae9d37867d9ac3ad0b.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/csg_toolkit/res/icons/empty-material.svg" 14 | dest_files=["res://.godot/imported/empty-material.svg-3f6f61e9606d6bae9d37867d9ac3ad0b.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/intersection.svg: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/intersection.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://2kohi3tb3c70" 6 | path="res://.godot/imported/intersection.svg-a7d56bc571616c4c8343b7fe260d4607.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/csg_toolkit/res/icons/intersection.svg" 14 | dest_files=["res://.godot/imported/intersection.svg-a7d56bc571616c4c8343b7fe260d4607.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/mesh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/mesh.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bnpu878eanspj" 6 | path="res://.godot/imported/mesh.svg-156308ec8458ed846eae996bc130ccbc.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/csg_toolkit/res/icons/mesh.svg" 15 | dest_files=["res://.godot/imported/mesh.svg-156308ec8458ed846eae996bc130ccbc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=true 39 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/polygon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/polygon.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cjps2pofcsfc0" 6 | path="res://.godot/imported/polygon.svg-9526fe3ac0cb0791e6339d67ae6afbcf.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/csg_toolkit/res/icons/polygon.svg" 15 | dest_files=["res://.godot/imported/polygon.svg-9526fe3ac0cb0791e6339d67ae6afbcf.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=true 39 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/sphere.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/sphere.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://kpld1ou63wlf" 6 | path="res://.godot/imported/sphere.svg-c7c8c1311207415ed880ee6c5e1e06f9.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/csg_toolkit/res/icons/sphere.svg" 15 | dest_files=["res://.godot/imported/sphere.svg-c7c8c1311207415ed880ee6c5e1e06f9.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=true 39 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/subtraction.svg: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/subtraction.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://snbhkpq6sh4j" 6 | path="res://.godot/imported/subtraction.svg-9afd3882eada513c9c6754b2b38f150f.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/csg_toolkit/res/icons/subtraction.svg" 14 | dest_files=["res://.godot/imported/subtraction.svg-9afd3882eada513c9c6754b2b38f150f.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/torus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/torus.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://gbgmyv4bknqo" 6 | path="res://.godot/imported/torus.svg-73f1780e51211292acb9e9d40bb4276f.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/csg_toolkit/res/icons/torus.svg" 15 | dest_files=["res://.godot/imported/torus.svg-73f1780e51211292acb9e9d40bb4276f.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=true 39 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/union.svg: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/icons/union.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://sc7itwu80oi3" 6 | path="res://.godot/imported/union.svg-330af8601d6493b573ab68d43d4b23f3.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/csg_toolkit/res/icons/union.svg" 14 | dest_files=["res://.godot/imported/union.svg-330af8601d6493b573ab68d43d4b23f3.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/image.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://d0dy7wteea7l5" 6 | path="res://.godot/imported/image.png-e18db3df6f24d50b719c17a226c337bd.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/csg_toolkit/res/image.png" 14 | dest_files=["res://.godot/imported/image.png-e18db3df6f24d50b719c17a226c337bd.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /addons/csg_toolkit/res/operation_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ButtonGroup" format=3 uid="uid://wxtkg1wlxka8"] 2 | 3 | [resource] 4 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scenes/config_window.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://dts41g6camqwq"] 2 | 3 | [ext_resource type="Script" path="res://addons/csg_toolkit/scripts/config_window.gd" id="1_pigko"] 4 | 5 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ng5lh"] 6 | 7 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_vj6tm"] 8 | 9 | [node name="ConfigWindow" type="Window"] 10 | title = "CSG Toolit Configuration" 11 | initial_position = 1 12 | size = Vector2i(480, 360) 13 | popup_window = true 14 | script = ExtResource("1_pigko") 15 | 16 | [node name="MarginContainer" type="MarginContainer" parent="."] 17 | anchors_preset = 15 18 | anchor_right = 1.0 19 | anchor_bottom = 1.0 20 | grow_horizontal = 2 21 | grow_vertical = 2 22 | theme_override_constants/margin_left = 8 23 | theme_override_constants/margin_top = 8 24 | theme_override_constants/margin_right = 8 25 | theme_override_constants/margin_bottom = 8 26 | 27 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] 28 | layout_mode = 2 29 | size_flags_horizontal = 3 30 | theme_override_constants/separation = 8 31 | 32 | [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] 33 | layout_mode = 2 34 | 35 | [node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"] 36 | layout_mode = 2 37 | text = "Default Behavior" 38 | 39 | [node name="VSeparator" type="VSeparator" parent="MarginContainer/VBoxContainer/HBoxContainer"] 40 | layout_mode = 2 41 | size_flags_horizontal = 3 42 | theme_override_styles/separator = SubResource("StyleBoxEmpty_ng5lh") 43 | 44 | [node name="OptionButton" type="OptionButton" parent="MarginContainer/VBoxContainer/HBoxContainer"] 45 | layout_mode = 2 46 | item_count = 2 47 | selected = 0 48 | popup/item_0/text = "Sibling" 49 | popup/item_0/id = 0 50 | popup/item_1/text = "Child" 51 | popup/item_1/id = 1 52 | 53 | [node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] 54 | layout_mode = 2 55 | 56 | [node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer2"] 57 | layout_mode = 2 58 | text = "Action Key" 59 | 60 | [node name="VSeparator" type="VSeparator" parent="MarginContainer/VBoxContainer/HBoxContainer2"] 61 | layout_mode = 2 62 | size_flags_horizontal = 3 63 | theme_override_styles/separator = SubResource("StyleBoxEmpty_ng5lh") 64 | 65 | [node name="Button" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer2"] 66 | layout_mode = 2 67 | text = "Shift" 68 | 69 | [node name="HBoxContainer3" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] 70 | layout_mode = 2 71 | 72 | [node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer3"] 73 | layout_mode = 2 74 | text = "Auto Hide" 75 | 76 | [node name="VSeparator" type="VSeparator" parent="MarginContainer/VBoxContainer/HBoxContainer3"] 77 | layout_mode = 2 78 | size_flags_horizontal = 3 79 | theme_override_styles/separator = SubResource("StyleBoxEmpty_ng5lh") 80 | 81 | [node name="CheckButton" type="CheckBox" parent="MarginContainer/VBoxContainer/HBoxContainer3"] 82 | layout_mode = 2 83 | 84 | [node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"] 85 | layout_mode = 2 86 | size_flags_vertical = 3 87 | theme_override_styles/separator = SubResource("StyleBoxEmpty_vj6tm") 88 | 89 | [node name="Save" type="Button" parent="MarginContainer/VBoxContainer"] 90 | layout_mode = 2 91 | text = "Save" 92 | 93 | [node name="HSeparator2" type="HSeparator" parent="MarginContainer/VBoxContainer"] 94 | layout_mode = 2 95 | 96 | [node name="Ko-Fi" type="LinkButton" parent="MarginContainer/VBoxContainer"] 97 | layout_mode = 2 98 | size_flags_horizontal = 4 99 | text = "Support me on Ko-Fi" 100 | underline = 1 101 | uri = "https://ko-fi.com/luckyteapot" 102 | 103 | [connection signal="item_selected" from="MarginContainer/VBoxContainer/HBoxContainer/OptionButton" to="." method="_on_option_button_item_selected"] 104 | [connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer2/Button" to="." method="_on_button_pressed"] 105 | [connection signal="toggled" from="MarginContainer/VBoxContainer/HBoxContainer3/CheckButton" to="." method="_on_check_box_toggled"] 106 | [connection signal="pressed" from="MarginContainer/VBoxContainer/Save" to="." method="_on_save_pressed"] 107 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scenes/csg_force_refresh_button.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://ver5l21tu05h"] 2 | 3 | [ext_resource type="Script" path="res://addons/csg_toolkit/scripts/csg_force_refresh_button.gd" id="1_xphgr"] 4 | 5 | [node name="CsgRefreshRepeaterButton" type="Button"] 6 | anchors_preset = 15 7 | anchor_right = 1.0 8 | anchor_bottom = 1.0 9 | grow_horizontal = 2 10 | grow_vertical = 2 11 | text = "Force Update CSG" 12 | script = ExtResource("1_xphgr") 13 | 14 | [connection signal="pressed" from="." to="." method="_on_pressed"] 15 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scenes/csg_toolkit_bar.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=15 format=3 uid="uid://cdjxmp0p1bbup"] 2 | 3 | [ext_resource type="Script" path="res://addons/csg_toolkit/scripts/csg_toolkit_bar.gd" id="1_guypd"] 4 | [ext_resource type="Texture2D" uid="uid://cjxx30pcamj36" path="res://addons/csg_toolkit/res/icons/box.svg" id="2_iwjnu"] 5 | [ext_resource type="Texture2D" uid="uid://dioxt3oaqvsi3" path="res://addons/csg_toolkit/res/icons/cyliner.svg" id="3_tedev"] 6 | [ext_resource type="Texture2D" uid="uid://bnpu878eanspj" path="res://addons/csg_toolkit/res/icons/mesh.svg" id="4_8ifcb"] 7 | [ext_resource type="Texture2D" uid="uid://cjps2pofcsfc0" path="res://addons/csg_toolkit/res/icons/polygon.svg" id="5_cc45h"] 8 | [ext_resource type="Texture2D" uid="uid://kpld1ou63wlf" path="res://addons/csg_toolkit/res/icons/sphere.svg" id="6_lwspd"] 9 | [ext_resource type="Texture2D" uid="uid://gbgmyv4bknqo" path="res://addons/csg_toolkit/res/icons/torus.svg" id="7_t1wb8"] 10 | [ext_resource type="Texture2D" uid="uid://sc7itwu80oi3" path="res://addons/csg_toolkit/res/icons/union.svg" id="8_4756x"] 11 | [ext_resource type="Texture2D" uid="uid://2kohi3tb3c70" path="res://addons/csg_toolkit/res/icons/intersection.svg" id="9_oukxm"] 12 | [ext_resource type="Texture2D" uid="uid://snbhkpq6sh4j" path="res://addons/csg_toolkit/res/icons/subtraction.svg" id="10_tb1b3"] 13 | [ext_resource type="Texture2D" uid="uid://clgooji83dl4u" path="res://addons/csg_toolkit/res/icons/config.svg" id="11_5p6ju"] 14 | [ext_resource type="Texture2D" uid="uid://cg5jbylrlg00x" path="res://addons/csg_toolkit/res/icons/empty-material.svg" id="11_r00bg"] 15 | 16 | [sub_resource type="ButtonGroup" id="ButtonGroup_2ipgb"] 17 | 18 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ixko7"] 19 | 20 | [node name="CsgToolkitBar" type="Control"] 21 | visible = false 22 | custom_minimum_size = Vector2(52, 0) 23 | layout_mode = 3 24 | anchors_preset = 9 25 | anchor_bottom = 1.0 26 | grow_vertical = 2 27 | script = ExtResource("1_guypd") 28 | 29 | [node name="MarginContainer" type="MarginContainer" parent="."] 30 | layout_mode = 1 31 | anchors_preset = 15 32 | anchor_right = 1.0 33 | anchor_bottom = 1.0 34 | offset_right = -2.0 35 | grow_horizontal = 2 36 | grow_vertical = 2 37 | theme_override_constants/margin_top = 8 38 | theme_override_constants/margin_bottom = 8 39 | 40 | [node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer"] 41 | layout_mode = 2 42 | horizontal_scroll_mode = 0 43 | 44 | [node name="HBoxContainer" type="VBoxContainer" parent="MarginContainer/ScrollContainer"] 45 | custom_minimum_size = Vector2(0, 120) 46 | layout_mode = 2 47 | size_flags_horizontal = 6 48 | size_flags_vertical = 3 49 | theme_override_constants/separation = 16 50 | alignment = 1 51 | 52 | [node name="CSG" type="VBoxContainer" parent="MarginContainer/ScrollContainer/HBoxContainer"] 53 | layout_mode = 2 54 | alignment = 1 55 | 56 | [node name="Box" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/CSG"] 57 | custom_minimum_size = Vector2(42, 42) 58 | layout_mode = 2 59 | tooltip_text = "Box" 60 | icon = ExtResource("2_iwjnu") 61 | icon_alignment = 1 62 | expand_icon = true 63 | 64 | [node name="Cylinder" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/CSG"] 65 | custom_minimum_size = Vector2(42, 42) 66 | layout_mode = 2 67 | tooltip_text = "Cylinder" 68 | theme_override_constants/icon_max_width = 24 69 | icon = ExtResource("3_tedev") 70 | icon_alignment = 1 71 | expand_icon = true 72 | 73 | [node name="Mesh" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/CSG"] 74 | custom_minimum_size = Vector2(42, 42) 75 | layout_mode = 2 76 | tooltip_text = "Mesh" 77 | theme_override_constants/icon_max_width = 24 78 | icon = ExtResource("4_8ifcb") 79 | icon_alignment = 1 80 | expand_icon = true 81 | 82 | [node name="Polygon" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/CSG"] 83 | custom_minimum_size = Vector2(42, 42) 84 | layout_mode = 2 85 | tooltip_text = "Polygon" 86 | theme_override_constants/icon_max_width = 24 87 | icon = ExtResource("5_cc45h") 88 | icon_alignment = 1 89 | expand_icon = true 90 | 91 | [node name="Sphere" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/CSG"] 92 | custom_minimum_size = Vector2(42, 42) 93 | layout_mode = 2 94 | tooltip_text = "Sphere" 95 | theme_override_constants/icon_max_width = 24 96 | icon = ExtResource("6_lwspd") 97 | icon_alignment = 1 98 | expand_icon = true 99 | 100 | [node name="Torus" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/CSG"] 101 | custom_minimum_size = Vector2(42, 42) 102 | layout_mode = 2 103 | tooltip_text = "Torus" 104 | theme_override_constants/icon_max_width = 24 105 | icon = ExtResource("7_t1wb8") 106 | icon_alignment = 1 107 | expand_icon = true 108 | 109 | [node name="Operation" type="VBoxContainer" parent="MarginContainer/ScrollContainer/HBoxContainer"] 110 | layout_mode = 2 111 | alignment = 1 112 | 113 | [node name="Union" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/Operation"] 114 | custom_minimum_size = Vector2(42, 42) 115 | layout_mode = 2 116 | tooltip_text = "Union" 117 | theme_override_constants/icon_max_width = 24 118 | toggle_mode = true 119 | button_group = SubResource("ButtonGroup_2ipgb") 120 | icon = ExtResource("8_4756x") 121 | icon_alignment = 1 122 | expand_icon = true 123 | 124 | [node name="Intersection" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/Operation"] 125 | custom_minimum_size = Vector2(42, 42) 126 | layout_mode = 2 127 | tooltip_text = "Intersection" 128 | theme_override_constants/icon_max_width = 24 129 | toggle_mode = true 130 | button_group = SubResource("ButtonGroup_2ipgb") 131 | icon = ExtResource("9_oukxm") 132 | icon_alignment = 1 133 | expand_icon = true 134 | 135 | [node name="Subtraction" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/Operation"] 136 | custom_minimum_size = Vector2(42, 42) 137 | layout_mode = 2 138 | tooltip_text = "Subtraction" 139 | theme_override_constants/icon_max_width = 24 140 | toggle_mode = true 141 | button_group = SubResource("ButtonGroup_2ipgb") 142 | icon = ExtResource("10_tb1b3") 143 | icon_alignment = 1 144 | expand_icon = true 145 | 146 | [node name="Material" type="VBoxContainer" parent="MarginContainer/ScrollContainer/HBoxContainer"] 147 | layout_mode = 2 148 | alignment = 1 149 | 150 | [node name="MaterialPicker" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/Material"] 151 | custom_minimum_size = Vector2(42, 42) 152 | layout_mode = 2 153 | tooltip_text = "Material" 154 | icon = ExtResource("11_r00bg") 155 | icon_alignment = 1 156 | expand_icon = true 157 | 158 | [node name="HSeparator" type="HSeparator" parent="MarginContainer/ScrollContainer/HBoxContainer"] 159 | layout_mode = 2 160 | size_flags_vertical = 3 161 | theme_override_styles/separator = SubResource("StyleBoxEmpty_ixko7") 162 | 163 | [node name="Options" type="VBoxContainer" parent="MarginContainer/ScrollContainer/HBoxContainer"] 164 | layout_mode = 2 165 | size_flags_horizontal = 4 166 | alignment = 1 167 | 168 | [node name="Config" type="Button" parent="MarginContainer/ScrollContainer/HBoxContainer/Options"] 169 | custom_minimum_size = Vector2(42, 42) 170 | layout_mode = 2 171 | tooltip_text = "Config" 172 | theme_override_constants/icon_max_width = 24 173 | icon = ExtResource("11_5p6ju") 174 | icon_alignment = 1 175 | 176 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/CSG/Box" to="." method="_on_box_pressed"] 177 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/CSG/Cylinder" to="." method="_on_cylinder_pressed"] 178 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/CSG/Mesh" to="." method="_on_mesh_pressed"] 179 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/CSG/Polygon" to="." method="_on_polygon_pressed"] 180 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/CSG/Sphere" to="." method="_on_sphere_pressed"] 181 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/CSG/Torus" to="." method="_on_torus_pressed"] 182 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/Operation/Union" to="." method="_on_operation_pressed" binds= [0]] 183 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/Operation/Intersection" to="." method="_on_operation_pressed" binds= [1]] 184 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/Operation/Subtraction" to="." method="_on_operation_pressed" binds= [2]] 185 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/Material/MaterialPicker" to="." method="_request_material"] 186 | [connection signal="pressed" from="MarginContainer/ScrollContainer/HBoxContainer/Options/Config" to="." method="_on_config_pressed"] 187 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scripts/config_window.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Window 3 | 4 | @onready var config: CsgTkConfig: 5 | get: return get_tree().root.get_node(CsgToolkit.AUTOLOAD_NAME) as CsgTkConfig 6 | @onready var action_key_button: Button = $MarginContainer/VBoxContainer/HBoxContainer2/Button 7 | @onready var default_behavior_option: OptionButton = $MarginContainer/VBoxContainer/HBoxContainer/OptionButton 8 | @onready var auto_hide_switch: CheckBox = $MarginContainer/VBoxContainer/HBoxContainer3/CheckButton 9 | signal key_press(key: InputEventKey) 10 | 11 | func _ready(): 12 | default_behavior_option.select(config.default_behavior) 13 | action_key_button.text = OS.get_keycode_string(config.action_key) 14 | auto_hide_switch.button_pressed = config.auto_hide 15 | 16 | func _on_option_button_item_selected(index): 17 | match index: 18 | 0: config.default_behavior = CsgTkConfig.CSGBehavior.SIBLING 19 | 1: config.default_behavior = CsgTkConfig.CSGBehavior.CHILD 20 | 21 | func _unhandled_input(event): 22 | if event is InputEventKey: 23 | if event.pressed: 24 | key_press.emit(event) 25 | 26 | func _on_save_pressed(): 27 | config.save_config() 28 | 29 | 30 | func _on_button_pressed(): 31 | var key_event: InputEventKey = await key_press 32 | config.action_key = key_event.keycode 33 | action_key_button.text = key_event.as_text_key_label() 34 | 35 | 36 | func _on_check_box_toggled(toggled_on): 37 | config.auto_hide = toggled_on 38 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scripts/csg_force_refresh_button.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name CSGForceUpdateButton extends Button 3 | 4 | func _enter_tree(): 5 | EditorInterface.get_selection().selection_changed.connect(_on_selection_changed) 6 | _on_selection_changed() 7 | 8 | func _exit_tree(): 9 | EditorInterface.get_selection().selection_changed.disconnect(_on_selection_changed) 10 | 11 | func _on_selection_changed(): 12 | var selection = EditorInterface.get_selection().get_selected_nodes() 13 | if selection.is_empty(): 14 | hide() 15 | elif selection[0] is CSGRepeater3D or selection[0] is CSGSpreader3D: 16 | show() 17 | else: 18 | hide() 19 | 20 | func _on_pressed(): 21 | var selection = EditorInterface.get_selection().get_selected_nodes() 22 | if (selection.is_empty()): 23 | return 24 | if selection[0] is CSGRepeater3D: 25 | selection[0].call("repeat_template") 26 | elif selection[0] is CSGSpreader3D: 27 | selection[0].call("spread_template") 28 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scripts/csg_repeater_3d.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name CSGRepeater3D extends CSGCombiner3D 3 | 4 | const REPEATER_NODE_META = "REPEATED_NODE_META" 5 | 6 | var _template_node_path: NodePath 7 | @export var template_node_path: NodePath: 8 | get: return _template_node_path 9 | set(value): 10 | _template_node_path = value 11 | repeat_template() 12 | 13 | var _repeat: Vector3 = Vector3.ONE 14 | @export var repeat := Vector3.ONE: 15 | get: 16 | return _repeat 17 | set(value): 18 | _repeat = value 19 | repeat_template() 20 | 21 | var _spacing: Vector3 = Vector3.ZERO 22 | @export var spacing := Vector3.ZERO: 23 | get: 24 | return _spacing 25 | set(value): 26 | _spacing = value 27 | repeat_template() 28 | 29 | func _ready() -> void: 30 | repeat_template() 31 | 32 | func _exit_tree(): 33 | if not Engine.is_editor_hint(): return 34 | 35 | func clear_children(): 36 | # Clear existing children except the template node 37 | for child in get_children(true): 38 | if child.has_meta(REPEATER_NODE_META): 39 | child.queue_free() # free repeated ndoes 40 | 41 | func repeat_template(): 42 | clear_children() 43 | 44 | var template_node = get_node_or_null(template_node_path) 45 | if not template_node: 46 | return 47 | 48 | # Clone and position the template node based on repeat and spacing 49 | for x in range(int(_repeat.x)): 50 | for y in range(int(_repeat.y)): 51 | for z in range(int(_repeat.z)): 52 | if x == 0 and y == 0 and z == 0: continue 53 | # Instance a new template node 54 | var instance = template_node.duplicate() 55 | instance.set_meta(REPEATER_NODE_META, true) 56 | # Position the instance 57 | var position = Vector3( 58 | x * (_spacing.x + template_node.transform.origin.x), 59 | y * (_spacing.y + template_node.transform.origin.y), 60 | z * (_spacing.z + template_node.transform.origin.z) 61 | ) 62 | instance.transform.origin = position 63 | # Add the instance to the combiner 64 | add_child(instance) 65 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scripts/csg_spreader_3d.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name CSGSpreader3D extends CSGCombiner3D 3 | 4 | const SPREADER_NODE_META = "SPREADER_NODE_META" 5 | 6 | var _template_node_path: NodePath 7 | @export var template_node_path: NodePath: 8 | get: return _template_node_path 9 | set(value): 10 | _template_node_path = value 11 | spread_template() 12 | 13 | var _max_count: int = 10 14 | @export var max_count: int = 10: 15 | get: return _max_count 16 | set(value): 17 | _max_count = value 18 | spread_template() 19 | 20 | var _noise_threshold: float = 0.5 21 | @export var noise_threshold: float = 0.5: 22 | get: return _noise_threshold 23 | set(value): 24 | _noise_threshold = value 25 | spread_template() 26 | 27 | var _seed: int = 0 28 | @export var seed: int = 0: 29 | get: return _seed 30 | set(value): 31 | _seed = value 32 | spread_template() 33 | 34 | var _spread_area = Vector3(10, 10, 10) 35 | ## Box area around this node. 36 | @export var spread_area: Vector3 = Vector3(10, 10, 10): 37 | get: return _spread_area 38 | set(value): 39 | _spread_area = value 40 | spread_template() 41 | 42 | var _allow_rotation: bool = false 43 | @export var allow_rotation: bool = false: 44 | get: return _allow_rotation 45 | set(value): 46 | _allow_rotation = value 47 | spread_template() 48 | 49 | func _ready(): 50 | spread_template() 51 | 52 | func clear_children(): 53 | # Clear existing children except the template node 54 | for child in get_children(true): 55 | if child.has_meta(SPREADER_NODE_META): 56 | child.queue_free() 57 | 58 | 59 | func spread_template(): 60 | clear_children() 61 | 62 | var template_node = get_node_or_null(template_node_path) 63 | if not template_node: 64 | return 65 | 66 | var rng = RandomNumberGenerator.new() 67 | if seed == 0: 68 | rng.randomize() 69 | else: 70 | rng.seed = seed 71 | 72 | # Spread the template node around the area 73 | for i in range(max_count): 74 | var instance = template_node.duplicate() 75 | instance.set_meta(SPREADER_NODE_META, true) 76 | # Position the instance 77 | var position = Vector3( 78 | rng.randf_range(-spread_area.x / 2, spread_area.x / 2), 79 | rng.randf_range(-spread_area.y / 2, spread_area.y / 2), 80 | rng.randf_range(-spread_area.z / 2, spread_area.z / 2) 81 | ) 82 | 83 | var noise_value = rng.randf() 84 | if noise_value > noise_threshold: 85 | instance.transform.origin = position 86 | if allow_rotation: 87 | instance.transform.basis = Basis().rotated(Vector3(0, 1, 0), rng.randf_range(0, 2 * PI)) 88 | add_child(instance) 89 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scripts/csg_toolkit_bar.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name CSGToolkitBar extends Control 3 | 4 | @onready var config: CsgTkConfig: 5 | get: 6 | return get_tree().root.get_node_or_null(CsgToolkit.AUTOLOAD_NAME) as CsgTkConfig 7 | 8 | var operation: CSGShape3D.Operation = CSGShape3D.OPERATION_UNION 9 | var selected_material: BaseMaterial3D 10 | var selected_shader: ShaderMaterial 11 | 12 | @onready var picker_button: Button = $MarginContainer/ScrollContainer/HBoxContainer/Material/MaterialPicker 13 | 14 | func _enter_tree(): 15 | EditorInterface.get_selection().selection_changed.connect(_on_selection_changed) 16 | 17 | func _exit_tree(): 18 | EditorInterface.get_selection().selection_changed.disconnect(_on_selection_changed) 19 | 20 | func _on_selection_changed(): 21 | if not config.auto_hide: 22 | return 23 | var selection = EditorInterface.get_selection().get_selected_nodes() 24 | if selection.any(func (node): return node is CSGShape3D): 25 | show() 26 | else: 27 | hide() 28 | 29 | func _ready(): 30 | picker_button.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER 31 | 32 | func _on_box_pressed(): 33 | create_csg(CSGBox3D) 34 | 35 | func _on_cylinder_pressed(): 36 | create_csg(CSGCylinder3D) 37 | 38 | func _on_mesh_pressed(): 39 | create_csg(CSGMesh3D) 40 | 41 | func _on_polygon_pressed(): 42 | create_csg(CSGPolygon3D) 43 | 44 | func _on_sphere_pressed(): 45 | create_csg(CSGSphere3D) 46 | 47 | func _on_torus_pressed(): 48 | create_csg(CSGTorus3D) 49 | 50 | # Operation Toggle 51 | func _on_operation_pressed(val): 52 | set_operation(val) 53 | 54 | 55 | func _on_config_pressed(): 56 | var config_view_scene = preload("res://addons/csg_toolkit/scenes/config_window.tscn") 57 | var config_view = config_view_scene.instantiate() 58 | config_view.close_requested.connect(func (): 59 | get_tree().root.remove_child(config_view) 60 | config_view.queue_free() 61 | ) 62 | get_tree().root.add_child(config_view) 63 | 64 | func _request_material(): 65 | var dialog = EditorFileDialog.new() 66 | dialog.title = "Select Material" 67 | dialog.display_mode = EditorFileDialog.DISPLAY_LIST 68 | dialog.filters = ["*.tres, *.material, *.res"] 69 | dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE 70 | dialog.position = ((EditorInterface.get_base_control().size / 2) as Vector2i) - dialog.size 71 | dialog.close_requested.connect(func (): 72 | get_tree().root.remove_child(dialog) 73 | dialog.queue_free() 74 | ) 75 | get_tree().root.add_child(dialog) 76 | dialog.show() 77 | var res_path = await dialog.file_selected 78 | var res = ResourceLoader.load(res_path) 79 | if res == null: 80 | return 81 | if res is BaseMaterial3D: 82 | update_material(res) 83 | elif res is ShaderMaterial: 84 | update_shader(res) 85 | else: 86 | return 87 | var previewer = EditorInterface.get_resource_previewer() 88 | previewer.queue_edited_resource_preview(res, self, "_update_picker_icon", null) 89 | 90 | func _update_picker_icon(path, preview, thumbnail, userdata): 91 | picker_button.icon = preview 92 | 93 | 94 | func set_operation(val: int): 95 | match val: 96 | 0: operation = CSGShape3D.OPERATION_UNION 97 | 1: operation = CSGShape3D.OPERATION_INTERSECTION 98 | 2: operation = CSGShape3D.OPERATION_SUBTRACTION 99 | _: operation = CSGShape3D.OPERATION_UNION 100 | 101 | func update_material(material: BaseMaterial3D): 102 | selected_material = material 103 | selected_shader = null 104 | 105 | func update_shader(shader: ShaderMaterial): 106 | selected_material = null 107 | selected_shader = shader 108 | 109 | func create_csg(type: Variant): 110 | var selected_nodes = EditorInterface.get_selection().get_selected_nodes() 111 | if selected_nodes.is_empty() or !(selected_nodes[0] is CSGShape3D): 112 | # Do not create a csg if not inside another csgshape 113 | return 114 | var selected_node: CSGShape3D = selected_nodes[0] 115 | var csg: CSGShape3D 116 | match type: 117 | CSGBox3D: 118 | csg = CSGBox3D.new() 119 | CSGCylinder3D: 120 | csg = CSGCylinder3D.new() 121 | CSGSphere3D: 122 | csg = CSGSphere3D.new() 123 | CSGMesh3D: 124 | csg = CSGMesh3D.new() 125 | CSGPolygon3D: 126 | csg = CSGPolygon3D.new() 127 | CSGTorus3D: 128 | csg = CSGTorus3D.new() 129 | 130 | csg.operation = operation 131 | if selected_material: 132 | csg.material = selected_material 133 | elif selected_shader: 134 | csg.material = selected_shader 135 | 136 | 137 | if (selected_node.get_owner() == null): 138 | return 139 | 140 | if Input.is_key_pressed(config.action_key): 141 | if config.default_behavior == CsgTkConfig.CSGBehavior.SIBLING: 142 | _add_as_child(selected_node, csg) 143 | elif config.default_behavior == CsgTkConfig.CSGBehavior.CHILD: 144 | _add_as_sibling(selected_node, csg) 145 | else: 146 | if config.default_behavior == CsgTkConfig.CSGBehavior.SIBLING: 147 | _add_as_sibling(selected_node, csg) 148 | elif config.default_behavior == CsgTkConfig.CSGBehavior.CHILD: 149 | _add_as_child(selected_node, csg) 150 | 151 | EditorInterface.get_selection().clear() 152 | EditorInterface.get_selection().add_node(csg) 153 | 154 | func _add_as_child(selected_node: CSGShape3D, csg: CSGShape3D): 155 | selected_node.add_child(csg, true) 156 | csg.owner = selected_node.get_owner() 157 | csg.global_position = selected_node.global_position 158 | 159 | func _add_as_sibling(selected_node: CSGShape3D, csg: CSGShape3D): 160 | selected_node.get_parent().add_child(csg, true) 161 | csg.owner = selected_node.get_owner() 162 | csg.global_position = selected_node.global_position 163 | -------------------------------------------------------------------------------- /addons/csg_toolkit/scripts/csg_toolkit_config.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Node 3 | class_name CsgTkConfig 4 | # Constants 5 | const CSG_TOOLKIT = "CSG_TOOLKIT" 6 | const DEFAULT_BEHAVIOR = "DEFAULT_BEHAVIOR" # sibling 7 | const ACTION_KEY = "ACTION_KEY" # shift 8 | const AUTO_HIDE = "AUTO_HIDE" # true 9 | 10 | # Configurable 11 | var default_behavior: CSGBehavior = CSGBehavior.SIBLING 12 | var action_key: Key = KEY_SHIFT 13 | var auto_hide: bool = true 14 | 15 | signal config_saved() 16 | 17 | func _enter_tree(): 18 | load_config() 19 | 20 | func save_config(): 21 | var config = ConfigFile.new() 22 | config.load("res://addons/csg_toolkit/csg_toolkit_config.cfg") 23 | config.set_value(CSG_TOOLKIT, DEFAULT_BEHAVIOR, default_behavior) 24 | config.set_value(CSG_TOOLKIT, ACTION_KEY, action_key) 25 | config.set_value(CSG_TOOLKIT, AUTO_HIDE, auto_hide) 26 | config.save("res://addons/csg_toolkit/csg_toolkit_config.cfg") 27 | print("CsgToolkit: Saved Config") 28 | config_saved.emit() 29 | 30 | func load_config(): 31 | var config = ConfigFile.new() 32 | if config.load("res://addons/csg_toolkit/csg_toolkit_config.cfg") == OK: 33 | default_behavior = config.get_value(CSG_TOOLKIT, DEFAULT_BEHAVIOR, default_behavior) 34 | action_key = config.get_value(CSG_TOOLKIT, ACTION_KEY, action_key) 35 | auto_hide = config.get_value(CSG_TOOLKIT, AUTO_HIDE, auto_hide) 36 | else: 37 | save_config() 38 | print("CsgToolkit: Loaded Config") 39 | 40 | 41 | enum CSGBehavior { SIBLING, CHILD } 42 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="CSG_Toolkit" 14 | run/main_scene="res://addons/csg_toolkit/demo/DemoWorld.tscn" 15 | config/features=PackedStringArray("4.3", "Forward Plus") 16 | boot_splash/show_image=false 17 | 18 | [autoload] 19 | 20 | CsgToolkitAutoload="*res://addons/csg_toolkit/scripts/csg_toolkit_config.gd" 21 | 22 | [dotnet] 23 | 24 | project/assembly_name="New Game Project" 25 | 26 | [editor_plugins] 27 | 28 | enabled=PackedStringArray("res://addons/csg_toolkit/plugin.cfg") 29 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |