1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-18 17:19:50 +00:00

Compare commits

...

36 commits

Author SHA1 Message Date
Variable d4da5a6a02
Merge 36bd0b9fe5 into d3f287347a 2025-01-05 14:25:13 +05:00
Variable d3f287347a
add api 5 to the list of legacy versions (#1162) 2025-01-04 23:12:03 +02:00
Emmanouil Papadeas 6afdb372b3 [skip ci] Hide the Brightness/Contrast dialog 2024-12-31 19:34:17 +02:00
Emmanouil Papadeas e98d481a19 [skip ci] Raise the Extensions API version to 6 2024-12-29 22:24:15 +02:00
Emmanouil Papadeas 6c3fc95099 [skip ci] Update CHANGELOG.md 2024-12-28 22:54:04 +02:00
Emmanouil Papadeas c60c62f476 Fix tileset being completely cleared when resizing a project
Now only remove the tiles that are used so they can be remade as resized tiles. Unused tiles remain in the tileset as is.
2024-12-27 03:30:56 +02:00
Emmanouil Papadeas 616bd91c49 Mirror image image effect now works with indexed mode 2024-12-22 02:40:05 +02:00
Emmanouil Papadeas a698668930 Fix #1157 for the polygon select and the curve tool as well 2024-12-21 03:52:33 +02:00
Emmanouil Papadeas 59254b943f Attempt to fix left tool preview not being shown when a right tool with a preview is selected
Maybe fixes #1157
2024-12-21 03:44:54 +02:00
Emmanouil Papadeas 033238b787 Fix the gradient of the noise generator's color ramp not updating properly 2024-12-21 00:32:56 +02:00
Emmanouil Papadeas d4c3ae3dc6 Change PXO_frame and PXO_layer to PXO_frame_index and PXO_layer_index 2024-12-21 00:31:51 +02:00
Emmanouil Papadeas b4fbb1df75 Set input as handled when dragging on a ValueSlider 2024-12-20 00:20:37 +02:00
Emmanouil Papadeas 360aa250c4 Hide the horizontal alignment option from the text tool
It's not doing anything at the moment and I am unsure why. We could expose it again if we figure it out.
2024-12-18 23:21:28 +02:00
Emmanouil Papadeas 80e93629d1 Add PXO_frame and PXO_layer as special loaded shader uniforms 2024-12-17 19:36:01 +02:00
Emmanouil Papadeas 5a17117d59 Improve support for visual shader loading
ShaderLoader now gets the VisualShaderNodeTextures of the VisualShader into account, allowing for visual shaders that are being loaded to have default textures.
2024-12-17 18:11:36 +02:00
Emmanouil Papadeas 3edb37168c Fix issues with the noise generator node
Its nodes now get updated when changing the noise texture, and it waits for `noise_texture.changed` to emit before emitting the `value_changed` signal. See https://docs.godotengine.org/en/stable/classes/class_noisetexture2d.html for the explanation.
2024-12-17 13:38:18 +02:00
Emmanouil Papadeas 0f53fc32fe Start working on a noise generator node
Used for shaders that need noise textures.

Still WIP. needs the nodes to set their appropriate values when setting a noise texture. Which means I'll probably have to re-write the whole thing, yay :D
2024-12-17 03:21:23 +02:00
Emmanouil Papadeas 618d5f4916 Fix bug with ValueSliderV3 where the grid_columns variable was setting the ratio's visibility instead 2024-12-17 02:31:21 +02:00
Emmanouil Papadeas a8392fb14f
[skip ci] Update bug_report.md 2024-12-17 01:43:43 +02:00
BrotherShort 91caefee4a
Update DrawingAlgos.gd (#1151)
Fixed ellipse draw algos bug.
2024-12-17 01:07:11 +02:00
Variable 7de7f3fab8
renamed the selection tile mode to wrap strokes, as it is a more accurate description. (#1150) 2024-12-17 01:06:58 +02:00
Emmanouil Papadeas 2d81bd495a Move value and basis slider files into a folder 2024-12-17 01:04:56 +02:00
Emmanouil Papadeas 11ae7c007b Implement support for elapsed time in loaded shaders for layer effects
Simply add `uniform float PXO_time;` in the shader's uniforms, and replace all instances of `TIME` with `PXO_time`. This will make the shader animate per frame.
2024-12-17 00:53:58 +02:00
Emmanouil Papadeas fede8c3e49 Update Translations.pot 2024-12-16 19:11:44 +02:00
Emmanouil Papadeas 1710294c9f Update CHANGELOG.md 2024-12-16 19:10:42 +02:00
Emmanouil Papadeas 8ab4af1047 Fix curve in the curve edit node not redrawing immediately after adding a new point 2024-12-16 19:10:03 +02:00
Emmanouil Papadeas 8bd31112be [skip ci] Update CHANGELOG.md 2024-12-16 01:36:11 +02:00
Emmanouil Papadeas d980eec683 [skip ci] Update CHANGELOG.md 2024-12-16 01:32:46 +02:00
Emmanouil Papadeas 39c85c3079 Implement the ability to load custom shaders and image and layer effects
Finally expose the feature of importing custom shaders as image effects, and implement custom shader loading for layer effects as well. To load a shader, drag and drop a .gdshader file into Pixelorama and it will get copied into `user://shaders`. Then, in the Effects menu, a new "Loaded" submenu will appear, and the new shaders will also be available in the layer effects dialog. Since they are stored on a persistent location, the shaders will also be available on the next times Pixelorama will launch as well.
2024-12-16 01:18:56 +02:00
Emmanouil Papadeas 8ceeba76c0 Update Translations.pot 2024-12-15 21:14:11 +02:00
Emmanouil Papadeas 93eab6929b For PixelCel's set_content not working when passing an Image instead of ImageExtended 2024-12-15 21:05:10 +02:00
Emmanouil Papadeas 1d9b9fda1e Add color curves layer effect 2024-12-15 21:04:32 +02:00
Emmanouil Papadeas 482dbecd13 Add presets to the curve edit widget 2024-12-15 20:46:07 +02:00
Emmanouil Papadeas cf8dacf0f5 Fix curve edit tangent points
They are working properly now
2024-12-15 18:37:21 +02:00
Emmanouil Papadeas 048058bd35 Implement a color curves image effect
Massive thanks to Material Maker for the custom widget code. The color curves effect is still WIP, I need to make the tangent points visible (not yet sure why they aren't now), add some curve presets, and implement it as a layer effect as well.
2024-12-15 18:10:55 +02:00
Emmanouil Papadeas 605bff7324 Show the index of the palette swatches when color indices are visible on the canvas 2024-12-15 00:13:59 +02:00
91 changed files with 1752 additions and 247 deletions

View file

@ -15,6 +15,10 @@ https://github.com/Orama-Interactive/Pixelorama/issues?q=is%3Aissue
<!-- Specify commit hash if using a non-official build. -->
**Where did you download Pixelorama from?**
<!-- Specify where you downloaded Pixelorama from. GitHub Releases, itch.io, Steam, Flatpak, self-built, somewhere else? -->
**OS/device including version:**
<!-- Specify GPU model and drivers if graphics-related. -->

View file

@ -6,22 +6,32 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [v1.1] - Unreleased
This update has been brought to you by the contributions of:
Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind))
Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind)), Spencer Beckwith ([@spencerjbeckwith](https://github.com/spencerjbeckwith))
Built using Godot 4.3
### Added
- Tilemap layers have arrived! Tilemap layers allow artists to create tiles, and easily preview and dynamically modify them within Pixelorama. [#1146](https://github.com/Orama-Interactive/Pixelorama/pull/1146)
- Indexed mode has finally been implemented! [#1136](https://github.com/Orama-Interactive/Pixelorama/pull/1136)
- Audio layers have been added, allowing artists to easily synchronize their animations with audio. [#1149](https://github.com/Orama-Interactive/Pixelorama/pull/1149)
- Added a new text tool. Destructive only for now, meaning that once the text is confirmed, it cannot be changed later. [#1134](https://github.com/Orama-Interactive/Pixelorama/pull/1134)
- A color curves image and layer effect has been added.
- It is now possible to load custom Godot shaders as image and layer effects.
- Implemented support for multiple grids. [#1122](https://github.com/Orama-Interactive/Pixelorama/pull/1122)
### Changed
- System font names are now sorted by alphabetical order.
- "Tile Mode" under the Selection menu has been renamed to "Wrap Strokes". This does not affect the "Tile Mode" option in the View menu. [#1150](https://github.com/Orama-Interactive/Pixelorama/pull/1150)
### Fixed
- Fixed crash when Pixelorama starts without a palette.
- Undo/redo now works again when the cursor is hovering over the timeline.
- Palette swatches now get deleted when the user removes all palettes
- The first frame is no longer exported twice when using ping-pong loop.
- Fixed pencil/eraser/shading previews turning white for a brief moment when changing image brushes, and when switching between tools.
- Fixed the preview on the left tool not being visible, if the right tool had a preview. [#1157](https://github.com/Orama-Interactive/Pixelorama/issues/1157)
- Dialogs that are children of other dialogs now always appear on top, to avoid issues where they could hide behind their parents and causing confusion that made Pixelorama seem unresponsive.
- Palette swatches now get deleted when the user removes all palettes.
- The CLI's output option now works with filepaths instead of just filenames. [#1145](https://github.com/Orama-Interactive/Pixelorama/pull/1145)
- Fixed the Palettize effect and palette exporting to images storing slightly wrong color values. [77f6bcf](https://github.com/Orama-Interactive/Pixelorama/commit/77f6bcf07bd80bc042e478bb883d05900cebe436)
- Fixed some issues with the Palettize effect where the output would be different if the palette size changed and empty swatches were added, even if the colors themselves stayed the same. Initially fixed by [bd7d3b1](https://github.com/Orama-Interactive/Pixelorama/commit/bd7d3b19cc98804e9b99754153c4d553d2048ee3), but [1dcb696](https://github.com/Orama-Interactive/Pixelorama/commit/1dcb696c35121f8208bde699f87bb75deff99d13) is the proper fix.
- Fixed recorder label not updating when project is changed. [#1139](https://github.com/Orama-Interactive/Pixelorama/pull/1139)
@ -50,7 +60,7 @@ Built using Godot 4.3
- Fixed layer effect slider values being rounded to the nearest integer.
- Fixed memory leak where the project remained referenced by a drawing tool, even when its tab was closed.
- Fixed memory leak where the first project remained forever references in memory by the Recorder panel.
- Slightly optimize circle brushes by only calling the ellipse algorithms once while drawing
- Slightly optimize circle brushes by only calling the ellipse algorithms once while drawing.
### Removed
- The Recorder panel has been removed from the Web version. It wasn't functional anyway in a way that was useful, and it's unsure if we can find a way to make it work.

View file

@ -211,6 +211,10 @@ msgstr ""
msgid "Initial angle:"
msgstr ""
#. Found under the Select menu, It's a checkbox that, if enabled, wraps around brush strokes if some part of them goes out of selection bounds.
msgid "Wrap Strokes"
msgstr ""
msgid "Clear"
msgstr ""
@ -1157,6 +1161,27 @@ msgstr ""
msgid "Tint effect factor:"
msgstr ""
#. An image effect that adjusts the colors of the image by using curves.
msgid "Color Curves"
msgstr ""
#. Refers to a color channel, such as the red, green, blue or alpha channels.
msgid "Channel:"
msgstr ""
msgid "Red"
msgstr ""
msgid "Green"
msgstr ""
#. Refers to the value (as in HSV) of the colors of an image.
msgid "Value"
msgstr ""
msgid "Presets"
msgstr ""
msgid "Apply"
msgstr ""
@ -1773,7 +1798,7 @@ msgstr ""
msgid "If enabled, the application window can become transparent. This affects performance, so keep it off if you don't need it."
msgstr ""
#. An option found in the preferences, under the Performance section.
#. An option found in the preferences, under the Performance section. A dummy driver is basically a driver that doesn't do anything. When this option is enabled, audio does not play, but it can help save some performance.
msgid "Use dummy audio driver"
msgstr ""

View file

@ -24,7 +24,7 @@ boot_splash/use_filter=false
config/icon="res://assets/graphics/icons/icon.png"
config/macos_native_icon="res://assets/graphics/icons/icon.icns"
config/windows_native_icon="res://assets/graphics/icons/icon.ico"
config/ExtensionsAPI_Version=5
config/ExtensionsAPI_Version=6
config/Pxo_Version=4
[autoload]
@ -685,6 +685,10 @@ adjust_brightness_contrast={
"deadzone": 0.5,
"events": []
}
color_curves={
"deadzone": 0.5,
"events": []
}
gradient={
"deadzone": 0.5,
"events": []

View file

@ -127,7 +127,7 @@ func get_ellipse_points(pos: Vector2i, size: Vector2i) -> Array[Vector2i]:
var y0 := pos.y
var y1 := pos.y + (size.y - 1)
var a := absi(x1 - x0)
var b := absi(y1 - x0)
var b := absi(y1 - y0)
var b1 := b & 1
var dx := 4 * (1 - a) * b * b
var dy := 4 * (b1 + 1) * a * a

View file

@ -168,11 +168,11 @@ class GeneralAPI:
## Returns a new ValueSliderV2. Useful for editing 2D vectors.
func create_value_slider_v2() -> ValueSliderV2:
return preload("res://src/UI/Nodes/ValueSliderV2.tscn").instantiate()
return preload("res://src/UI/Nodes/Sliders/ValueSliderV2.tscn").instantiate()
## Returns a new ValueSliderV3. Useful for editing 3D vectors.
func create_value_slider_v3() -> ValueSliderV3:
return preload("res://src/UI/Nodes/ValueSliderV3.tscn").instantiate()
return preload("res://src/UI/Nodes/Sliders/ValueSliderV3.tscn").instantiate()
## Gives ability to add/remove items from menus in the top bar.

View file

@ -64,16 +64,17 @@ enum EffectsMenu {
DESATURATION,
HSV,
BRIGHTNESS_SATURATION,
COLOR_CURVES,
PALETTIZE,
PIXELIZE,
POSTERIZE,
GAUSSIAN_BLUR,
GRADIENT,
GRADIENT_MAP,
SHADER
LOADED_EFFECTS
}
## Enumeration of items present in the Select Menu.
enum SelectMenu { SELECT_ALL, CLEAR_SELECTION, INVERT, TILE_MODE, MODIFY }
enum SelectMenu { SELECT_ALL, CLEAR_SELECTION, INVERT, WRAP_STROKES, MODIFY }
## Enumeration of items present in the Help Menu.
enum HelpMenu {
VIEW_SPLASH_SCREEN,
@ -809,6 +810,7 @@ func _initialize_keychain() -> void:
&"drop_shadow": Keychain.InputAction.new("", "Effects menu", true),
&"adjust_hsv": Keychain.InputAction.new("", "Effects menu", true),
&"adjust_brightness_contrast": Keychain.InputAction.new("", "Effects menu", true),
&"color_curves": Keychain.InputAction.new("", "Effects menu", true),
&"gaussian_blur": Keychain.InputAction.new("", "Effects menu", true),
&"gradient": Keychain.InputAction.new("", "Effects menu", true),
&"gradient_map": Keychain.InputAction.new("", "Effects menu", true),

View file

@ -3,6 +3,9 @@ extends Node
signal project_saved
signal reference_image_imported
signal shader_copied(file_path: String)
const SHADERS_DIRECTORY := "user://shaders"
var preview_dialog_tscn := preload("res://src/UI/Dialogs/ImportPreviewDialog.tscn")
var preview_dialogs := [] ## Array of preview dialogs
@ -29,7 +32,11 @@ func handle_loading_file(file: String) -> void:
open_pxo_file(file)
elif file_ext == "tres": # Godot resource file
return
var resource := load(file)
if resource is VisualShader:
var new_path := SHADERS_DIRECTORY.path_join(file.get_file())
DirAccess.copy_absolute(file, new_path)
shader_copied.emit(new_path)
elif file_ext == "tscn": # Godot scene file
return
@ -39,12 +46,13 @@ func handle_loading_file(file: String) -> void:
elif file_ext in ["pck", "zip"]: # Godot resource pack file
Global.control.get_node("Extensions").install_extension(file)
elif file_ext == "shader" or file_ext == "gdshader": # Godot shader file
elif file_ext == "gdshader": # Godot shader file
var shader := load(file)
if not shader is Shader:
return
var file_name: String = file.get_file().get_basename()
Global.control.find_child("ShaderEffect").change_shader(shader, file_name)
var new_path := SHADERS_DIRECTORY.path_join(file.get_file())
DirAccess.copy_absolute(file, new_path)
shader_copied.emit(new_path)
elif file_ext == "mp3": # Audio file
open_audio_file(file)
@ -279,7 +287,10 @@ func open_pxo_file(path: String, is_backup := false, replace_empty := true) -> v
var image := Image.create_from_data(
tile_size.x, tile_size.y, false, new_project.get_image_format(), image_data
)
tileset.add_tile(image, null)
tileset.add_tile(image, null, 0)
for cel in new_project.get_all_pixel_cels():
if cel is CelTileMap:
cel.find_times_used_of_tiles()
zip_reader.close()
new_project.export_directory_path = path.get_base_dir()
@ -870,7 +881,7 @@ func open_image_as_tileset(
Rect2i(frame_width * xx, frame_height * yy, frame_width, frame_height)
)
@warning_ignore("int_as_enum_without_cast")
tileset.add_tile(cropped_image, null)
tileset.add_tile(cropped_image, null, 0)
project.tilesets.append(tileset)
@ -893,7 +904,7 @@ func open_image_as_tileset_smart(
)
cropped_image.blit_rect(image, rect, offset)
@warning_ignore("int_as_enum_without_cast")
tileset.add_tile(cropped_image, null)
tileset.add_tile(cropped_image, null, 0)
project.tilesets.append(tileset)

View file

@ -24,6 +24,13 @@ func get_final_opacity(layer: BaseLayer) -> float:
return layer.opacity * opacity
func get_frame(project: Project) -> Frame:
for frame in project.frames:
if frame.cels.has(self):
return frame
return null
# Methods to Override:

View file

@ -330,7 +330,7 @@ func serialize_undo_data_source_image(
if source_image.get_size() != image.get_size():
undo_data[self]["resize"] = true
_resize_cells(source_image.get_size())
tileset.clear_tileset(self)
tileset.handle_project_resize(self)
var tile_editing_mode := TileSetPanel.tile_editing_mode
if tile_editing_mode == TileSetPanel.TileEditingMode.MANUAL:
tile_editing_mode = TileSetPanel.TileEditingMode.AUTO
@ -352,6 +352,13 @@ func deserialize_undo_data(dict: Dictionary, undo_redo: UndoRedo, undo: bool) ->
undo_redo.add_do_method(tileset.deserialize_undo_data.bind(dict.tileset, self))
## Called when loading a new project. Loops through all [member cells]
## and finds the amount of times each tile from the [member tileset] is being used.
func find_times_used_of_tiles() -> void:
for cell in cells:
tileset.tiles[cell.index].times_used += 1
## Gets called every time a change is being applied to the [param image],
## such as when finishing drawing with a draw tool, or when applying an image effect.
## This method responsible for updating the indices of the [member cells], as well as

View file

@ -25,7 +25,13 @@ func get_content() -> ImageExtended:
func set_content(content, texture: ImageTexture = null) -> void:
image = content
var proper_content: ImageExtended
if content is not ImageExtended:
proper_content = ImageExtended.new()
proper_content.copy_from_custom(content, image.is_indexed)
else:
proper_content = content
image = proper_content
if is_instance_valid(texture) and is_instance_valid(texture.get_image()):
image_texture = texture
if image_texture.get_image().get_size() != image.get_size():

View file

@ -144,7 +144,9 @@ func set_nodes() -> void:
selection_checkbox = $VBoxContainer/OptionsContainer/SelectionCheckBox
affect_option_button = $VBoxContainer/OptionsContainer/AffectOptionButton
animate_panel = $"%AnimatePanel"
if is_instance_valid(animate_panel):
animate_panel.image_effect_node = self
if is_instance_valid(live_checkbox):
live_checkbox.button_pressed = live_preview

View file

@ -232,10 +232,14 @@ func display_effects(cel: BaseCel, image_override: Image = null) -> Image:
return image
var image_size := image.get_size()
for effect in effects:
if not effect.enabled:
if not effect.enabled or not is_instance_valid(effect.shader):
continue
var params := effect.params
params["PXO_time"] = cel.get_frame(project).position_in_seconds(project)
params["PXO_frame_index"] = project.frames.find(cel.get_frame(project))
params["PXO_layer_index"] = index
var shader_image_effect := ShaderImageEffect.new()
shader_image_effect.generate_image(image, effect.shader, effect.params, image_size)
shader_image_effect.generate_image(image, effect.shader, params, image_size)
# Inherit effects from the parents, if their blend mode is set to pass through
for ancestor in get_ancestors():
if ancestor.blend_mode != BlendModes.PASS_THROUGH:

View file

@ -1,9 +1,10 @@
class_name ShaderLoader
extends RefCounted
const VALUE_SLIDER_V2_TSCN := preload("res://src/UI/Nodes/ValueSliderV2.tscn")
const BASIS_SLIDERS_TSCN := preload("res://src/UI/Nodes/BasisSliders.tscn")
const VALUE_SLIDER_V2_TSCN := preload("res://src/UI/Nodes/Sliders/ValueSliderV2.tscn")
const BASIS_SLIDERS_TSCN := preload("res://src/UI/Nodes/Sliders/BasisSliders.tscn")
const GRADIENT_EDIT_TSCN := preload("res://src/UI/Nodes/GradientEdit.tscn")
const NOISE_GENERATOR := preload("res://src/UI/Nodes/NoiseGeneratorDialog.tscn")
static func create_ui_for_shader_uniforms(
@ -62,6 +63,8 @@ static func create_ui_for_shader_uniforms(
var u_init := u_left_side[0].split(" ")
var u_type := u_init[1]
var u_name := u_init[2]
if u_name in ["PXO_time", "PXO_frame_index", "PXO_layer_index"]:
continue
# Find custom data of the uniform, if any exists
# Right now it only checks if a uniform should have another type of node
# Such as integers having OptionButtons
@ -238,47 +241,34 @@ static func create_ui_for_shader_uniforms(
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var hbox := HBoxContainer.new()
hbox.add_child(label)
if u_name.begins_with("gradient_"):
var gradient_edit := GRADIENT_EDIT_TSCN.instantiate() as GradientEditNode
gradient_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
if params.has(u_name) and params[u_name] is GradientTexture2D:
gradient_edit.set_gradient_texture(params[u_name])
else:
params[u_name] = gradient_edit.texture
# This needs to be call_deferred because GradientTexture2D gets updated next frame.
# Without this, the texture is purple.
value_changed.call_deferred(gradient_edit.texture, u_name)
gradient_edit.updated.connect(
func(_gradient, _cc): value_changed.call(gradient_edit.texture, u_name)
if shader is VisualShader and u_name.begins_with("tex_frg_"):
var node_id := int(u_name.replace("tex_frg_", ""))
var shader_node := (shader as VisualShader).get_node(
VisualShader.TYPE_FRAGMENT, node_id
)
hbox.add_child(gradient_edit)
else: ## Simple texture
var file_dialog := FileDialog.new()
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
file_dialog.access = FileDialog.ACCESS_FILESYSTEM
file_dialog.size = Vector2(384, 281)
file_dialog.file_selected.connect(file_selected.bind(u_name))
file_dialog.use_native_dialog = Global.use_native_file_dialogs
var button := Button.new()
button.text = "Load texture"
button.pressed.connect(file_dialog.popup_centered)
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
var mod_button := Button.new()
mod_button.text = "Modify"
mod_button.pressed.connect(
func():
_modify_texture_resource(
_get_loaded_texture(params, u_name),
u_name,
_shader_update_texture.bind(value_changed, u_name)
if shader_node is VisualShaderNodeTexture:
var texture := (shader_node as VisualShaderNodeTexture).texture
params[u_name] = texture
if texture is GradientTexture1D or texture is GradientTexture2D:
_create_gradient_texture_ui(params, u_name, hbox, value_changed)
elif texture is CurveTexture:
_create_curve_texture_ui(params, u_name, hbox, value_changed)
elif texture is NoiseTexture2D:
_create_noise_texture_ui(params, u_name, hbox, value_changed, parent_node)
else: # Simple texture
_create_simple_texture_ui(
params, u_name, hbox, value_changed, parent_node, file_selected
)
elif u_name.begins_with("gradient_"):
_create_gradient_texture_ui(params, u_name, hbox, value_changed)
elif u_name.begins_with("curve_"):
_create_curve_texture_ui(params, u_name, hbox, value_changed)
elif u_name.begins_with("noise_"):
_create_noise_texture_ui(params, u_name, hbox, value_changed, parent_node)
else: # Simple texture
_create_simple_texture_ui(
params, u_name, hbox, value_changed, parent_node, file_selected
)
mod_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
mod_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
hbox.add_child(button)
hbox.add_child(mod_button)
parent_node.add_child(file_dialog)
parent_node.add_child(hbox)
elif u_type == "bool":
@ -374,6 +364,106 @@ static func _mat3str_to_basis(mat3: String) -> Basis:
return basis
static func _create_simple_texture_ui(
params: Dictionary,
u_name: String,
hbox: BoxContainer,
value_changed: Callable,
parent_node: Control,
file_selected: Callable
) -> void:
var file_dialog := FileDialog.new()
file_dialog.always_on_top = true
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
file_dialog.access = FileDialog.ACCESS_FILESYSTEM
file_dialog.size = Vector2(384, 281)
file_dialog.file_selected.connect(file_selected.bind(u_name))
file_dialog.use_native_dialog = Global.use_native_file_dialogs
var button := Button.new()
button.text = "Load texture"
button.pressed.connect(file_dialog.popup_centered)
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
var mod_button := Button.new()
mod_button.text = "Modify"
mod_button.pressed.connect(
func():
_modify_texture_resource(
_get_loaded_texture(params, u_name),
u_name,
_shader_update_texture.bind(value_changed, u_name)
)
)
mod_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
mod_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
hbox.add_child(button)
hbox.add_child(mod_button)
parent_node.add_child(file_dialog)
static func _create_gradient_texture_ui(
params: Dictionary, u_name: String, hbox: BoxContainer, value_changed: Callable
) -> void:
var gradient_edit := GRADIENT_EDIT_TSCN.instantiate() as GradientEditNode
gradient_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
if params.has(u_name):
var texture = params[u_name]
if texture is GradientTexture2D:
gradient_edit.set_gradient_texture(texture)
elif texture is GradientTexture1D:
gradient_edit.set_gradient_texture_1d(texture)
else:
params[u_name] = gradient_edit.texture
# This needs to be call_deferred because GradientTexture2D gets updated next frame.
# Without this, the texture is purple.
value_changed.call_deferred(gradient_edit.texture, u_name)
gradient_edit.updated.connect(
func(_gradient, _cc): value_changed.call(gradient_edit.texture, u_name)
)
hbox.add_child(gradient_edit)
static func _create_curve_texture_ui(
params: Dictionary, u_name: String, hbox: BoxContainer, value_changed: Callable
) -> void:
var curve_edit := CurveEdit.new()
curve_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
if params.has(u_name) and params[u_name] is CurveTexture:
curve_edit.curve = params[u_name].curve
else:
curve_edit.set_default_curve()
params[u_name] = CurveEdit.to_texture(curve_edit.curve)
curve_edit.value_changed.connect(
func(curve: Curve): value_changed.call(CurveEdit.to_texture(curve), u_name)
)
hbox.add_child(curve_edit)
static func _create_noise_texture_ui(
params: Dictionary,
u_name: String,
hbox: BoxContainer,
value_changed: Callable,
parent_node: Control
) -> void:
var noise_generator_dialog := NOISE_GENERATOR.instantiate() as AcceptDialog
var noise_generator := noise_generator_dialog.get_child(0) as NoiseGenerator
if params.has(u_name) and params[u_name] is NoiseTexture2D:
noise_generator.noise_texture = params[u_name]
else:
params[u_name] = noise_generator.noise_texture
noise_generator.value_changed.connect(
func(noise_texture: NoiseTexture2D): value_changed.call(noise_texture, u_name)
)
parent_node.add_child(noise_generator_dialog)
var button := Button.new()
button.text = "Generate noise"
button.pressed.connect(noise_generator_dialog.popup_centered)
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
hbox.add_child(button)
static func _shader_change_palette(value_changed: Callable, parameter_name: String) -> void:
var palette := Palettes.current_palette
_shader_update_palette_texture(palette, value_changed, parameter_name)

View file

@ -16,9 +16,9 @@ var name := ""
var tile_size: Vector2i
## The collection of tiles in the form of an [Array] of type [TileSetCustom.Tile].
var tiles: Array[Tile] = []
## If [code]true[/code], the code in [method clear_tileset] does not execute.
## If [code]true[/code], the code in [method handle_project_resize] does not execute.
## This variable is used to prevent multiple cels from clearing the tileset at the same time.
## In [method clear_tileset], the variable is set to [code]true[/code], and then
## In [method handle_project_resize], the variable is set to [code]true[/code], and then
## immediately set to [code]false[/code] in the next frame using [method Object.set_deferred].
var _tileset_has_been_cleared := false
@ -50,8 +50,9 @@ func _init(_tile_size: Vector2i, _name := "", add_empty_tile := true) -> void:
## Adds a new [param image] as a tile to the tileset.
## The [param cel] parameter references the [CelTileMap] that this change is coming from,
## and the [param edit_mode] parameter contains the tile editing mode at the time of this change.
func add_tile(image: Image, cel: CelTileMap) -> void:
func add_tile(image: Image, cel: CelTileMap, times_used := 1) -> void:
var tile := Tile.new(image)
tile.times_used = times_used
tiles.append(tile)
updated.emit(cel, -1)
@ -115,14 +116,15 @@ func remove_unused_tiles(cel: CelTileMap) -> bool:
return tile_removed
## Clears the tileset. Usually called when the project gets resized,
## Clears the used tiles of tileset. Called when the project gets resized,
## and tilemap cels are updating their size and clearing the tileset to re-create it.
func clear_tileset(cel: CelTileMap) -> void:
func handle_project_resize(cel: CelTileMap) -> void:
if _tileset_has_been_cleared:
return
tiles.clear()
var empty_image := Image.create_empty(tile_size.x, tile_size.y, false, Image.FORMAT_RGBA8)
tiles.append(Tile.new(empty_image))
for i in range(tiles.size() - 1, 0, -1):
var tile := tiles[i]
if tile.times_used > 0:
tiles.erase(tile)
updated.emit(cel, -1)
_tileset_has_been_cleared = true
set_deferred("_tileset_has_been_cleared", false)

View file

@ -13,6 +13,8 @@ const BIN_ACTION := "trash"
var extensions := {} ## Extension name: Extension class
var extension_selected := -1
var damaged_extension: String
## Extensions built using the versions in this array are considered compatible with the current Api
var legacy_api_versions = [5, 4]
class Extension:
@ -157,14 +159,17 @@ func _load_extension(extension_file_or_folder_name: StringName, internal := fals
if extension_json.has("supported_api_versions"):
var supported_api_versions = extension_json["supported_api_versions"]
var current_api_version = ExtensionsApi.get_api_version()
if typeof(supported_api_versions) == TYPE_ARRAY:
supported_api_versions = PackedInt32Array(supported_api_versions)
# Extensions that support API version 4 are backwards compatible with version 5.
# Version 5 only adds new methods and does not break compatibility.
# TODO: Find a better way to determine which API versions
# have backwards compatibility with each other.
if 4 in supported_api_versions and not 5 in supported_api_versions:
supported_api_versions.append(5)
if not current_api_version in supported_api_versions:
for legacy_version: int in legacy_api_versions:
if legacy_version in supported_api_versions:
supported_api_versions.append(current_api_version)
if not ExtensionsApi.get_api_version() in supported_api_versions:
var err_text := (
"The extension %s will not work on this version of Pixelorama \n"
@ -173,7 +178,7 @@ func _load_extension(extension_file_or_folder_name: StringName, internal := fals
var required_text := str(
"Extension works on API versions: %s" % str(supported_api_versions),
"\n",
"But Pixelorama's API version is: %s" % ExtensionsApi.get_api_version()
"But Pixelorama's API version is: %s" % current_api_version
)
Global.popup_error(str(err_text, required_text))
print("Incompatible API")

View file

@ -64,6 +64,7 @@ func draw_palette() -> void:
var grid_index := i + grid_size.x * j
var index := convert_grid_index_to_palette_index(grid_index)
var swatch := swatches[grid_index]
swatch.color_index = index
swatch.show_left_highlight = Palettes.left_selected_color == index
swatch.show_right_highlight = Palettes.right_selected_color == index
var color = current_palette.get_color(index)

View file

@ -8,6 +8,7 @@ signal dropped(source_index: int, new_index: int)
const DEFAULT_COLOR := Color(0.0, 0.0, 0.0, 0.0)
var index := -1
var color_index := -1
var show_left_highlight := false
var show_right_highlight := false
var empty := true:
@ -48,6 +49,23 @@ func _draw() -> void:
draw_rect(
Rect2(margin - Vector2.ONE, size - margin * 2 + Vector2(2, 2)), Color.WHITE, false, 1
)
if Global.show_pixel_indices:
var font := Themes.get_font()
var str_pos := Vector2(size.x / 2, size.y - 2)
var text_color := Global.control.theme.get_color(&"font_color", &"Label")
draw_string_outline(
font,
str_pos,
str(color_index),
HORIZONTAL_ALIGNMENT_RIGHT,
-1,
size.x / 2,
1,
text_color.inverted()
)
draw_string(
font, str_pos, str(color_index), HORIZONTAL_ALIGNMENT_RIGHT, -1, size.x / 2, text_color
)
## Enables drawing of highlights which indicate selected swatches

View file

@ -4,10 +4,10 @@
[ext_resource type="PackedScene" uid="uid://bq7ibhm0txl5p" path="res://addons/keychain/ShortcutEdit.tscn" id="3"]
[ext_resource type="Script" path="res://src/Preferences/ThemesPreferences.gd" id="3_nvl8k"]
[ext_resource type="Script" path="res://src/Preferences/GridPreferences.gd" id="4_76iff"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="5_rlmsh"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="7"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="5_rlmsh"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="7"]
[ext_resource type="Script" path="res://src/Preferences/ExtensionsPreferences.gd" id="7_8ume5"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="8"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="8"]
[ext_resource type="PackedScene" uid="uid://chy5d42l72crk" path="res://src/UI/ExtensionExplorer/Store.tscn" id="8_jmnx8"]
[sub_resource type="ButtonGroup" id="ButtonGroup_8vsfb"]

View file

@ -0,0 +1,67 @@
shader_type canvas_item;
// CurveTexture(s)
uniform sampler2D curve_rgb;
uniform sampler2D curve_red;
uniform sampler2D curve_green;
uniform sampler2D curve_blue;
uniform sampler2D curve_alpha;
uniform sampler2D curve_hue;
uniform sampler2D curve_sat;
uniform sampler2D curve_value;
uniform sampler2D selection : filter_nearest;
vec3 rgb2hsb(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz),
vec4(c.gb, K.xy),
step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r),
vec4(c.r, p.yzx),
step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
d / (q.x + e),
q.x);
}
vec3 hsb2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void fragment() {
vec4 original_color = texture(TEXTURE, UV);
vec4 selection_color = texture(selection, UV);
vec4 col;
float red_curve_color = texture(curve_red, vec2(COLOR.r, 0.0)).r;
float green_curve_color = texture(curve_green, vec2(COLOR.g, 0.0)).r;
float blue_curve_color = texture(curve_blue, vec2(COLOR.b, 0.0)).r;
float alpha_curve_color = texture(curve_alpha, vec2(COLOR.a, 0.0)).r;
col.r = red_curve_color;
col.g = green_curve_color;
col.b = blue_curve_color;
col.a = alpha_curve_color;
vec3 hsb = rgb2hsb(col.rgb);
float hue_curve_color = texture(curve_hue, vec2(hsb.r, 0.0)).r;
float sat_curve_color = texture(curve_sat, vec2(hsb.g, 0.0)).r;
float value_curve_color = texture(curve_value, vec2(hsb.b, 0.0)).r;
hsb.r = hue_curve_color;
hsb.g = sat_curve_color;
hsb.b = value_curve_color;
col.rgb = hsb2rgb(hsb);
float rgb_curve_color_r = texture(curve_rgb, vec2(col.r, 0.0)).r;
float rgb_curve_color_g = texture(curve_rgb, vec2(col.g, 0.0)).r;
float rgb_curve_color_b = texture(curve_rgb, vec2(col.b, 0.0)).r;
col.rgb = vec3(rgb_curve_color_r, rgb_curve_color_g, rgb_curve_color_b);
vec4 output = mix(original_color.rgba, col, selection_color.a);
COLOR = output;
}

View file

@ -2,11 +2,11 @@
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1"]
[ext_resource type="Script" path="res://src/Tools/3DTools/3DShapeEdit.gd" id="2"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="4"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="5"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="4"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="5"]
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="6"]
[ext_resource type="PackedScene" uid="uid://dpoteid430evf" path="res://src/UI/Nodes/ValueSliderV3.tscn" id="7"]
[ext_resource type="PackedScene" uid="uid://dpoteid430evf" path="res://src/UI/Nodes/Sliders/ValueSliderV3.tscn" id="7"]
[sub_resource type="InputEventAction" id="InputEventAction_8sqgw"]
action = &"delete"

View file

@ -1,10 +1,10 @@
[gd_scene load_steps=9 format=3 uid="uid://ubyatap3sylf"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="1"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="1"]
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="2"]
[ext_resource type="Script" path="res://src/Tools/BaseDraw.gd" id="3"]
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="3_76bek"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="5_kdxku"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="5_kdxku"]
[sub_resource type="ButtonGroup" id="ButtonGroup_7u3x0"]
resource_name = "rotate"

View file

@ -3,7 +3,7 @@
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1"]
[ext_resource type="Script" path="res://src/Tools/BaseSelectionTool.gd" id="2"]
[ext_resource type="Texture2D" uid="uid://d267xalp3p7ru" path="res://assets/graphics/misc/check_plain.png" id="3_mtv71"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="4"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="4"]
[ext_resource type="Texture2D" uid="uid://bnc78807k1xjv" path="res://assets/graphics/misc/close.png" id="4_ad04n"]
[sub_resource type="InputEventAction" id="InputEventAction_gfv4x"]

View file

@ -148,6 +148,7 @@ func draw_end(pos: Vector2i) -> void:
_start = Vector2i.ZERO
_dest = Vector2i.ZERO
_drawing = false
Global.canvas.previews_sprite.texture = null
_displace_origin = false
cursor_text = ""
super.draw_end(pos)
@ -174,8 +175,6 @@ func draw_preview() -> void:
image.set_pixelv(point, Color.WHITE)
var texture := ImageTexture.create_from_image(image)
canvas.texture = texture
else:
canvas.texture = null
func _draw_shape(origin: Vector2i, dest: Vector2i) -> void:

View file

@ -2,7 +2,7 @@
[ext_resource type="Script" path="res://src/Tools/BaseShapeDrawer.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://ubyatap3sylf" path="res://src/Tools/BaseDraw.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3"]
[sub_resource type="ButtonGroup" id="ButtonGroup_7w1wt"]
resource_name = "rotate"

View file

@ -1,9 +1,9 @@
[gd_scene load_steps=7 format=3 uid="uid://bbvvkrrjyxugo"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="1"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="1"]
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="2"]
[ext_resource type="Script" path="res://src/Tools/DesignTools/Bucket.gd" id="3"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="4_1pngp"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="4_1pngp"]
[sub_resource type="StyleBoxFlat" id="2"]
bg_color = Color(1, 1, 1, 1)

View file

@ -128,7 +128,6 @@ func draw_end(pos: Vector2i) -> void:
func draw_preview() -> void:
var previews := Global.canvas.previews_sprite
if not _drawing:
previews.texture = null
return
var points := _bezier()
var image := Image.create(
@ -207,6 +206,7 @@ func _clear() -> void:
_curve.clear_points()
_fill_inside_rect = Rect2i()
_drawing = false
Global.canvas.previews_sprite.texture = null
_editing_out_control_point = false
Global.canvas.previews.queue_redraw()

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://ubyatap3sylf" path="res://src/Tools/BaseDraw.tscn" id="1_rvuea"]
[ext_resource type="Script" path="res://src/Tools/DesignTools/CurveTool.gd" id="2_tjnp6"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3_g0nav"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3_g0nav"]
[sub_resource type="ButtonGroup" id="ButtonGroup_drx24"]
resource_name = "rotate"

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://ubyatap3sylf" path="res://src/Tools/BaseDraw.tscn" id="1"]
[ext_resource type="Script" path="res://src/Tools/DesignTools/Eraser.gd" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3"]
[sub_resource type="ButtonGroup" id="ButtonGroup_7k1sb"]
resource_name = "rotate"

View file

@ -142,6 +142,7 @@ func draw_end(pos: Vector2i) -> void:
_start = Vector2.ZERO
_dest = Vector2.ZERO
_drawing = false
Global.canvas.previews_sprite.texture = null
_displace_origin = false
cursor_text = ""
super.draw_end(pos)
@ -163,8 +164,6 @@ func draw_preview() -> void:
image.set_pixelv(point, Color.WHITE)
var texture := ImageTexture.create_from_image(image)
canvas.texture = texture
else:
canvas.texture = null
func _draw_shape() -> void:

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://ubyatap3sylf" path="res://src/Tools/BaseDraw.tscn" id="1"]
[ext_resource type="Script" path="res://src/Tools/DesignTools/LineTool.gd" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3"]
[sub_resource type="ButtonGroup" id="ButtonGroup_o5212"]
resource_name = "rotate"

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=5 format=3 uid="uid://cul5mpy17ebfl"]
[ext_resource type="PackedScene" uid="uid://ubyatap3sylf" path="res://src/Tools/BaseDraw.tscn" id="1"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="2"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="2"]
[ext_resource type="Script" path="res://src/Tools/DesignTools/Pencil.gd" id="3"]
[sub_resource type="ButtonGroup" id="ButtonGroup_e3rs3"]

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://ubyatap3sylf" path="res://src/Tools/BaseDraw.tscn" id="1"]
[ext_resource type="Script" path="res://src/Tools/DesignTools/Shading.gd" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3"]
[sub_resource type="ButtonGroup" id="ButtonGroup_lvcwb"]
resource_name = "rotate"

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://bd62qfjn380wf" path="res://src/Tools/BaseSelectionTool.tscn" id="1"]
[ext_resource type="Script" path="res://src/Tools/SelectionTools/ColorSelect.gd" id="2"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="3_44rxy"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="3_44rxy"]
[node name="ToolOptions" instance=ExtResource("1")]
script = ExtResource("2")

View file

@ -68,8 +68,6 @@ func draw_preview() -> void:
image.set_pixelv(point, Color.WHITE)
var texture := ImageTexture.create_from_image(image)
canvas.texture = texture
else:
canvas.texture = null
func apply_selection(_position: Vector2i) -> void:
@ -111,6 +109,7 @@ func apply_selection(_position: Vector2i) -> void:
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
Global.canvas.selection.commit_undo("Select", undo_data)
Global.canvas.previews_sprite.texture = null
func set_ellipse(selection_map: SelectionMap, pos: Vector2i) -> void:

View file

@ -54,8 +54,6 @@ func draw_preview() -> void:
image.set_pixelv(draw_point, Color.WHITE)
var texture := ImageTexture.create_from_image(image)
canvas.texture = texture
else:
canvas.texture = null
func apply_selection(_position) -> void:
@ -82,6 +80,7 @@ func apply_selection(_position) -> void:
Global.canvas.selection.commit_undo("Select", undo_data)
_draw_points.clear()
_last_position = Vector2.INF
Global.canvas.previews_sprite.texture = null
func lasso_selection(

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://bd62qfjn380wf" path="res://src/Tools/BaseSelectionTool.tscn" id="1"]
[ext_resource type="Script" path="res://src/Tools/SelectionTools/MagicWand.gd" id="2"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="3_4ed6a"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="3_4ed6a"]
[node name="ToolOptions" instance=ExtResource("1")]
script = ExtResource("2")

View file

@ -82,8 +82,6 @@ func draw_preview() -> void:
image.set_pixelv(draw_point, Color.WHITE)
var texture := ImageTexture.create_from_image(image)
canvas.texture = texture
else:
canvas.texture = null
func apply_selection(pos: Vector2i) -> void:
@ -111,6 +109,7 @@ func apply_selection(pos: Vector2i) -> void:
Global.canvas.selection.commit_undo("Select", undo_data)
_draw_points.clear()
_last_position = Vector2.INF
Global.canvas.previews_sprite.texture = null
func paint_selection(

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://bd62qfjn380wf" path="res://src/Tools/BaseSelectionTool.tscn" id="1"]
[ext_resource type="Script" path="res://src/Tools/SelectionTools/PaintSelect.gd" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3"]
[sub_resource type="StyleBoxFlat" id="1"]
bg_color = Color(1, 1, 1, 1)

View file

@ -89,8 +89,6 @@ func draw_preview() -> void:
image.set_pixelv(draw_point, Color.WHITE)
var texture := ImageTexture.create_from_image(image)
previews.texture = texture
else:
previews.texture = null
func apply_selection(pos: Vector2i) -> void:
@ -122,6 +120,7 @@ func apply_selection(pos: Vector2i) -> void:
func _clear() -> void:
_ongoing_selection = false
Global.canvas.previews_sprite.texture = null
_draw_points.clear()
_ready_to_apply = false
Global.canvas.previews.queue_redraw()

View file

@ -1,10 +1,10 @@
[gd_scene load_steps=6 format=3 uid="uid://c35n21ii7onhe"]
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="2"]
[ext_resource type="Script" path="res://src/Tools/UtilityTools/CropTool.gd" id="3"]
[ext_resource type="Texture2D" uid="uid://bgrq56ndc4ydj" path="res://assets/graphics/misc/unlocked_size.png" id="4"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="5"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="5"]
[node name="ToolOptions" instance=ExtResource("1")]
script = ExtResource("3")

View file

@ -3,7 +3,7 @@
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1_1q6ub"]
[ext_resource type="Script" path="res://src/Tools/UtilityTools/Text.gd" id="2_ql5g6"]
[ext_resource type="Texture2D" uid="uid://d267xalp3p7ru" path="res://assets/graphics/misc/check_plain.png" id="3_novww"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="3_tidsq"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="3_tidsq"]
[ext_resource type="Texture2D" uid="uid://bnc78807k1xjv" path="res://assets/graphics/misc/close.png" id="4_nhcnn"]
[node name="ToolOptions" instance=ExtResource("1_1q6ub")]
@ -101,11 +101,13 @@ popup/item_3/text = "Bold Italic"
popup/item_3/id = 3
[node name="HorizontalAlignmentLabel" type="Label" parent="GridContainer" index="4"]
visible = false
layout_mode = 2
size_flags_horizontal = 3
text = "Horizontal alignment:"
[node name="HorizontalAlignmentOptionButton" type="OptionButton" parent="GridContainer" index="5"]
visible = false
layout_mode = 2
selected = 0
item_count = 4

View file

@ -7,7 +7,7 @@
[ext_resource type="Script" path="res://src/UI/Canvas/CanvasCamera.gd" id="5_ge2km"]
[ext_resource type="Texture2D" uid="uid://c7smxwfa8826j" path="res://assets/graphics/timeline/play.png" id="6"]
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="7_o7sn3"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="8"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="8"]
[sub_resource type="ShaderMaterial" id="1"]
shader = ExtResource("2")

View file

@ -3,7 +3,7 @@
[ext_resource type="Script" path="res://src/UI/Dialogs/ExportDialog.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://3pmb60gpst7b" path="res://src/UI/Nodes/TransparentChecker.tscn" id="2"]
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="3"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="4"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="4"]
[node name="ExportDialog" type="ConfirmationDialog"]
canvas_item_default_texture_filter = 0

View file

@ -2,12 +2,11 @@
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1_5wfra"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/BrightnessContrastDialog.gd" id="2_msv0o"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="3_2epr4"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="3_2epr4"]
[node name="BrightnessContrastDialog" instance=ExtResource("1_5wfra")]
title = "Adjust Brightness/Contrast"
size = Vector2i(362, 540)
visible = true
script = ExtResource("2_msv0o")
[node name="VBoxContainer" parent="." index="3"]

View file

@ -0,0 +1,50 @@
extends ImageEffect
enum Channel { RGB, RED, GREEN, BLUE, ALPHA, HUE, SATURATION, VALUE }
const SHADER := preload("res://src/Shaders/Effects/ColorCurves.gdshader")
var curves: Array[Curve]
@onready var channel_option_button := %ChannelOptionButton as OptionButton
@onready var curve_edit := $VBoxContainer/CurveEdit as CurveEdit
func _ready() -> void:
super._ready()
var sm := ShaderMaterial.new()
sm.shader = SHADER
preview.set_material(sm)
for i in channel_option_button.item_count:
var curve := Curve.new()
curve.add_point(Vector2.ZERO, 0, 1, Curve.TANGENT_LINEAR)
curve.add_point(Vector2.ONE, 1, 0, Curve.TANGENT_LINEAR)
curves.append(curve)
curve_edit.curve = curves[Channel.RGB]
func commit_action(cel: Image, project := Global.current_project) -> void:
var selection_tex: ImageTexture
if selection_checkbox.button_pressed and project.has_selection:
var selection := project.selection_map.return_cropped_copy(project.size)
selection_tex = ImageTexture.create_from_image(selection)
var params := {
"curve_rgb": CurveEdit.to_texture(curves[Channel.RGB]),
"curve_red": CurveEdit.to_texture(curves[Channel.RED]),
"curve_green": CurveEdit.to_texture(curves[Channel.GREEN]),
"curve_blue": CurveEdit.to_texture(curves[Channel.BLUE]),
"curve_alpha": CurveEdit.to_texture(curves[Channel.ALPHA]),
"curve_hue": CurveEdit.to_texture(curves[Channel.HUE]),
"curve_sat": CurveEdit.to_texture(curves[Channel.SATURATION]),
"curve_value": CurveEdit.to_texture(curves[Channel.VALUE]),
"selection": selection_tex
}
if !has_been_confirmed:
for param in params:
preview.material.set_shader_parameter(param, params[param])
else:
var gen := ShaderImageEffect.new()
gen.generate_image(cel, SHADER, params, project.size)
func _on_channel_option_button_item_selected(index: int) -> void:
curve_edit.curve = curves[index]

View file

@ -0,0 +1,61 @@
[gd_scene load_steps=5 format=3 uid="uid://cthknpr74lawl"]
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1_4g7xo"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/ColorCurvesDialog.gd" id="2_xkivc"]
[ext_resource type="Script" path="res://src/UI/Nodes/CurveEditor/CurveEdit.gd" id="3_3yyhs"]
[sub_resource type="Curve" id="Curve_gvi51"]
_data = [Vector2(0, 0), 0.0, 1.0, 0, 1, Vector2(1, 1), 1.0, 0.0, 1, 0]
point_count = 2
[node name="ColorCurvesDialog" instance=ExtResource("1_4g7xo")]
title = "Color Curves"
size = Vector2i(362, 481)
script = ExtResource("2_xkivc")
[node name="VBoxContainer" parent="." index="3"]
offset_bottom = 432.0
[node name="ShowAnimate" parent="VBoxContainer" index="0"]
visible = false
[node name="ColorOptions" type="GridContainer" parent="VBoxContainer" index="3"]
layout_mode = 2
columns = 2
[node name="ChannelLabel" type="Label" parent="VBoxContainer/ColorOptions" index="0"]
layout_mode = 2
size_flags_horizontal = 3
text = "Channel:"
[node name="ChannelOptionButton" type="OptionButton" parent="VBoxContainer/ColorOptions" index="1"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
mouse_default_cursor_shape = 2
selected = 0
item_count = 8
popup/item_0/text = "RGB"
popup/item_1/text = "Red"
popup/item_1/id = 1
popup/item_2/text = "Green"
popup/item_2/id = 2
popup/item_3/text = "Blue"
popup/item_3/id = 3
popup/item_4/text = "Alpha"
popup/item_4/id = 4
popup/item_5/text = "Hue"
popup/item_5/id = 5
popup/item_6/text = "Saturation"
popup/item_6/id = 6
popup/item_7/text = "Value"
popup/item_7/id = 7
[node name="CurveEdit" type="VBoxContainer" parent="VBoxContainer" index="4"]
custom_minimum_size = Vector2(32, 150)
layout_mode = 2
size_flags_vertical = 3
script = ExtResource("3_3yyhs")
curve = SubResource("Curve_gvi51")
[connection signal="item_selected" from="VBoxContainer/ColorOptions/ChannelOptionButton" to="." method="_on_channel_option_button_item_selected"]

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/DropShadowDialog.gd" id="2"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="3"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="3"]
[node name="DropShadowDialog" instance=ExtResource("1")]
title = "Drop Shadow"

View file

@ -43,6 +43,8 @@ func _flip_image(cel: Image, affect_selection: bool, project: Project) -> void:
if flip_v.button_pressed:
selected.flip_y()
cel.blend_rect(selected, Rect2i(Vector2i.ZERO, selected.get_size()), rectangle.position)
if cel is ImageExtended:
cel.convert_rgb_to_indexed()
func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void:

View file

@ -2,8 +2,8 @@
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1_cuu40"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/GaussianBlur.gd" id="2_37xhl"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="3_237k2"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="4_yprgi"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="3_237k2"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="4_yprgi"]
[node name="GaussianBlur" instance=ExtResource("1_cuu40")]
title = "Gaussian Blur"

View file

@ -3,8 +3,8 @@
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/GradientDialog.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://bn4aw27dj7pwi" path="res://src/UI/Nodes/GradientEdit.tscn" id="3"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="4"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="5"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="4"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="5"]
[node name="GradientDialog" instance=ExtResource("2")]
title = "Gradient"

View file

@ -2,7 +2,7 @@
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/HSVDialog.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3"]
[node name="HSVDialog" instance=ExtResource("2")]
title = "Adjust Hue/Saturation/Value"

View file

@ -4,7 +4,7 @@
[ext_resource type="PackedScene" uid="uid://3pmb60gpst7b" path="res://src/UI/Nodes/TransparentChecker.tscn" id="2"]
[ext_resource type="Script" path="res://src/Classes/ImageEffect.gd" id="3"]
[ext_resource type="Texture2D" uid="uid://blrd4x0ma7b3h" path="res://assets/graphics/misc/animate.png" id="4"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="4_whox6"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="4_whox6"]
[node name="ImageEffectParent" type="ConfirmationDialog"]
canvas_item_default_texture_filter = 0

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=4 format=3 uid="uid://q355qqjvuajs"]
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="2"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="2"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/OffsetImage.gd" id="3"]
[node name="OffsetImage" instance=ExtResource("1")]

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=4 format=3 uid="uid://ci2qpf6t3dyyr"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/OutlineDialog.gd" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="2"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="2"]
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="3"]
[node name="OutlineDialog" instance=ExtResource("3")]

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1_eiotn"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/PixelizeDialog.gd" id="2_x5pd6"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="3_s7ey1"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="3_s7ey1"]
[node name="PixelizeDialog" instance=ExtResource("1_eiotn")]
title = "Pixelize"

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=4 format=3 uid="uid://cnryslyvxv4ye"]
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="2"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="2"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/Posterize.gd" id="3"]
[node name="Posterize" instance=ExtResource("1")]

View file

@ -2,8 +2,8 @@
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/RotateImage.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="4"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="4"]
[node name="RotateImage" instance=ExtResource("2")]
title = "Rotate Image"

View file

@ -3,8 +3,7 @@ extends ImageEffect
var shader: Shader
var params := {}
@onready var shader_loaded_label: Label = $VBoxContainer/ShaderLoadedLabel
@onready var shader_params: BoxContainer = $VBoxContainer/ShaderParams
@onready var shader_params := $VBoxContainer/ShaderParams as VBoxContainer
func _about_to_popup() -> void:
@ -17,36 +16,22 @@ func _about_to_popup() -> void:
super._about_to_popup()
func commit_action(cel: Image, project := Global.current_project) -> void:
if !shader:
return
func set_nodes() -> void:
aspect_ratio_container = $VBoxContainer/AspectRatioContainer
preview = $VBoxContainer/AspectRatioContainer/Preview
func commit_action(cel: Image, project := Global.current_project) -> void:
if not is_instance_valid(shader):
return
var gen := ShaderImageEffect.new()
gen.generate_image(cel, shader, params, project.size)
func _on_ChooseShader_pressed() -> void:
if OS.get_name() == "Web":
Html5FileExchange.load_shader()
else:
$FileDialog.popup_centered(Vector2(300, 340))
func _on_FileDialog_file_selected(path: String) -> void:
var shader_tmp = load(path)
if !shader_tmp is Shader:
return
change_shader(shader_tmp, path.get_file().get_basename())
func set_nodes() -> void:
preview = $VBoxContainer/AspectRatioContainer/Preview
func change_shader(shader_tmp: Shader, shader_name: String) -> void:
shader = shader_tmp
preview.material.shader = shader_tmp
shader_loaded_label.text = tr("Shader loaded:") + " " + shader_name
title = shader_name
params.clear()
for child in shader_params.get_children():
child.queue_free()

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=4 format=3 uid="uid://bkr47ocij684y"]
[gd_scene load_steps=4 format=3 uid="uid://b1ola6loro5m7"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/ShaderEffect.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://3pmb60gpst7b" path="res://src/UI/Nodes/TransparentChecker.tscn" id="2"]
@ -6,6 +6,8 @@
[sub_resource type="ShaderMaterial" id="1"]
[node name="ShaderEffect" type="ConfirmationDialog"]
position = Vector2i(0, 36)
size = Vector2i(612, 350)
script = ExtResource("1")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
@ -15,17 +17,14 @@ anchor_bottom = 1.0
offset_left = 8.0
offset_top = 8.0
offset_right = -8.0
offset_bottom = -36.0
[node name="Label" type="Label" parent="VBoxContainer"]
layout_mode = 2
text = "This is an experimental feature and may not be included in the stable version"
offset_bottom = -49.0
[node name="AspectRatioContainer" type="AspectRatioContainer" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="Preview" type="TextureRect" parent="VBoxContainer/AspectRatioContainer"]
texture_filter = 1
material = SubResource("1")
custom_minimum_size = Vector2(200, 200)
layout_mode = 2
@ -39,22 +38,5 @@ anchors_preset = 0
anchor_right = 1.0
anchor_bottom = 1.0
[node name="ChooseShader" type="Button" parent="VBoxContainer"]
layout_mode = 2
mouse_default_cursor_shape = 2
text = "Choose Shader"
[node name="ShaderLoadedLabel" type="Label" parent="VBoxContainer"]
layout_mode = 2
text = "No shader loaded!"
[node name="ShaderParams" type="VBoxContainer" parent="VBoxContainer"]
layout_mode = 2
[node name="FileDialog" type="FileDialog" parent="." groups=["FileDialogs"]]
access = 2
filters = PackedStringArray("*gdshader; Godot Shader File")
show_hidden_files = true
[connection signal="pressed" from="VBoxContainer/ChooseShader" to="." method="_on_ChooseShader_pressed"]
[connection signal="file_selected" from="FileDialog" to="." method="_on_FileDialog_file_selected"]

View file

@ -4,7 +4,7 @@
[ext_resource type="Script" path="res://src/UI/Dialogs/HelperScripts/RowColumnLines.gd" id="2_yokw4"]
[ext_resource type="Script" path="res://src/UI/Dialogs/HelperScripts/SmartSlicePreview.gd" id="3_aeccv"]
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="4_7dy5o"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="4_nmo33"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="4_nmo33"]
[node name="ImportPreviewDialog" type="ConfirmationDialog"]
canvas_item_default_texture_filter = 0

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://wcbpnsm7gptu"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="1_3jelw"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="1_3jelw"]
[ext_resource type="Script" path="res://src/UI/Dialogs/ModifySelection.gd" id="1_w6rs7"]
[node name="ModifySelection" type="ConfirmationDialog"]

View file

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://3pmb60gpst7b" path="res://src/UI/Nodes/TransparentChecker.tscn" id="1"]
[ext_resource type="Script" path="res://src/UI/Canvas/TileMode.gd" id="2"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="2_ul2eq"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="2_ul2eq"]
[ext_resource type="Script" path="res://src/UI/Dialogs/TileModeOffsetsDialog.gd" id="3"]
[sub_resource type="CanvasItemMaterial" id="1"]

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://bcdt0pa7rojy5"]
[ext_resource type="Script" path="res://src/UI/Dialogs/WindowOpacityDialog.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="2"]
[node name="WindowOpacityDialog" type="AcceptDialog"]
title = "Window Opacity"

View file

@ -5,7 +5,7 @@
[ext_resource type="Script" path="res://src/UI/GlobalToolOptions/GlobalToolOptions.gd" id="3"]
[ext_resource type="Texture2D" uid="uid://ct8wn8m6x4m54" path="res://assets/graphics/misc/value_arrow.svg" id="3_faalk"]
[ext_resource type="Texture2D" uid="uid://22h12g8p3jtd" path="res://assets/graphics/misc/pixel_perfect_off.png" id="4"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="5"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="5"]
[ext_resource type="Texture2D" uid="uid://dlxhm0ronna25" path="res://assets/graphics/misc/xy_mirror_off.png" id="5_hcmgx"]
[ext_resource type="Texture2D" uid="uid://j8eywwy082a4" path="res://assets/graphics/misc/alpha_lock_off.png" id="5_jv20x"]
[ext_resource type="Texture2D" uid="uid://dg3dumyfj1682" path="res://assets/graphics/misc/dynamics.png" id="6"]

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://dmlgx1jgau8a5"]
[ext_resource type="Script" path="res://src/UI/Nodes/AnimatePanel.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="2"]
[node name="AnimatePanel" type="PanelContainer"]
offset_right = 360.0

View file

@ -0,0 +1,103 @@
# Code taken and modified from Material Maker, licensed under MIT
# gdlint: ignore=max-line-length
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/curve_edit/control_point.gd
class_name CurveEditControlPoint
extends Control
signal moved(index: int)
signal removed(index: int)
const OFFSET := Vector2(3, 3)
var moving := false
var min_x: float
var max_x: float
var min_y: float
var max_y: float
var left_slope: CurveEditTangentPoint
var right_slope: CurveEditTangentPoint
@onready var parent := get_parent() as Control
@onready var grandparent := parent.get_parent() as CurveEdit
func _ready() -> void:
gui_input.connect(_on_gui_input)
custom_minimum_size = Vector2(8, 8)
left_slope = CurveEditTangentPoint.new()
right_slope = CurveEditTangentPoint.new()
add_child(left_slope)
add_child(right_slope)
func _draw() -> void:
var color := Color.GRAY
var current_scene := get_tree().current_scene
if current_scene is Control:
var current_theme := (current_scene as Control).theme
color = current_theme.get_color("font_color", "Label")
for c: CurveEditTangentPoint in get_children():
if c.visible:
draw_line(OFFSET, c.position + OFFSET, color)
draw_rect(Rect2(0, 0, 7, 7), color)
func initialize(curve: Curve, index: int) -> void:
if not is_instance_valid(parent):
await ready
position = grandparent.transform_point(curve.get_point_position(index)) - OFFSET
var left_tangent := curve.get_point_left_tangent(index)
var right_tangent := curve.get_point_right_tangent(index)
if left_tangent != INF:
left_slope.position = (
left_slope.distance * (parent.size * Vector2(1.0, -left_tangent)).normalized()
)
if right_tangent != INF:
right_slope.position = (
right_slope.distance * (parent.size * Vector2(1.0, -right_tangent)).normalized()
)
func set_control_point_visibility(left: bool, new_visible: bool) -> void:
if not is_instance_valid(left_slope):
await ready
if left:
left_slope.visible = new_visible
else:
right_slope.visible = new_visible
func set_constraint(new_min_x: float, new_max_x: float, new_min_y: float, new_max_y: float) -> void:
min_x = new_min_x
max_x = new_max_x
min_y = new_min_y
max_y = new_max_y
func _on_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.pressed:
moving = true
else:
moving = false
grandparent.update_controls()
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
removed.emit(get_index())
elif moving and event is InputEventMouseMotion:
position += event.relative
if position.x < min_x:
position.x = min_x
elif position.x > max_x:
position.x = max_x
if position.y < min_y:
position.y = min_y
elif position.y > max_y:
position.y = max_y
moved.emit(get_index())
func update_tangents() -> void:
queue_redraw()
moved.emit(get_index())

View file

@ -0,0 +1,275 @@
# Code taken and modified from Material Maker, licensed under MIT
# gdlint: ignore=max-line-length
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/curve_edit/curve_view.gd
# and
# gdlint: ignore=max-line-length
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/curve_edit/curve_editor.gd
@tool
class_name CurveEdit
extends VBoxContainer
signal value_changed(value: Curve)
@export var show_axes := true
@export var curve: Curve:
set(value):
curve = value
queue_redraw()
update_controls()
## Array of dictionaries of key [String] and value [Array] of type [CurveEdit.CurvePoint].
var presets: Array[Dictionary] = [
{"Linear": [CurvePoint.new(0.0, 0.0, 0.0, 1.0), CurvePoint.new(1.0, 1.0, 1.0, 0.0)]},
{
"Ease out":
[
CurvePoint.new(0.0, 0.0, 0.0, 4.0),
CurvePoint.new(0.292893, 0.707107, 1.0, 1.0),
CurvePoint.new(1.0, 1.0, 0.0, 0.0)
]
},
{
"Ease in out":
[
CurvePoint.new(0.0, 0.0, 0.0, 0.0),
CurvePoint.new(0.5, 0.5, 3.0, 3.0),
CurvePoint.new(1.0, 1.0, 0.0, 0.0)
]
},
{
"Ease in":
[
CurvePoint.new(0.0, 0.0, 0.0, 0.0),
CurvePoint.new(0.707107, 0.292893, 1.0, 1.0),
CurvePoint.new(1.0, 1.0, 4.0, 0.0)
]
},
{
"Sawtooth":
[
CurvePoint.new(0.0, 0.0, 0.0, 2.0),
CurvePoint.new(0.5, 1.0, 2.0, -2.0),
CurvePoint.new(1.0, 0.0, -2.0, 0.0)
]
},
{
"Bounce":
[
CurvePoint.new(0.0, 0.0, 0.0, 5.0),
CurvePoint.new(0.15, 0.65, 2.45201, 2.45201),
CurvePoint.new(0.5, 1.0, 0.0, 0.0),
CurvePoint.new(0.85, 0.65, -2.45201, -2.45201),
CurvePoint.new(1.0, 0.0, -5.0, 0.0)
]
},
{
"Bevel":
[
CurvePoint.new(0.0, 0.0, 0.0, 2.38507),
CurvePoint.new(0.292893, 0.707107, 2.34362, 0.428147),
CurvePoint.new(1.0, 1.0, 0.410866, 0.0)
]
}
]
var curve_editor := Control.new()
var hbox := HBoxContainer.new()
class CurvePoint:
var pos: Vector2
var left_tangent: float
var right_tangent: float
func _init(x: float, y: float, _left_tangent := 0.0, _right_tangent := 0.0) -> void:
pos = Vector2(x, y)
left_tangent = _left_tangent
right_tangent = _right_tangent
func _ready() -> void:
if not is_instance_valid(curve):
curve = Curve.new()
if custom_minimum_size.is_zero_approx():
custom_minimum_size = Vector2(32, 150)
curve_editor.gui_input.connect(_on_gui_input)
resized.connect(_on_resize)
curve_editor.size_flags_vertical = Control.SIZE_EXPAND_FILL
add_child(curve_editor)
add_child(hbox)
var presets_button := MenuButton.new()
presets_button.text = "Presets"
presets_button.flat = false
presets_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
presets_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
presets_button.get_popup().id_pressed.connect(_on_presets_item_selected)
for preset in presets:
presets_button.get_popup().add_item(preset.keys()[0])
var invert_button := Button.new()
invert_button.text = "Invert"
invert_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
invert_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
invert_button.pressed.connect(_on_invert_button_pressed)
hbox.add_child(presets_button)
hbox.add_child(invert_button)
_on_resize.call_deferred()
func update_controls() -> void:
for c in curve_editor.get_children():
if c is CurveEditControlPoint:
c.queue_free()
for i in curve.point_count:
var p := curve.get_point_position(i)
var control_point := CurveEditControlPoint.new()
curve_editor.add_child(control_point)
control_point.initialize(curve, i)
control_point.position = transform_point(p) - control_point.OFFSET
if i == 0 or i == curve.point_count - 1:
control_point.set_constraint(
control_point.position.x,
control_point.position.x,
-control_point.OFFSET.y,
available_size().y - control_point.OFFSET.y
)
if i == 0:
control_point.set_control_point_visibility(true, false)
else:
control_point.set_control_point_visibility(false, false)
else:
var min_x := transform_point(curve.get_point_position(i - 1)).x + 1
var max_x := transform_point(curve.get_point_position(i + 1)).x - 1
control_point.set_constraint(
min_x, max_x, -control_point.OFFSET.y, available_size().y - control_point.OFFSET.y
)
control_point.moved.connect(_on_control_point_moved)
control_point.removed.connect(_on_control_point_removed)
value_changed.emit(curve)
static func to_texture(from_curve: Curve, width := 256) -> CurveTexture:
var texture := CurveTexture.new()
texture.texture_mode = CurveTexture.TEXTURE_MODE_RED
texture.curve = from_curve
texture.width = width
return texture
func set_default_curve() -> void:
if not is_instance_valid(curve):
curve = Curve.new()
_on_presets_item_selected(0)
func available_size() -> Vector2:
if curve_editor.size.is_zero_approx():
return Vector2.ONE
return curve_editor.size
func transform_point(p: Vector2) -> Vector2:
return (Vector2(0.0, 1.0) + Vector2(1.0, -1.0) * p) * available_size()
func reverse_transform_point(p: Vector2) -> Vector2:
return Vector2(0.0, 1.0) + Vector2(1.0, -1.0) * p / available_size()
func _draw() -> void:
var bg := Color.DARK_GRAY
var fg := Color.GRAY
var current_scene := get_tree().current_scene
if current_scene is Control:
var current_theme := (current_scene as Control).theme
var panel_stylebox := current_theme.get_stylebox("panel", "Panel")
if panel_stylebox is StyleBoxFlat:
bg = panel_stylebox.bg_color
fg = current_theme.get_color("font_color", "Label")
var axes_color := bg.lerp(fg, 0.25)
var curve_color := bg.lerp(fg, 0.75)
if show_axes:
for i in range(5):
var p := transform_point(0.25 * Vector2(i, i))
draw_line(Vector2(p.x, 0), Vector2(p.x, available_size().y - 1), axes_color)
draw_line(Vector2(0, p.y), Vector2(available_size().x - 1, p.y), axes_color)
var points := PackedVector2Array()
for i in range(curve.point_count - 1):
var p1 := curve.get_point_position(i)
var p2 := curve.get_point_position(i + 1)
var d := (p2.x - p1.x) / 3.0
var yac := p1.y + d * curve.get_point_right_tangent(i)
var ybc := p2.y - d * curve.get_point_left_tangent(i + 1)
var p := transform_point(p1)
if points.is_empty():
points.push_back(p)
var count := maxi(1, transform_point(p2).x - p.x / 5.0)
for tt in range(count):
var t := (tt + 1.0) / count
var omt := 1.0 - t
var omt2 := omt * omt
var omt3 := omt2 * omt
var t2 := t * t
var t3 := t2 * t
var x := p1.x + (p2.x - p1.x) * t
var y := p1.y * omt3 + yac * omt2 * t * 3.0 + ybc * omt * t2 * 3.0 + p2.y * t3
p = transform_point(Vector2(x, y))
points.push_back(p)
if points.size() > 1:
draw_polyline(points, curve_color)
func _on_control_point_moved(index: int) -> void:
var control_point := curve_editor.get_child(index) as CurveEditControlPoint
var new_point := reverse_transform_point(control_point.position + control_point.OFFSET)
curve.set_point_offset(index, new_point.x)
curve.set_point_value(index, new_point.y)
if is_instance_valid(control_point.left_slope):
var slope_vector := control_point.left_slope.position / available_size()
if slope_vector.x != 0:
curve.set_point_left_tangent(index, -slope_vector.y / slope_vector.x)
if is_instance_valid(control_point.right_slope):
var slope_vector := control_point.right_slope.position / available_size()
if slope_vector.x != 0:
curve.set_point_right_tangent(index, -slope_vector.y / slope_vector.x)
queue_redraw()
value_changed.emit(curve)
func _on_control_point_removed(index: int) -> void:
if index > 0 and index < curve.point_count:
curve.remove_point(index)
queue_redraw()
update_controls()
func _on_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.double_click:
var new_point_position := reverse_transform_point(get_local_mouse_position())
curve.add_point(new_point_position, 0.0, 0.0)
queue_redraw()
update_controls()
func _on_resize() -> void:
queue_redraw()
update_controls()
func _on_presets_item_selected(index: int) -> void:
curve.clear_points()
var preset_points: Array = presets[index].values()[0]
for point: CurvePoint in preset_points:
curve.add_point(point.pos, point.left_tangent, point.right_tangent)
curve = curve # Call setter
func _on_invert_button_pressed() -> void:
var copy_curve := curve.duplicate() as Curve
curve.clear_points()
for i in copy_curve.point_count:
var point := copy_curve.get_point_position(i)
point.y = 1.0 - point.y
var left_tangent := -copy_curve.get_point_left_tangent(i)
var right_tangent := -copy_curve.get_point_right_tangent(i)
curve.add_point(point, left_tangent, right_tangent)
curve = curve # Call setter

View file

@ -0,0 +1,62 @@
# Code taken and modified from Material Maker, licensed under MIT
# gdlint: ignore=max-line-length
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/curve_edit/slope_point.gd
class_name CurveEditTangentPoint
extends Control
const OFFSET := Vector2(0, 0)
@export var distance := 30
var moving = false
@onready var parent := get_parent() as CurveEditControlPoint
@onready var grandparent := parent.get_parent() as Control
func _ready() -> void:
gui_input.connect(_on_gui_input)
custom_minimum_size = Vector2(8, 8)
if get_index() == 0:
distance = -distance
func _draw() -> void:
var color := Color.GRAY
var current_scene := get_tree().current_scene
if current_scene is Control:
var current_theme := (current_scene as Control).theme
color = current_theme.get_color("font_color", "Label")
draw_circle(Vector2(3.0, 3.0), 3.0, color)
func _on_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.pressed:
if event.double_click:
var vector: Vector2
if get_index() == 0:
vector = (
parent.position - grandparent.get_child(parent.get_index() - 1).position
)
else:
vector = (
grandparent.get_child(parent.get_index() + 1).position - parent.position
)
vector = distance * vector.normalized()
position = vector - OFFSET
if event.is_control_or_command_pressed():
parent.get_child(1 - get_index()).position = -vector - OFFSET
parent.update_tangents()
else:
moving = true
else:
moving = false
elif moving and event is InputEventMouseMotion:
var vector := get_global_mouse_position() - parent.get_global_rect().position + OFFSET
vector *= signf(vector.x)
vector = distance * vector.normalized()
position = vector - OFFSET
if event.is_command_or_control_pressed():
parent.get_child(1 - get_index()).position = -vector - OFFSET
parent.update_tangents()

View file

@ -169,6 +169,13 @@ func get_gradient_color(x: float) -> Color:
return gradient.sample(x / x_offset)
func set_gradient_texture_1d(new_texture: GradientTexture1D) -> void:
texture = GradientTexture2D.new()
texture.gradient = new_texture.gradient
$TextureRect.texture = texture
gradient = texture.gradient
func set_gradient_texture(new_texture: GradientTexture2D) -> void:
$TextureRect.texture = new_texture
texture = new_texture

View file

@ -0,0 +1,125 @@
class_name NoiseGenerator
extends ScrollContainer
signal value_changed(noise_texture: NoiseTexture2D)
var noise_texture: NoiseTexture2D:
set(value):
noise_texture = value
if not is_instance_valid(noise_texture.noise):
noise_texture.noise = FastNoiseLite.new()
if not is_instance_valid(preview):
await ready
preview.texture = noise_texture
_set_node_values()
@onready var preview := %Preview as TextureRect
@onready var size_slider := %SizeSlider as ValueSliderV2
@onready var properties := {
"invert": %InvertCheckBox,
"in_3d_space": %In3DSpaceCheckBox,
"seamless": %SeamlessCheckBox,
"as_normal_map": %NormalMapCheckBox,
"normalize": %NormalizeCheckBox,
"color_ramp": %ColorRampEdit,
"noise:noise_type": %NoiseTypeOptionButton,
"noise:seed": %SeedSlider,
"noise:frequency": %FrequencySlider,
"noise:offset": %OffsetSlider,
"noise:fractal_type": %FractalTypeOptionButton,
"noise:fractal_octaves": %FractalOctavesSlider,
"noise:fractal_lacunarity": %FractalLacunaritySlider,
"noise:fractal_gain": %FractalGainSlider,
"noise:fractal_weighted_strength": %FractalWeightedStrengthSlider,
"noise:domain_warp_enabled": %DomainWarpEnabledCheckBox,
"noise:domain_warp_type": %DomainWarpTypeOptionButton,
"noise:domain_warp_amplitude": %DomainWarpAmplitudeSlider,
"noise:domain_warp_frequency": %DomainWarpFrequencySlider,
"noise:domain_warp_fractal_type": %DomainWarpFractalTypeOptionButton,
"noise:domain_warp_fractal_octaves": %DomainWarpFractalOctavesSlider,
"noise:domain_warp_fractal_lacunarity": %DomainWarpFractalLacunaritySlider,
"noise:domain_warp_fractal_gain": %DomainWarpFractalGainSlider
}
func _init() -> void:
noise_texture = NoiseTexture2D.new()
func _ready() -> void:
# Connect the signals of the object property nodes
for prop in properties:
var node: Control = properties[prop]
if node is ValueSliderV3:
node.value_changed.connect(_property_vector3_changed.bind(prop))
elif node is ValueSliderV2:
var property_path: String = prop
node.value_changed.connect(_property_vector2_changed.bind(property_path))
elif node is Range:
node.value_changed.connect(_property_value_changed.bind(prop))
elif node is OptionButton:
node.item_selected.connect(_property_item_selected.bind(prop))
elif node is CheckBox:
node.toggled.connect(_property_toggled.bind(prop))
elif node is GradientEditNode:
node.updated.connect(_property_gradient_changed.bind(prop))
func _set_node_values() -> void:
size_slider.value.x = noise_texture.width
size_slider.value.y = noise_texture.height
for prop in properties:
var property_path: String = prop
var value = noise_texture.get_indexed(property_path)
if value == null:
continue
var node: Control = properties[prop]
if node is Range or node is ValueSliderV3 or node is ValueSliderV2:
if typeof(node.value) != typeof(value) and typeof(value) != TYPE_INT:
continue
node.value = value
elif node is OptionButton:
node.selected = value
elif node is CheckBox:
node.button_pressed = value
elif node is GradientEditNode:
var gradient_tex := GradientTexture2D.new()
gradient_tex.gradient = value
node.set_gradient_texture(gradient_tex)
func _set_value_from_node(value, prop: String) -> void:
noise_texture.set_indexed(prop, value)
await noise_texture.changed
value_changed.emit(noise_texture)
func _property_vector3_changed(value: Vector3, prop: String) -> void:
_set_value_from_node(value, prop)
func _property_vector2_changed(value: Vector2, prop: String) -> void:
_set_value_from_node(value, prop)
func _property_value_changed(value: float, prop: String) -> void:
_set_value_from_node(value, prop)
func _property_item_selected(value: int, prop: String) -> void:
_set_value_from_node(value, prop)
func _property_gradient_changed(value: Gradient, _cc: bool, prop: String) -> void:
_set_value_from_node(value, prop)
func _property_toggled(value: bool, prop: String) -> void:
_set_value_from_node(value, prop)
func _on_size_slider_value_changed(value: Vector2) -> void:
noise_texture.width = value.x
noise_texture.height = value.y
await noise_texture.changed
value_changed.emit(noise_texture)

View file

@ -0,0 +1,508 @@
[gd_scene load_steps=7 format=3 uid="uid://be14ffwmcp5xy"]
[ext_resource type="PackedScene" uid="uid://bbnqcxa20a5a5" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="1_evt0j"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="1_pm12o"]
[ext_resource type="Script" path="res://src/UI/Nodes/NoiseGenerator.gd" id="1_uxdt4"]
[ext_resource type="PackedScene" uid="uid://bn4aw27dj7pwi" path="res://src/UI/Nodes/GradientEdit.tscn" id="2_nxkb0"]
[ext_resource type="PackedScene" uid="uid://dpoteid430evf" path="res://src/UI/Nodes/Sliders/ValueSliderV3.tscn" id="3_ffklk"]
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="4_r1f12"]
[node name="NoiseGenerator" type="ScrollContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_uxdt4")
[node name="VSplitContainer" type="VSplitContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Preview" type="TextureRect" parent="VSplitContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(64, 64)
layout_mode = 2
size_flags_vertical = 3
expand_mode = 1
stretch_mode = 5
[node name="VBoxContainer" type="VBoxContainer" parent="VSplitContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="GridContainer" type="GridContainer" parent="VSplitContainer/VBoxContainer"]
layout_mode = 2
columns = 2
[node name="SizeLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Size:"
[node name="SizeSlider" parent="VSplitContainer/VBoxContainer/GridContainer" instance=ExtResource("1_evt0j")]
unique_name_in_owner = true
layout_mode = 2
value = Vector2(512, 512)
min_value = Vector2(1, 1)
max_value = Vector2(1024, 1024)
allow_greater = true
show_ratio = true
grid_columns = 2
suffix_x = "px"
suffix_y = "px"
[node name="InvertLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Invert:"
[node name="InvertCheckBox" type="CheckBox" parent="VSplitContainer/VBoxContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_default_cursor_shape = 2
text = "On"
[node name="In3DSpaceLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "In 3D space:"
[node name="In3DSpaceCheckBox" type="CheckBox" parent="VSplitContainer/VBoxContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_default_cursor_shape = 2
text = "On"
[node name="SeamlessLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Seamless:"
[node name="SeamlessCheckBox" type="CheckBox" parent="VSplitContainer/VBoxContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_default_cursor_shape = 2
text = "On"
[node name="NormalMapLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Normal map:"
[node name="NormalMapCheckBox" type="CheckBox" parent="VSplitContainer/VBoxContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_default_cursor_shape = 2
text = "On"
[node name="NormalizeLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Normalize:"
[node name="NormalizeCheckBox" type="CheckBox" parent="VSplitContainer/VBoxContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_default_cursor_shape = 2
button_pressed = true
text = "On"
[node name="ColorRampLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Color ramp:"
[node name="ColorRampEdit" parent="VSplitContainer/VBoxContainer/GridContainer" instance=ExtResource("2_nxkb0")]
unique_name_in_owner = true
layout_mode = 2
[node name="NoiseTypeLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Noise type:"
[node name="NoiseTypeOptionButton" type="OptionButton" parent="VSplitContainer/VBoxContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
mouse_default_cursor_shape = 2
selected = 1
item_count = 6
popup/item_0/text = "Simplex"
popup/item_1/text = "Simplex Smooth"
popup/item_1/id = 1
popup/item_2/text = "Cellural"
popup/item_2/id = 2
popup/item_3/text = "Perlin"
popup/item_3/id = 3
popup/item_4/text = "Value Cubic"
popup/item_4/id = 4
popup/item_5/text = "Value"
popup/item_5/id = 5
[node name="SeedLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Seed:"
[node name="SeedSlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
max_value = 1024.0
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
[node name="FrequencyLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Frequency:"
[node name="FrequencySlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
min_value = 0.001
max_value = 1.0
step = 0.001
value = 0.001
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
snap_step = 0.1
[node name="OffsetLabel" type="Label" parent="VSplitContainer/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Offset:"
[node name="OffsetSlider" parent="VSplitContainer/VBoxContainer/GridContainer" instance=ExtResource("3_ffklk")]
unique_name_in_owner = true
layout_mode = 2
min_value = Vector3(-1000, -1000, -1000)
max_value = Vector3(1000, 1000, 1000)
grid_columns = 3
[node name="FractalOptions" type="VBoxContainer" parent="VSplitContainer/VBoxContainer"]
layout_mode = 2
theme_type_variation = &"CollapsibleContainer"
script = ExtResource("4_r1f12")
text = "Fractal"
[node name="GridContainer" type="GridContainer" parent="VSplitContainer/VBoxContainer/FractalOptions"]
visible = false
layout_mode = 2
columns = 2
[node name="FractalTypeLabel" type="Label" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Type:"
[node name="FractalTypeOptionButton" type="OptionButton" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
mouse_default_cursor_shape = 2
selected = 0
item_count = 4
popup/item_0/text = "None"
popup/item_1/text = "FBM"
popup/item_1/id = 1
popup/item_2/text = "Ridged"
popup/item_2/id = 2
popup/item_3/text = "Ping-Pong"
popup/item_3/id = 3
[node name="FractalOctavesLabel" type="Label" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Octaves:"
[node name="FractalOctavesSlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
min_value = 1.0
max_value = 10.0
value = 5.0
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
[node name="FractalLacunarityLabel" type="Label" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Lacunarity:"
[node name="FractalLacunaritySlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
min_value = -50.0
max_value = 50.0
value = 2.0
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
[node name="FractalGainLabel" type="Label" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Gain:"
[node name="FractalGainSlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
min_value = -20.0
max_value = 20.0
step = 0.001
value = 0.5
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
snap_step = 0.01
[node name="FractalWeightedStrengthLabel" type="Label" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Weighted Strength:"
[node name="FractalWeightedStrengthSlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/FractalOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
max_value = 1.0
step = 0.01
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
snap_step = 0.1
[node name="DomainWarpOptions" type="VBoxContainer" parent="VSplitContainer/VBoxContainer"]
layout_mode = 2
theme_type_variation = &"CollapsibleContainer"
script = ExtResource("4_r1f12")
text = "Domain Warp"
[node name="GridContainer" type="GridContainer" parent="VSplitContainer/VBoxContainer/DomainWarpOptions"]
visible = false
layout_mode = 2
columns = 2
[node name="DomainWarpEnabledLabel" type="Label" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Enabled:"
[node name="DomainWarpEnabledCheckBox" type="CheckBox" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_default_cursor_shape = 2
text = "On"
[node name="DomainWarpTypeLabel" type="Label" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Type:"
[node name="DomainWarpTypeOptionButton" type="OptionButton" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
mouse_default_cursor_shape = 2
selected = 0
item_count = 3
popup/item_0/text = "Simplex"
popup/item_1/text = "Simplex Reduced"
popup/item_1/id = 1
popup/item_2/text = "Basic Grid"
popup/item_2/id = 2
[node name="DomainWarpAmplitudeLabel" type="Label" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Amplitude:"
[node name="DomainWarpAmplitudeSlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
value = 30.0
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
[node name="DomainWarpFrequencyLabel" type="Label" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Frequency:"
[node name="DomainWarpFrequencySlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
min_value = -20.0
max_value = 20.0
step = 0.001
value = 0.05
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
snap_step = 0.01
[node name="DomainWarpFractalTypeLabel" type="Label" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Fractal type:"
[node name="DomainWarpFractalTypeOptionButton" type="OptionButton" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
mouse_default_cursor_shape = 2
selected = 0
item_count = 3
popup/item_0/text = "None"
popup/item_1/text = "Progressive"
popup/item_1/id = 1
popup/item_2/text = "Independent"
popup/item_2/id = 2
[node name="DomainWarpFractalOctavesLabel" type="Label" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Fractal octaves:"
[node name="DomainWarpFractalOctavesSlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
min_value = 1.0
max_value = 10.0
value = 5.0
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
[node name="DomainWarpFractalLacunarityLabel" type="Label" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Fractal lacunarity:"
[node name="DomainWarpFractalLacunaritySlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
min_value = -50.0
max_value = 50.0
value = 6.0
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
[node name="DomainWarpFractalGainLabel" type="Label" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Fractal gain:"
[node name="DomainWarpFractalGainSlider" type="TextureProgressBar" parent="VSplitContainer/VBoxContainer/DomainWarpOptions/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
min_value = -20.0
max_value = 20.0
step = 0.001
value = 0.5
allow_greater = true
allow_lesser = true
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource("1_pm12o")
snap_step = 0.01
[connection signal="value_changed" from="VSplitContainer/VBoxContainer/GridContainer/SizeSlider" to="." method="_on_size_slider_value_changed"]

View file

@ -0,0 +1,15 @@
[gd_scene load_steps=2 format=3 uid="uid://buixtfobyc3df"]
[ext_resource type="PackedScene" uid="uid://be14ffwmcp5xy" path="res://src/UI/Nodes/NoiseGenerator.tscn" id="1_wso7i"]
[node name="NoiseGeneratorDialog" type="AcceptDialog"]
title = "Generate noise"
size = Vector2i(500, 500)
[node name="NoiseGenerator" parent="." instance=ExtResource("1_wso7i")]
offset_left = 8.0
offset_top = 8.0
offset_right = -8.0
offset_bottom = -49.0
size_flags_horizontal = 3
size_flags_vertical = 3

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://d0d66oh6bw3kt"]
[ext_resource type="Script" path="res://src/UI/Nodes/BasisSliders.gd" id="1_sbf5t"]
[ext_resource type="PackedScene" uid="uid://dpoteid430evf" path="res://src/UI/Nodes/ValueSliderV3.tscn" id="2_7swri"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/BasisSliders.gd" id="1_sbf5t"]
[ext_resource type="PackedScene" uid="uid://dpoteid430evf" path="res://src/UI/Nodes/Sliders/ValueSliderV3.tscn" id="2_7swri"]
[node name="BasisSliders" type="HBoxContainer"]
offset_right = 40.0

View file

@ -166,6 +166,7 @@ func _gui_input(event: InputEvent) -> void:
else:
if event.ctrl_pressed:
value = roundf(value / snap_step) * snap_step
get_viewport().set_input_as_handled()
func _setup_nodes() -> void: ## Only called once on _ready()

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://yjhp0ssng2mp"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="1"]
[ext_resource type="Texture2D" uid="uid://c7u0yofrpm50a" path="res://assets/graphics/misc/value_slider.png" id="2"]
[node name="ValueSlider" type="TextureProgressBar"]

View file

@ -25,11 +25,13 @@ signal ratio_toggled(button_pressed: bool)
min_value = val
$GridContainer/X.min_value = val.x
$GridContainer/Y.min_value = val.y
value = value # Call value setter
@export var max_value := Vector2(100.0, 100.0):
set(val):
max_value = val
$GridContainer/X.max_value = val.x
$GridContainer/Y.max_value = val.y
value = value # Call value setter
@export var step := 1.0:
set(val):
step = val

View file

@ -1,70 +1,68 @@
[gd_scene load_steps=6 format=2]
[gd_scene load_steps=6 format=3 uid="uid://bbnqcxa20a5a5"]
[ext_resource path="res://src/UI/Nodes/ValueSlider.gd" type="Script" id=1]
[ext_resource path="res://src/UI/Nodes/ValueSliderV2.gd" type="Script" id=2]
[ext_resource path="res://assets/graphics/misc/lock_aspect_2.png" type="Texture2D" id=3]
[ext_resource path="res://assets/graphics/misc/lock_aspect_guides.png" type="Texture2D" id=4]
[ext_resource path="res://assets/graphics/misc/lock_aspect.png" type="Texture2D" id=5]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSliderV2.gd" id="2"]
[ext_resource type="Texture2D" uid="uid://cancw70yw0pv7" path="res://assets/graphics/misc/lock_aspect_2.png" id="3"]
[ext_resource type="Texture2D" uid="uid://kd10jfc1dxf5" path="res://assets/graphics/misc/lock_aspect_guides.png" id="4"]
[ext_resource type="Texture2D" uid="uid://beqermx8s5q8y" path="res://assets/graphics/misc/lock_aspect.png" id="5"]
[node name="ValueSliderV2" type="HBoxContainer"]
offset_right = 45.0
offset_bottom = 52.0
script = ExtResource( 2 )
script = ExtResource("2")
[node name="GridContainer" type="GridContainer" parent="."]
offset_right = 45.0
offset_bottom = 52.0
layout_mode = 2
size_flags_horizontal = 3
[node name="X" type="TextureProgressBar" parent="GridContainer"]
offset_right = 45.0
offset_bottom = 24.0
custom_minimum_size = Vector2( 32, 24 )
mouse_default_cursor_shape = 2
custom_minimum_size = Vector2(32, 24)
layout_mode = 2
size_flags_horizontal = 3
theme_type_variation = "ValueSlider"
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource( 1 )
script = ExtResource("1")
prefix = "X:"
[node name="Y" type="TextureProgressBar" parent="GridContainer"]
offset_top = 28.0
offset_right = 45.0
offset_bottom = 52.0
custom_minimum_size = Vector2( 32, 24 )
mouse_default_cursor_shape = 2
custom_minimum_size = Vector2(32, 24)
layout_mode = 2
size_flags_horizontal = 3
theme_type_variation = "ValueSlider"
focus_mode = 2
mouse_default_cursor_shape = 2
theme_type_variation = &"ValueSlider"
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
stretch_margin_right = 3
stretch_margin_bottom = 3
script = ExtResource( 1 )
script = ExtResource("1")
prefix = "Y:"
[node name="Ratio" type="Control" parent="."]
visible = false
offset_left = 36.0
offset_right = 52.0
offset_bottom = 52.0
custom_minimum_size = Vector2( 16, 0 )
custom_minimum_size = Vector2(16, 0)
layout_mode = 2
[node name="RatioGuides" type="NinePatchRect" parent="Ratio" groups=["UIButtons"]]
custom_minimum_size = Vector2(9, 0)
layout_mode = 0
anchor_bottom = 1.0
offset_right = 9.0
custom_minimum_size = Vector2( 9, 0 )
texture = ExtResource( 4 )
region_rect = Rect2( 0, 0, 9, 44 )
texture = ExtResource("4")
region_rect = Rect2(0, 0, 9, 44)
patch_margin_top = 15
patch_margin_bottom = 13
[node name="RatioButton" type="TextureButton" parent="Ratio" groups=["UIButtons"]]
unique_name_in_owner = true
layout_mode = 0
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
@ -76,8 +74,8 @@ offset_bottom = 8.0
tooltip_text = "Lock aspect ratio"
mouse_default_cursor_shape = 2
toggle_mode = true
texture_normal = ExtResource( 3 )
texture_pressed = ExtResource( 5 )
texture_normal = ExtResource("3")
texture_pressed = ExtResource("5")
[connection signal="value_changed" from="GridContainer/X" to="." method="_on_X_value_changed"]
[connection signal="value_changed" from="GridContainer/Y" to="." method="_on_Y_value_changed"]

View file

@ -27,12 +27,14 @@ signal ratio_toggled(button_pressed: bool)
$GridContainer/X.min_value = val.x
$GridContainer/Y.min_value = val.y
$GridContainer/Z.min_value = val.z
value = value # Call value setter
@export var max_value := Vector3(100.0, 100.0, 100.0):
set(val):
max_value = val
$GridContainer/X.max_value = val.x
$GridContainer/Y.max_value = val.y
$GridContainer/Z.max_value = val.z
value = value # Call value setter
@export var step := 1.0:
set(val):
step = val
@ -54,8 +56,8 @@ signal ratio_toggled(button_pressed: bool)
$Ratio.visible = val
@export var grid_columns := 1:
set(val):
show_ratio = val
$Ratio.visible = val
grid_columns = val
$GridContainer.columns = val
@export var slider_min_size := Vector2(32, 24):
set(val):
slider_min_size = val

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=6 format=3 uid="uid://dpoteid430evf"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSliderV3.gd" id="2"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSliderV3.gd" id="2"]
[ext_resource type="Texture2D" uid="uid://cancw70yw0pv7" path="res://assets/graphics/misc/lock_aspect_2.png" id="3"]
[ext_resource type="Texture2D" uid="uid://kd10jfc1dxf5" path="res://assets/graphics/misc/lock_aspect_guides.png" id="4"]
[ext_resource type="Texture2D" uid="uid://beqermx8s5q8y" path="res://assets/graphics/misc/lock_aspect.png" id="5"]

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://collailpx6ft5"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="1"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="3"]
[node name="LineButton" type="VBoxContainer"]

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=6 format=3 uid="uid://calecly82t1aw"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="1"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="1"]
[ext_resource type="Script" path="res://src/UI/PerspectiveEditor/VanishingPoint.gd" id="2"]
[ext_resource type="Texture2D" uid="uid://ct8wn8m6x4m54" path="res://assets/graphics/misc/value_arrow.svg" id="4"]
[ext_resource type="Script" path="res://src/UI/PerspectiveEditor/PointCollapseContainer.gd" id="5"]

View file

@ -1,9 +1,9 @@
[gd_scene load_steps=13 format=3 uid="uid://cxhs8qy5ilufv"]
[ext_resource type="Script" path="res://src/UI/ReferenceImages/ReferencesPanel.gd" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="2_1qu4x"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="2_1qu4x"]
[ext_resource type="Texture2D" uid="uid://d1oxrkwndy5fi" path="res://assets/graphics/timeline/move_arrow.png" id="2_uqbp6"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="3_1w6gu"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3_1w6gu"]
[ext_resource type="Script" path="res://src/UI/ReferenceImages/ReferenceEdit.gd" id="3_skjtb"]
[ext_resource type="Texture2D" uid="uid://d2m7enib3dplc" path="res://assets/graphics/reference_images/select.png" id="3_us8st"]
[ext_resource type="Texture2D" uid="uid://cedsyi8gf2n2i" path="res://assets/graphics/reference_images/move.png" id="4_8mlcg"]

View file

@ -8,7 +8,7 @@
[ext_resource type="Texture2D" uid="uid://x2k652y15v04" path="res://assets/graphics/layers/delete.png" id="6"]
[ext_resource type="Texture2D" uid="uid://d3gx4phcox58s" path="res://assets/graphics/layers/clone.png" id="7"]
[ext_resource type="Texture2D" uid="uid://d1oxrkwndy5fi" path="res://assets/graphics/timeline/move_arrow.png" id="8"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="9"]
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="9"]
[ext_resource type="Texture2D" uid="uid://dt6cysvv1w77u" path="res://assets/graphics/layers/fx.png" id="9_yphnd"]
[ext_resource type="Texture2D" uid="uid://ct8wn8m6x4m54" path="res://assets/graphics/misc/value_arrow.svg" id="10"]
[ext_resource type="Script" path="res://src/UI/Timeline/FrameScrollContainer.gd" id="11"]
@ -22,7 +22,7 @@
[ext_resource type="Texture2D" uid="uid://l4jj86y1hukm" path="res://assets/graphics/timeline/go_to_last_frame.png" id="25"]
[ext_resource type="Texture2D" uid="uid://dhc0pnnqojd2m" path="res://assets/graphics/layers/unlock.png" id="25_7x5su"]
[ext_resource type="Texture2D" uid="uid://b2ndrc0cvy1m5" path="res://assets/graphics/timeline/next_frame.png" id="26"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="26_tfw1u"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="26_tfw1u"]
[ext_resource type="Texture2D" uid="uid://cerkv5yx4cqeh" path="res://assets/graphics/timeline/copy_frame.png" id="27"]
[ext_resource type="Texture2D" uid="uid://dndlglvqc7v6a" path="res://assets/graphics/layers/group_expanded.png" id="27_lrc8y"]
[ext_resource type="Texture2D" uid="uid://dukip7mvotxsp" path="res://assets/graphics/timeline/onion_skinning_off.png" id="29"]

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://clbjfkdupw52l"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="1_85pb7"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="1_85pb7"]
[ext_resource type="Script" path="res://src/UI/Timeline/CelProperties.gd" id="1_lyy7i"]
[node name="CelProperties" type="AcceptDialog"]

View file

@ -20,6 +20,7 @@ var effects: Array[LayerEffect] = [
"Adjust Brightness/Contrast",
preload("res://src/Shaders/Effects/BrightnessContrast.gdshader")
),
LayerEffect.new("Color Curves", preload("res://src/Shaders/Effects/ColorCurves.gdshader")),
LayerEffect.new("Palettize", preload("res://src/Shaders/Effects/Palettize.gdshader")),
LayerEffect.new("Pixelize", preload("res://src/Shaders/Effects/Pixelize.gdshader")),
LayerEffect.new("Posterize", preload("res://src/Shaders/Effects/Posterize.gdshader")),
@ -36,6 +37,11 @@ var effects: Array[LayerEffect] = [
func _ready() -> void:
for effect in effects:
effect_list.get_popup().add_item(effect.name)
if not DirAccess.dir_exists_absolute(OpenSave.SHADERS_DIRECTORY):
DirAccess.make_dir_recursive_absolute(OpenSave.SHADERS_DIRECTORY)
for file_name in DirAccess.get_files_at(OpenSave.SHADERS_DIRECTORY):
_load_shader_file(OpenSave.SHADERS_DIRECTORY.path_join(file_name))
OpenSave.shader_copied.connect(_load_shader_file)
effect_list.get_popup().id_pressed.connect(_on_effect_list_id_pressed)
@ -48,6 +54,7 @@ func _on_about_to_popup() -> void:
var layer := Global.current_project.layers[Global.current_project.current_layer]
enabled_button.button_pressed = layer.effects_enabled
for effect in layer.effects:
if is_instance_valid(effect.shader):
_create_effect_ui(layer, effect)
@ -58,6 +65,14 @@ func _on_visibility_changed() -> void:
child.queue_free()
func _load_shader_file(file_path: String) -> void:
var file := load(file_path)
if file is Shader:
var effect_name := file_path.get_file().get_basename()
effects.append(LayerEffect.new(effect_name, file))
effect_list.get_popup().add_item(effect_name)
func _on_effect_list_id_pressed(index: int) -> void:
var layer := Global.current_project.layers[Global.current_project.current_layer]
var effect := effects[index].duplicate()
@ -153,7 +168,8 @@ func _apply_effect(layer: BaseLayer, effect: LayerEffect) -> void:
var index := layer.effects.find(effect)
var redo_data := {}
var undo_data := {}
for frame in project.frames:
for i in project.frames.size():
var frame := project.frames[i]
var cel := frame.cels[layer.index]
var cel_image := cel.get_image()
if cel is CelTileMap:
@ -162,8 +178,12 @@ func _apply_effect(layer: BaseLayer, effect: LayerEffect) -> void:
undo_data[cel_image.indices_image] = cel_image.indices_image.data
undo_data[cel_image] = cel_image.data
var image_size := cel_image.get_size()
var params := effect.params
params["PXO_time"] = frame.position_in_seconds(project)
params["PXO_frame_index"] = i
params["PXO_layer_index"] = layer.index
var shader_image_effect := ShaderImageEffect.new()
shader_image_effect.generate_image(cel_image, effect.shader, effect.params, image_size)
shader_image_effect.generate_image(cel_image, effect.shader, params, image_size)
var tile_editing_mode := TileSetPanel.tile_editing_mode
if tile_editing_mode == TileSetPanel.TileEditingMode.MANUAL:

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://d3dt1gdlf7hox"]
[ext_resource type="Script" path="res://src/UI/Timeline/LayerProperties.gd" id="1_54q1t"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="2_bwpwc"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="2_bwpwc"]
[node name="LayerProperties" type="AcceptDialog"]
title = "Layer properties"

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://hbgwxlin4jun"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="1_uvdem"]
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="1_uvdem"]
[ext_resource type="Script" path="res://src/UI/Timeline/NewTileMapLayerDialog.gd" id="1_y2r5h"]
[node name="NewTileMapLayerDialog" type="ConfirmationDialog"]

View file

@ -14,6 +14,7 @@ const HEART_ICON := preload("res://assets/graphics/misc/heart.svg")
var recent_projects := []
var selected_layout := 0
var zen_mode := false
var loaded_effects_submenu: PopupMenu
# Dialogs
var new_image_dialog := Dialog.new("res://src/UI/Dialogs/CreateNewImage.tscn")
@ -33,13 +34,14 @@ var hsv_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/HSVDialog.tscn")
var adjust_brightness_saturation_dialog := Dialog.new(
"res://src/UI/Dialogs/ImageEffects/BrightnessContrastDialog.tscn"
)
var color_curves_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/ColorCurvesDialog.tscn")
var gaussian_blur_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GaussianBlur.tscn")
var gradient_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GradientDialog.tscn")
var gradient_map_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GradientMapDialog.tscn")
var palettize_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/PalettizeDialog.tscn")
var pixelize_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/PixelizeDialog.tscn")
var posterize_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/Posterize.tscn")
var shader_effect_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/ShaderEffect.tscn")
var loaded_effect_dialogs: Array[Dialog] = []
var manage_layouts_dialog := Dialog.new("res://src/UI/Dialogs/ManageLayouts.tscn")
var window_opacity_dialog := Dialog.new("res://src/UI/Dialogs/WindowOpacityDialog.tscn")
var about_dialog := Dialog.new("res://src/UI/Dialogs/AboutDialog.tscn")
@ -78,21 +80,24 @@ class Dialog:
func popup(dialog_size := Vector2i.ZERO) -> void:
if not is_instance_valid(node):
instantiate_scene()
node.popup_centered(dialog_size)
var is_file_dialog := node is FileDialog
Global.dialog_open(true, is_file_dialog)
func instantiate_scene() -> void:
var scene := load(scene_path)
if not scene is PackedScene:
return
node = scene.instantiate()
if not is_instance_valid(node):
return
if is_instance_valid(node):
Global.control.get_node("Dialogs").add_child(node)
node.popup_centered(dialog_size)
var is_file_dialog := node is FileDialog
Global.dialog_open(true, is_file_dialog)
func _ready() -> void:
Global.project_switched.connect(_project_switched)
Global.cel_switched.connect(_update_current_frame_mark)
OpenSave.shader_copied.connect(_load_shader_file)
_setup_file_menu()
_setup_edit_menu()
_setup_view_menu()
@ -449,33 +454,64 @@ func _setup_effects_menu() -> void:
"Desaturation": "desaturation",
"Adjust Hue/Saturation/Value": "adjust_hsv",
"Adjust Brightness/Contrast": "adjust_brightness_contrast",
"Color Curves": "color_curves",
"Palettize": "palettize",
"Pixelize": "pixelize",
"Posterize": "posterize",
"Gaussian Blur": "gaussian_blur",
"Gradient": "gradient",
"Gradient Map": "gradient_map",
# "Shader": ""
"Loaded": ""
}
var i := 0
for item in menu_items:
if item == "Loaded":
_setup_loaded_effects_submenu()
else:
_set_menu_shortcut(menu_items[item], effects_menu, i, item)
i += 1
effects_menu.id_pressed.connect(effects_menu_id_pressed)
func _setup_loaded_effects_submenu() -> void:
if not DirAccess.dir_exists_absolute(OpenSave.SHADERS_DIRECTORY):
DirAccess.make_dir_recursive_absolute(OpenSave.SHADERS_DIRECTORY)
var shader_files := DirAccess.get_files_at(OpenSave.SHADERS_DIRECTORY)
if shader_files.size() == 0:
return
for shader_file in shader_files:
_load_shader_file(OpenSave.SHADERS_DIRECTORY.path_join(shader_file))
func _load_shader_file(file_path: String) -> void:
var file := load(file_path)
if file is not Shader:
return
var effect_name := file_path.get_file().get_basename()
if not is_instance_valid(loaded_effects_submenu):
loaded_effects_submenu = PopupMenu.new()
loaded_effects_submenu.set_name("loaded_effects_submenu")
loaded_effects_submenu.id_pressed.connect(_loaded_effects_submenu_id_pressed)
effects_menu.add_child(loaded_effects_submenu)
effects_menu.add_submenu_item("Loaded", loaded_effects_submenu.get_name())
loaded_effects_submenu.add_item(effect_name)
var effect_index := loaded_effects_submenu.item_count - 1
loaded_effects_submenu.set_item_metadata(effect_index, file)
loaded_effect_dialogs.append(Dialog.new("res://src/UI/Dialogs/ImageEffects/ShaderEffect.tscn"))
func _setup_select_menu() -> void:
# Order as in Global.SelectMenu enum
var select_menu_items := {
"All": "select_all",
"Clear": "clear_selection",
"Invert": "invert_selection",
"Tile Mode": "",
"Wrap Strokes": "",
"Modify": ""
}
for i in select_menu_items.size():
var item: String = select_menu_items.keys()[i]
if item == "Tile Mode":
if item == "Wrap Strokes":
select_menu.add_check_item(item, i)
elif item == "Modify":
_setup_selection_modify_submenu(item)
@ -768,6 +804,17 @@ func _snap_to_submenu_id_pressed(id: int) -> void:
snap_to_submenu.set_item_checked(id, Global.snap_to_perspective_guides)
func _loaded_effects_submenu_id_pressed(id: int) -> void:
var dialog := loaded_effect_dialogs[id]
if is_instance_valid(dialog.node):
dialog.popup()
else:
dialog.instantiate_scene()
var shader := loaded_effects_submenu.get_item_metadata(id) as Shader
dialog.node.change_shader(shader, loaded_effects_submenu.get_item_text(id))
dialog.popup()
func _panels_submenu_id_pressed(id: int) -> void:
if zen_mode:
return
@ -934,6 +981,8 @@ func effects_menu_id_pressed(id: int) -> void:
hsv_dialog.popup()
Global.EffectsMenu.BRIGHTNESS_SATURATION:
adjust_brightness_saturation_dialog.popup()
Global.EffectsMenu.COLOR_CURVES:
color_curves_dialog.popup()
Global.EffectsMenu.GAUSSIAN_BLUR:
gaussian_blur_dialog.popup()
Global.EffectsMenu.GRADIENT:
@ -946,8 +995,6 @@ func effects_menu_id_pressed(id: int) -> void:
pixelize_dialog.popup()
Global.EffectsMenu.POSTERIZE:
posterize_dialog.popup()
#Global.EffectsMenu.SHADER:
#shader_effect_dialog.popup()
_:
_handle_metadata(id, effects_menu)
@ -960,7 +1007,7 @@ func select_menu_id_pressed(id: int) -> void:
Global.canvas.selection.clear_selection(true)
Global.SelectMenu.INVERT:
Global.canvas.selection.invert()
Global.SelectMenu.TILE_MODE:
Global.SelectMenu.WRAP_STROKES:
var state = select_menu.is_item_checked(id)
Global.canvas.selection.flag_tilemode = !state
select_menu.set_item_checked(id, !state)

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://bsgwar3l6qtgv"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="1"]
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="1"]
[ext_resource type="Script" path="res://src/UI/TopMenuContainer/TopMenuContainer.gd" id="2"]
[node name="TopMenuContainer" type="Panel"]