diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..38a08fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Godot-specific ignores +.import/ +.export/ +export.cfg +export_presets.cfg + +# Imported translations (automatically generated from CSV files) +*.translation + +# Mono-specific ignores +.mono/ +data_*/ \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7440b53 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,7 @@ +Copyright 2022 Schrotty + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Node2D.tscn b/Node2D.tscn new file mode 100644 index 0000000..aa2010d --- /dev/null +++ b/Node2D.tscn @@ -0,0 +1,253 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://script/Demo.gd" type="Script" id=1] +[ext_resource path="res://script/PerlinWaterGenerator.gd" type="Script" id=3] + +[sub_resource type="GDScript" id=1] +script/source = "extends Control + +signal clicked + +func _gui_input(event): + if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.pressed: + emit_signal(\"clicked\") +" + +[node name="Node2D" type="Node2D"] +script = ExtResource( 1 ) + +[node name="PerlinWaterGenerator" type="Node2D" parent="."] +script = ExtResource( 3 ) + +[node name="ColorRect" type="ColorRect" parent="."] +margin_right = 900.0 +margin_bottom = 600.0 +color = Color( 0.278431, 0.278431, 0.278431, 1 ) + +[node name="TextureContainer" type="MarginContainer" parent="."] +margin_top = 109.0 +margin_right = 900.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +custom_constants/margin_right = 10 +custom_constants/margin_top = 10 +custom_constants/margin_left = 10 +custom_constants/margin_bottom = 10 + +[node name="Center" type="CenterContainer" parent="TextureContainer"] +margin_left = 10.0 +margin_top = 10.0 +margin_right = 890.0 +margin_bottom = 481.0 + +[node name="Texture" type="TextureRect" parent="TextureContainer/Center"] +margin_left = 440.0 +margin_top = 235.0 +margin_right = 440.0 +margin_bottom = 235.0 +expand = true +stretch_mode = 4 + +[node name="Panel" type="ColorRect" parent="."] +margin_right = 900.0 +margin_bottom = 109.0 +grow_horizontal = 2 +grow_vertical = 2 +rect_clip_content = true +color = Color( 0.211765, 0.211765, 0.211765, 1 ) + +[node name="Controls" type="GridContainer" parent="."] +anchor_right = 1.0 +margin_left = 10.0 +margin_top = 10.0 +margin_right = 890.0 +margin_bottom = 100.0 +custom_constants/vseparation = 15 +custom_constants/hseparation = 15 +columns = 4 + +[node name="Colors" type="GridContainer" parent="Controls"] +margin_right = 203.0 +margin_bottom = 55.0 +custom_constants/vseparation = 15 +custom_constants/hseparation = 10 +columns = 2 + +[node name="ForegroundLabel" type="Label" parent="Controls/Colors"] +margin_top = 3.0 +margin_right = 74.0 +margin_bottom = 17.0 +text = "Foreground" + +[node name="Foreground" type="ColorPickerButton" parent="Controls/Colors"] +margin_left = 84.0 +margin_right = 203.0 +margin_bottom = 20.0 +text = "FrontColor" + +[node name="BackgroundLabel" type="Label" parent="Controls/Colors"] +margin_top = 38.0 +margin_right = 74.0 +margin_bottom = 52.0 +text = "Background" + +[node name="Background" type="ColorPickerButton" parent="Controls/Colors"] +margin_left = 84.0 +margin_top = 35.0 +margin_right = 203.0 +margin_bottom = 55.0 +text = "BackgroundColor" + +[node name="Noise" type="GridContainer" parent="Controls"] +margin_left = 218.0 +margin_right = 497.0 +margin_bottom = 55.0 +custom_constants/vseparation = 7 +custom_constants/hseparation = 5 +columns = 4 + +[node name="OctavesLabel" type="Label" parent="Controls/Noise"] +margin_top = 5.0 +margin_right = 75.0 +margin_bottom = 19.0 +text = "Octaves" + +[node name="Octaves" type="SpinBox" parent="Controls/Noise"] +margin_left = 80.0 +margin_right = 154.0 +margin_bottom = 24.0 +max_value = 9.0 + +[node name="PeriodLabel" type="Label" parent="Controls/Noise"] +margin_left = 159.0 +margin_top = 5.0 +margin_right = 200.0 +margin_bottom = 19.0 +text = "Period" + +[node name="Period" type="SpinBox" parent="Controls/Noise"] +margin_left = 205.0 +margin_right = 279.0 +margin_bottom = 24.0 + +[node name="PersistenceLabel" type="Label" parent="Controls/Noise"] +margin_top = 36.0 +margin_right = 75.0 +margin_bottom = 50.0 +text = "Persistence" + +[node name="Persistence" type="SpinBox" parent="Controls/Noise"] +margin_left = 80.0 +margin_top = 31.0 +margin_right = 154.0 +margin_bottom = 55.0 +step = 0.1 + +[node name="Size" type="GridContainer" parent="Controls"] +margin_left = 512.0 +margin_right = 633.0 +margin_bottom = 55.0 +custom_constants/vseparation = 7 +custom_constants/hseparation = 5 +columns = 2 + +[node name="WidthLabel" type="Label" parent="Controls/Size"] +margin_top = 5.0 +margin_right = 42.0 +margin_bottom = 19.0 +text = "Width" + +[node name="Width" type="SpinBox" parent="Controls/Size"] +margin_left = 47.0 +margin_right = 121.0 +margin_bottom = 24.0 +min_value = 1.0 +max_value = 8192.0 +value = 1.0 + +[node name="HeightLabel" type="Label" parent="Controls/Size"] +margin_top = 36.0 +margin_right = 42.0 +margin_bottom = 50.0 +text = "Heigth" + +[node name="Heigth" type="SpinBox" parent="Controls/Size"] +margin_left = 47.0 +margin_top = 31.0 +margin_right = 121.0 +margin_bottom = 55.0 +min_value = 1.0 +max_value = 8192.0 +value = 1.0 + +[node name="Threshold" type="GridContainer" parent="Controls"] +margin_left = 648.0 +margin_right = 805.0 +margin_bottom = 55.0 +custom_constants/vseparation = 7 +custom_constants/hseparation = 5 +columns = 2 + +[node name="UpperThresholdLabel" type="Label" parent="Controls/Threshold"] +margin_top = 5.0 +margin_right = 78.0 +margin_bottom = 19.0 +text = "Upper Thres" + +[node name="UpperThreadshold" type="SpinBox" parent="Controls/Threshold"] +margin_left = 83.0 +margin_right = 157.0 +margin_bottom = 24.0 +max_value = 1.0 +step = 0.1 + +[node name="LowerThresholdLabel" type="Label" parent="Controls/Threshold"] +margin_top = 36.0 +margin_right = 78.0 +margin_bottom = 50.0 +text = "Lower Thres" + +[node name="LowerThreadshold" type="SpinBox" parent="Controls/Threshold"] +margin_left = 83.0 +margin_top = 31.0 +margin_right = 157.0 +margin_bottom = 55.0 +max_value = 1.0 +step = 0.1 + +[node name="GenerateButton" type="Button" parent="Controls"] +margin_top = 70.0 +margin_right = 203.0 +margin_bottom = 90.0 +grow_vertical = 2 +text = "Generate Texture" +script = SubResource( 1 ) + +[node name="ExportButton" type="Button" parent="Controls"] +margin_left = 218.0 +margin_top = 70.0 +margin_right = 497.0 +margin_bottom = 90.0 +disabled = true +text = "Export Texture" + +[node name="PathDialog" type="FileDialog" parent="."] +margin_left = 48.0 +margin_top = 150.0 +margin_right = 675.0 +margin_bottom = 483.0 +popup_exclusive = true +window_title = "Datei speichern" +resizable = true +access = 2 +filters = PoolStringArray( "*.png ; PNGs" ) +current_dir = "/Projekte/noise-water-proto" +current_file = "noise_water.png" +current_path = "/Projekte/noise-water-proto/noise_water.png" + +[connection signal="texture_ready" from="PerlinWaterGenerator" to="." method="_on_PerlinWaterGenerator_texture_ready"] +[connection signal="draw" from="TextureContainer/Center/Texture" to="." method="_on_Texture_draw"] +[connection signal="pressed" from="Controls/GenerateButton" to="." method="_on_GenerateButton_pressed"] +[connection signal="pressed" from="Controls/ExportButton" to="." method="_on_ExportButton_pressed"] +[connection signal="file_selected" from="PathDialog" to="." method="_on_PathDialog_file_selected"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..9413d9a --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Perlin Water Generator +A godot based tool for generating water textures with perlin noise. + +# License +MIT \ No newline at end of file diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..c98fbb6 Binary files /dev/null and b/icon.png differ diff --git a/icon.png.import b/icon.png.import new file mode 100644 index 0000000..96cbf46 --- /dev/null +++ b/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..69e1c7a --- /dev/null +++ b/project.godot @@ -0,0 +1,36 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=4 + +_global_script_classes=[ { +"base": "Node2D", +"class": "PerlinWaterGenerator", +"language": "GDScript", +"path": "res://script/PerlinWaterGenerator.gd" +} ] +_global_script_class_icons={ +"PerlinWaterGenerator": "" +} + +[application] + +config/name="PerlinWaterGenerator" +run/main_scene="res://Node2D.tscn" +config/icon="res://icon.png" + +[display] + +window/size/width=900 +window/size/resizable=false +window/dpi/allow_hidpi=true +window/vsync/use_vsync=false + +[physics] + +common/enable_pause_aware_picking=true diff --git a/script/Demo.gd b/script/Demo.gd new file mode 100644 index 0000000..006887b --- /dev/null +++ b/script/Demo.gd @@ -0,0 +1,73 @@ +extends Node2D + +var thread = Thread.new() +var export_path + +func _ready(): + + # default colors + $Controls/Colors/Foreground.color = Color("e1e1e1") + $Controls/Colors/Background.color = Color("2a91dc") + + # default noise values + $Controls/Noise/Octaves.value = 1 + $Controls/Noise/Period.value = 96 + $Controls/Noise/Persistence.value = .8 + + # default size + $Controls/Size/Width.value = 256 + $Controls/Size/Heigth.value = 256 + + # default threshold + $Controls/Threshold/UpperThreadshold.value = .4 + $Controls/Threshold/LowerThreadshold.value = .6 + +func _on_GenerateButton_pressed(): + + # colors + var front_color = $Controls/Colors/Foreground.color + var back_color = $Controls/Colors/Background.color + + # noise parameters + var octaves = $Controls/Noise/Octaves.value + var period = $Controls/Noise/Period.value + var persistence = $Controls/Noise/Persistence.value + + # size parameter + var width = $Controls/Size/Width.value + var heigth = $Controls/Size/Heigth.value + + # thresholds + var lower_threshold = $Controls/Threshold/LowerThreadshold.value + var upper_threshold = $Controls/Threshold/UpperThreadshold.value + + # open progress dialog + $Controls/GenerateButton.disabled = true + + thread.start($PerlinWaterGenerator, "generate_texture", { + "upper_threshold": upper_threshold, + "lower_threshold": lower_threshold, + "octaves": octaves, + "period": period, + "persistence": persistence, + "foreground": front_color, + "background": back_color, + "width": width, + "heigth": heigth + }) + + +func _on_ExportButton_pressed(): + $PathDialog.popup_centered() + +func _on_PathDialog_file_selected(path: String): + $PerlinWaterGenerator.export_texture(path) + +func _on_Texture_draw(): + if (not thread.is_alive() and thread.is_active()): + thread.wait_to_finish() + $Controls/GenerateButton.disabled = false + +func _on_PerlinWaterGenerator_texture_ready(texture): + $TextureContainer/Center/Texture.texture = texture + $Controls/ExportButton.disabled = false diff --git a/script/PerlinWaterGenerator.gd b/script/PerlinWaterGenerator.gd new file mode 100644 index 0000000..59278bd --- /dev/null +++ b/script/PerlinWaterGenerator.gd @@ -0,0 +1,38 @@ +extends Node2D + +class_name PerlinWaterGenerator + +signal texture_ready(texture) + +var noise_image: Image = Image.new() +var noise: OpenSimplexNoise = OpenSimplexNoise.new() + +func generate_texture(options: Dictionary) -> Texture: + noise.seed = randi() + noise.octaves = options.get("octaves", 1) + noise.period = options.get("period", 96) + noise.persistence = options.get("persistence", .8) + + noise_image = Image.new() + noise_image.create(options.get("width", 64), options.get("heigth", 64), false, Image.FORMAT_RGBA8) + noise_image.lock() + + for w in noise_image.get_width(): + for h in noise_image.get_height(): + var n = abs(noise.get_noise_2d(w, h)) + if n >= options.get("upper_threshold", .4) and n <= options.get("lower_threshold", .6): + noise_image.set_pixel(w, h, options.get("foreground")) + else: + noise_image.set_pixel(w, h, options.get("background")) + + noise_image.unlock() + + var texture = ImageTexture.new() + texture.create_from_image(noise_image) + + emit_signal("texture_ready", texture) + return texture + +func export_texture(export_path: String): + if noise_image.save_png(export_path): + print("Error I guess?!")