mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-31 07:29:49 +00:00
Add a transform
method to DrawingAlgos
Can be used as a general method to apply rotation and skewing. It does not handle scaling though, and I am not sure if it should.
This commit is contained in:
parent
0809dc2dcf
commit
e40d507a6a
|
@ -1,5 +1,6 @@
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
|
enum RotationAlgorithm { ROTXEL_SMEAR, CLEANEDGE, OMNISCALE, NNS, NN, ROTXEL, URD }
|
||||||
enum GradientDirection { TOP, BOTTOM, LEFT, RIGHT }
|
enum GradientDirection { TOP, BOTTOM, LEFT, RIGHT }
|
||||||
## Continuation from Image.Interpolation
|
## Continuation from Image.Interpolation
|
||||||
enum Interpolation { SCALE3X = 5, CLEANEDGE = 6, OMNISCALE = 7 }
|
enum Interpolation { SCALE3X = 5, CLEANEDGE = 6, OMNISCALE = 7 }
|
||||||
|
@ -14,6 +15,8 @@ var omniscale_shader: Shader:
|
||||||
if omniscale_shader == null:
|
if omniscale_shader == null:
|
||||||
omniscale_shader = load("res://src/Shaders/Effects/Rotation/OmniScale.gdshader")
|
omniscale_shader = load("res://src/Shaders/Effects/Rotation/OmniScale.gdshader")
|
||||||
return omniscale_shader
|
return omniscale_shader
|
||||||
|
var rotxel_shader := preload("res://src/Shaders/Effects/Rotation/SmearRotxel.gdshader")
|
||||||
|
var nn_shader := preload("res://src/Shaders/Effects/Rotation/NearestNeighbour.gdshader")
|
||||||
|
|
||||||
|
|
||||||
## Blends canvas layers into passed image starting from the origin position
|
## Blends canvas layers into passed image starting from the origin position
|
||||||
|
@ -270,6 +273,41 @@ func scale_3x(sprite: Image, tol := 0.196078) -> Image:
|
||||||
return scaled
|
return scaled
|
||||||
|
|
||||||
|
|
||||||
|
func transform(
|
||||||
|
image: Image,
|
||||||
|
params: Dictionary,
|
||||||
|
algorithm: RotationAlgorithm,
|
||||||
|
project := Global.current_project
|
||||||
|
) -> void:
|
||||||
|
var pivot: Vector2 = params.get("pivot", image.get_size() / 2)
|
||||||
|
if type_is_shader(algorithm):
|
||||||
|
params["pivot"] = pivot / Vector2(image.get_size())
|
||||||
|
var shader := rotxel_shader
|
||||||
|
match algorithm:
|
||||||
|
RotationAlgorithm.CLEANEDGE:
|
||||||
|
shader = clean_edge_shader
|
||||||
|
RotationAlgorithm.OMNISCALE:
|
||||||
|
shader = omniscale_shader
|
||||||
|
RotationAlgorithm.NNS:
|
||||||
|
shader = nn_shader
|
||||||
|
var gen := ShaderImageEffect.new()
|
||||||
|
gen.generate_image(image, shader, params, project.size)
|
||||||
|
else:
|
||||||
|
var transformation_matrix: Transform2D = params.get("transformation_matrix", Transform2D())
|
||||||
|
var angle := transformation_matrix.get_rotation()
|
||||||
|
match algorithm:
|
||||||
|
RotationAlgorithm.ROTXEL:
|
||||||
|
rotxel(image, angle, pivot)
|
||||||
|
RotationAlgorithm.NN:
|
||||||
|
nn_rotate(image, angle, pivot)
|
||||||
|
RotationAlgorithm.URD:
|
||||||
|
fake_rotsprite(image, angle, pivot)
|
||||||
|
|
||||||
|
|
||||||
|
func type_is_shader(algorithm: RotationAlgorithm) -> bool:
|
||||||
|
return algorithm <= RotationAlgorithm.NNS
|
||||||
|
|
||||||
|
|
||||||
func rotxel(sprite: Image, angle: float, pivot: Vector2) -> void:
|
func rotxel(sprite: Image, angle: float, pivot: Vector2) -> void:
|
||||||
if is_zero_approx(angle) or is_equal_approx(angle, TAU):
|
if is_zero_approx(angle) or is_equal_approx(angle, TAU):
|
||||||
return
|
return
|
||||||
|
|
|
@ -46,6 +46,7 @@ var undo_data: Dictionary
|
||||||
var gizmos: Array[Gizmo] = []
|
var gizmos: Array[Gizmo] = []
|
||||||
var dragged_gizmo: Gizmo = null
|
var dragged_gizmo: Gizmo = null
|
||||||
var angle := 0.0
|
var angle := 0.0
|
||||||
|
var rotation_algorithm := DrawingAlgos.RotationAlgorithm.NN
|
||||||
var content_pivot := Vector2.ZERO
|
var content_pivot := Vector2.ZERO
|
||||||
var mouse_pos_on_gizmo_drag := Vector2.ZERO
|
var mouse_pos_on_gizmo_drag := Vector2.ZERO
|
||||||
var resize_keep_ratio := false
|
var resize_keep_ratio := false
|
||||||
|
@ -405,7 +406,9 @@ func resize_selection() -> void:
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
content_pivot = original_big_bounding_rectangle.size / 2.0
|
content_pivot = original_big_bounding_rectangle.size / 2.0
|
||||||
DrawingAlgos.nn_rotate(preview_image, angle, content_pivot)
|
var transformation_matrix := Transform2D(angle, Vector2.ZERO)
|
||||||
|
var params := {"transformation_matrix": transformation_matrix, "pivot": content_pivot}
|
||||||
|
DrawingAlgos.transform(preview_image, params, rotation_algorithm)
|
||||||
preview_image.resize(size.x, size.y, Image.INTERPOLATE_NEAREST)
|
preview_image.resize(size.x, size.y, Image.INTERPOLATE_NEAREST)
|
||||||
if temp_rect.size.x < 0:
|
if temp_rect.size.x < 0:
|
||||||
preview_image.flip_x()
|
preview_image.flip_x()
|
||||||
|
@ -416,7 +419,9 @@ func resize_selection() -> void:
|
||||||
Global.current_project.selection_map.copy_from(original_bitmap)
|
Global.current_project.selection_map.copy_from(original_bitmap)
|
||||||
|
|
||||||
var bitmap_pivot := original_big_bounding_rectangle.get_center()
|
var bitmap_pivot := original_big_bounding_rectangle.get_center()
|
||||||
DrawingAlgos.nn_rotate(Global.current_project.selection_map, angle, bitmap_pivot)
|
var bitmap_matrix := Transform2D(angle, Vector2.ZERO)
|
||||||
|
var bitmap_params := {"transformation_matrix": bitmap_matrix, "pivot": bitmap_pivot}
|
||||||
|
DrawingAlgos.transform(Global.current_project.selection_map, bitmap_params, rotation_algorithm)
|
||||||
Global.current_project.selection_map.resize_bitmap_values(
|
Global.current_project.selection_map.resize_bitmap_values(
|
||||||
Global.current_project, size, temp_rect.size.x < 0, temp_rect.size.y < 0
|
Global.current_project, size, temp_rect.size.x < 0, temp_rect.size.y < 0
|
||||||
)
|
)
|
||||||
|
@ -552,7 +557,11 @@ func transform_content_confirm() -> void:
|
||||||
src.crop(preview_image.get_width(), preview_image.get_height())
|
src.crop(preview_image.get_width(), preview_image.get_height())
|
||||||
tilemap.apply_resizing_to_image(src, selected_cells, big_bounding_rectangle)
|
tilemap.apply_resizing_to_image(src, selected_cells, big_bounding_rectangle)
|
||||||
else:
|
else:
|
||||||
DrawingAlgos.nn_rotate(src, angle, content_pivot)
|
var transformation_matrix := Transform2D(angle, Vector2.ZERO)
|
||||||
|
var params := {
|
||||||
|
"transformation_matrix": transformation_matrix, "pivot": content_pivot
|
||||||
|
}
|
||||||
|
DrawingAlgos.transform(src, params, rotation_algorithm)
|
||||||
src.resize(
|
src.resize(
|
||||||
preview_image.get_width(), preview_image.get_height(), Image.INTERPOLATE_NEAREST
|
preview_image.get_width(), preview_image.get_height(), Image.INTERPOLATE_NEAREST
|
||||||
)
|
)
|
||||||
|
|
|
@ -80,7 +80,7 @@ func _calculate_pivot() -> void:
|
||||||
func commit_action(cel: Image, project := Global.current_project) -> void:
|
func commit_action(cel: Image, project := Global.current_project) -> void:
|
||||||
var angle := deg_to_rad(animate_panel.get_animated_value(commit_idx, Animate.ANGLE))
|
var angle := deg_to_rad(animate_panel.get_animated_value(commit_idx, Animate.ANGLE))
|
||||||
var init_angle := deg_to_rad(animate_panel.get_animated_value(commit_idx, Animate.INIT_ANGLE))
|
var init_angle := deg_to_rad(animate_panel.get_animated_value(commit_idx, Animate.INIT_ANGLE))
|
||||||
|
var rotation_algorithm := type_option_button.get_selected_id()
|
||||||
var selection_tex: ImageTexture
|
var selection_tex: ImageTexture
|
||||||
var image := Image.new()
|
var image := Image.new()
|
||||||
image.copy_from(cel)
|
image.copy_from(cel)
|
||||||
|
@ -88,7 +88,7 @@ func commit_action(cel: Image, project := Global.current_project) -> void:
|
||||||
var selection := project.selection_map.return_cropped_copy(project.size)
|
var selection := project.selection_map.return_cropped_copy(project.size)
|
||||||
selection_tex = ImageTexture.create_from_image(selection)
|
selection_tex = ImageTexture.create_from_image(selection)
|
||||||
|
|
||||||
if !_type_is_shader():
|
if not DrawingAlgos.type_is_shader(rotation_algorithm):
|
||||||
var blank := project.new_empty_image()
|
var blank := project.new_empty_image()
|
||||||
cel.blit_rect_mask(
|
cel.blit_rect_mask(
|
||||||
blank, selection, Rect2i(Vector2i.ZERO, cel.get_size()), Vector2i.ZERO
|
blank, selection, Rect2i(Vector2i.ZERO, cel.get_size()), Vector2i.ZERO
|
||||||
|
@ -97,41 +97,26 @@ func commit_action(cel: Image, project := Global.current_project) -> void:
|
||||||
image.blit_rect_mask(
|
image.blit_rect_mask(
|
||||||
blank, selection, Rect2i(Vector2i.ZERO, image.get_size()), Vector2i.ZERO
|
blank, selection, Rect2i(Vector2i.ZERO, image.get_size()), Vector2i.ZERO
|
||||||
)
|
)
|
||||||
if _type_is_shader():
|
var transformation_matrix := Transform2D(angle, Vector2.ZERO)
|
||||||
var shader := rotxel_shader
|
|
||||||
var params := {
|
var params := {
|
||||||
"transformation_matrix": Transform2D(angle, Vector2.ZERO),
|
"transformation_matrix": transformation_matrix,
|
||||||
|
"pivot": pivot,
|
||||||
"selection_tex": selection_tex,
|
"selection_tex": selection_tex,
|
||||||
"pivot": pivot / Vector2(cel.get_size()),
|
"initial_angle": init_angle,
|
||||||
|
"ending_angle": angle,
|
||||||
|
"tolerance": tolerance_slider.value,
|
||||||
"preview": true
|
"preview": true
|
||||||
}
|
}
|
||||||
match type_option_button.get_selected_id():
|
if DrawingAlgos.type_is_shader(rotation_algorithm):
|
||||||
ROTXEL_SMEAR:
|
|
||||||
params["ending_angle"] = angle
|
|
||||||
params["initial_angle"] = init_angle
|
|
||||||
params["tolerance"] = tolerance_slider.value
|
|
||||||
CLEANEDGE:
|
|
||||||
shader = DrawingAlgos.clean_edge_shader
|
|
||||||
OMNISCALE:
|
|
||||||
shader = DrawingAlgos.omniscale_shader
|
|
||||||
NNS:
|
|
||||||
shader = nn_shader
|
|
||||||
if !has_been_confirmed:
|
if !has_been_confirmed:
|
||||||
|
params["pivot"] /= Vector2(cel.get_size())
|
||||||
for param in params:
|
for param in params:
|
||||||
preview.material.set_shader_parameter(param, params[param])
|
preview.material.set_shader_parameter(param, params[param])
|
||||||
else:
|
else:
|
||||||
params["preview"] = false
|
params["preview"] = false
|
||||||
var gen := ShaderImageEffect.new()
|
DrawingAlgos.transform(cel, params, rotation_algorithm, project)
|
||||||
gen.generate_image(cel, shader, params, project.size)
|
|
||||||
else:
|
else:
|
||||||
match type_option_button.get_selected_id():
|
DrawingAlgos.transform(image, params, rotation_algorithm, project)
|
||||||
ROTXEL:
|
|
||||||
DrawingAlgos.rotxel(image, angle, pivot)
|
|
||||||
NN:
|
|
||||||
DrawingAlgos.nn_rotate(image, angle, pivot)
|
|
||||||
URD:
|
|
||||||
DrawingAlgos.fake_rotsprite(image, angle, pivot)
|
|
||||||
|
|
||||||
if project.has_selection and selection_checkbox.button_pressed:
|
if project.has_selection and selection_checkbox.button_pressed:
|
||||||
cel.blend_rect(image, Rect2i(Vector2i.ZERO, image.get_size()), Vector2i.ZERO)
|
cel.blend_rect(image, Rect2i(Vector2i.ZERO, image.get_size()), Vector2i.ZERO)
|
||||||
else:
|
else:
|
||||||
|
@ -140,10 +125,6 @@ func commit_action(cel: Image, project := Global.current_project) -> void:
|
||||||
cel.convert_rgb_to_indexed()
|
cel.convert_rgb_to_indexed()
|
||||||
|
|
||||||
|
|
||||||
func _type_is_shader() -> bool:
|
|
||||||
return type_option_button.get_selected_id() <= NNS
|
|
||||||
|
|
||||||
|
|
||||||
func _on_TypeOptionButton_item_selected(_id: int) -> void:
|
func _on_TypeOptionButton_item_selected(_id: int) -> void:
|
||||||
match type_option_button.get_selected_id():
|
match type_option_button.get_selected_id():
|
||||||
ROTXEL_SMEAR:
|
ROTXEL_SMEAR:
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/RotateImage.gd" id="1"]
|
[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://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="2"]
|
||||||
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="3"]
|
[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"]
|
[ext_resource type="PackedScene" uid="uid://bbnqcxa20a5a5" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="4"]
|
||||||
|
|
||||||
[node name="RotateImage" instance=ExtResource("2")]
|
[node name="RotateImage" instance=ExtResource("2")]
|
||||||
title = "Rotate Image"
|
title = "Rotate Image"
|
||||||
|
|
Loading…
Reference in a new issue