1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-31 07:29:49 +00:00

Layer Opacity - Change alpha of each layer

Added a slider under the layer add/remove/etc buttons that changes the currently selected layer's transparency. It gets saved in .png and .pxo files, while respecting non-opaque pixels in the image too. Which means, their alpha values aren't being overwritten.
This commit is contained in:
OverloadedOrama 2019-12-24 23:51:08 +02:00
parent aa860960e2
commit ed2e757c11
7 changed files with 77 additions and 35 deletions

View file

@ -158,12 +158,14 @@ anchor_bottom = 1.0
custom_constants/separation = 0 custom_constants/separation = 0
[node name="TopMenuContainer" type="Panel" parent="MenuAndUI"] [node name="TopMenuContainer" type="Panel" parent="MenuAndUI"]
editor/display_folded = true
margin_right = 1152.0 margin_right = 1152.0
margin_bottom = 28.0 margin_bottom = 28.0
rect_min_size = Vector2( 0, 28 ) rect_min_size = Vector2( 0, 28 )
custom_styles/panel = ExtResource( 3 ) custom_styles/panel = ExtResource( 3 )
[node name="MenuItems" type="HBoxContainer" parent="MenuAndUI/TopMenuContainer"] [node name="MenuItems" type="HBoxContainer" parent="MenuAndUI/TopMenuContainer"]
editor/display_folded = true
margin_left = 2.0 margin_left = 2.0
margin_top = 4.0 margin_top = 4.0
margin_right = 1010.0 margin_right = 1010.0
@ -233,7 +235,6 @@ text = "[64×64]"
align = 2 align = 2
[node name="UI" type="HBoxContainer" parent="MenuAndUI"] [node name="UI" type="HBoxContainer" parent="MenuAndUI"]
editor/display_folded = true
margin_top = 28.0 margin_top = 28.0
margin_right = 1152.0 margin_right = 1152.0
margin_bottom = 648.0 margin_bottom = 648.0
@ -1326,7 +1327,6 @@ margin_right = 224.0
margin_bottom = 419.0 margin_bottom = 419.0
[node name="LayerVBoxContainer" type="VBoxContainer" parent="MenuAndUI/UI/LayerPanel/LayersAndMisc"] [node name="LayerVBoxContainer" type="VBoxContainer" parent="MenuAndUI/UI/LayerPanel/LayersAndMisc"]
editor/display_folded = true
margin_top = 423.0 margin_top = 423.0
margin_right = 224.0 margin_right = 224.0
margin_bottom = 604.0 margin_bottom = 604.0
@ -1417,9 +1417,16 @@ texture_normal = ExtResource( 55 )
texture_hover = ExtResource( 56 ) texture_hover = ExtResource( 56 )
texture_disabled = ExtResource( 57 ) texture_disabled = ExtResource( 57 )
[node name="OpacitySlider" type="HSlider" parent="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer"]
margin_top = 38.0
margin_right = 224.0
margin_bottom = 44.0
value = 100.0
ticks_on_borders = false
[node name="ScrollLayers" type="ScrollContainer" parent="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer"] [node name="ScrollLayers" type="ScrollContainer" parent="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer"]
editor/display_folded = true editor/display_folded = true
margin_top = 38.0 margin_top = 50.0
margin_right = 224.0 margin_right = 224.0
margin_bottom = 181.0 margin_bottom = 181.0
size_flags_horizontal = 3 size_flags_horizontal = 3
@ -1688,9 +1695,9 @@ anchor_top = 0.5
anchor_right = 0.5 anchor_right = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
margin_left = -92.0 margin_left = -92.0
margin_top = -36.0 margin_top = -27.0
margin_right = 92.0 margin_right = 92.0
margin_bottom = 5.0 margin_bottom = -4.0
custom_constants/vseparation = 4 custom_constants/vseparation = 4
custom_constants/hseparation = 4 custom_constants/hseparation = 4
columns = 2 columns = 2
@ -1871,6 +1878,7 @@ visible = false
[connection signal="pressed" from="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer/CenterLayerButtons/LayerButtons/MovwDownLayer" to="." method="change_layer_order" binds= [ -1 ]] [connection signal="pressed" from="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer/CenterLayerButtons/LayerButtons/MovwDownLayer" to="." method="change_layer_order" binds= [ -1 ]]
[connection signal="pressed" from="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer/CenterLayerButtons/LayerButtons/CloneLayer" to="." method="add_layer" binds= [ false ]] [connection signal="pressed" from="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer/CenterLayerButtons/LayerButtons/CloneLayer" to="." method="add_layer" binds= [ false ]]
[connection signal="pressed" from="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer/CenterLayerButtons/LayerButtons/MergeDownLayer" to="." method="_on_MergeLayer_pressed"] [connection signal="pressed" from="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer/CenterLayerButtons/LayerButtons/MergeDownLayer" to="." method="_on_MergeLayer_pressed"]
[connection signal="value_changed" from="MenuAndUI/UI/LayerPanel/LayersAndMisc/LayerVBoxContainer/OpacitySlider" to="." method="_on_OpacitySlider_value_changed"]
[connection signal="toggled" from="SplitScreenButton" to="." method="_on_SplitScreenButton_toggled"] [connection signal="toggled" from="SplitScreenButton" to="." method="_on_SplitScreenButton_toggled"]
[connection signal="confirmed" from="CreateNewImage" to="." method="_on_CreateNewImage_confirmed"] [connection signal="confirmed" from="CreateNewImage" to="." method="_on_CreateNewImage_confirmed"]
[connection signal="popup_hide" from="CreateNewImage" to="." method="_can_draw_true"] [connection signal="popup_hide" from="CreateNewImage" to="." method="_can_draw_true"]

View file

@ -36,8 +36,8 @@ func _ready() -> void:
var tex := ImageTexture.new() var tex := ImageTexture.new()
tex.create_from_image(sprite, 0) tex.create_from_image(sprite, 0)
#Store [Image, ImageTexture, Layer Name, Visibity boolean] #Store [Image, ImageTexture, Layer Name, Visibity boolean, Opacity]
layers.append([sprite, tex, "Layer 0", true]) layers.append([sprite, tex, "Layer 0", true, 1])
generate_layer_panels() generate_layer_panels()
@ -407,18 +407,19 @@ func _draw() -> void:
#Draw current frame layers #Draw current frame layers
for texture in layers: for texture in layers:
var modulate_color := Color(1, 1, 1, texture[4])
if texture[3]: #if it's visible if texture[3]: #if it's visible
draw_texture(texture[1], location) draw_texture(texture[1], location, modulate_color)
if Global.tile_mode: if Global.tile_mode:
draw_texture(texture[1], Vector2(location.x, location.y + size.y)) #Down draw_texture(texture[1], Vector2(location.x, location.y + size.y), modulate_color) #Down
draw_texture(texture[1], Vector2(location.x - size.x, location.y + size.y)) #Down Left draw_texture(texture[1], Vector2(location.x - size.x, location.y + size.y), modulate_color) #Down Left
draw_texture(texture[1], Vector2(location.x - size.x, location.y)) #Left draw_texture(texture[1], Vector2(location.x - size.x, location.y), modulate_color) #Left
draw_texture(texture[1], location - size) #Up left draw_texture(texture[1], location - size, modulate_color) #Up left
draw_texture(texture[1], Vector2(location.x, location.y - size.y)) #Up draw_texture(texture[1], Vector2(location.x, location.y - size.y), modulate_color) #Up
draw_texture(texture[1], Vector2(location.x + size.x, location.y - size.y)) #Up right draw_texture(texture[1], Vector2(location.x + size.x, location.y - size.y), modulate_color) #Up right
draw_texture(texture[1], Vector2(location.x + size.x, location.y)) #Right draw_texture(texture[1], Vector2(location.x + size.x, location.y), modulate_color) #Right
draw_texture(texture[1], location + size) #Down right draw_texture(texture[1], location + size, modulate_color) #Down right
#Idea taken from flurick (on GitHub) #Idea taken from flurick (on GitHub)
if Global.draw_grid: if Global.draw_grid:
@ -476,7 +477,7 @@ func generate_layer_panels() -> void:
layer_container.get_child(1).get_child(0).texture = layers[i][1] layer_container.get_child(1).get_child(0).texture = layers[i][1]
layer_container.get_child(1).get_child(1).text = layers[i][2] layer_container.get_child(1).get_child(1).text = layers[i][2]
layer_container.get_child(1).get_child(2).text = layers[i][2] layer_container.get_child(1).get_child(2).text = layers[i][2]
layers[i][3] = true #set visible layers[i][3] = true # Set visible
Global.vbox_layer_container.add_child(layer_container) Global.vbox_layer_container.add_child(layer_container)
func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void: func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void:

View file

@ -46,7 +46,7 @@ func _on_PopupMenu_id_pressed(ID : int) -> void:
sprite.lock() sprite.lock()
var tex := ImageTexture.new() var tex := ImageTexture.new()
tex.create_from_image(sprite, 0) tex.create_from_image(sprite, 0)
new_canvas.layers.append([sprite, tex, layer[2], layer[3]]) new_canvas.layers.append([sprite, tex, layer[2], layer[3], layer[4]])
Global.undos += 1 Global.undos += 1
Global.undo_redo.create_action("Add Frame") Global.undo_redo.create_action("Add Frame")

View file

@ -189,6 +189,7 @@ var remove_layer_button : BaseButton
var move_up_layer_button : BaseButton var move_up_layer_button : BaseButton
var move_down_layer_button : BaseButton var move_down_layer_button : BaseButton
var merge_down_layer_button : BaseButton var merge_down_layer_button : BaseButton
var layer_opacity_slider : HSlider
var add_palette_button : TextureButton var add_palette_button : TextureButton
var remove_palette_button : TextureButton var remove_palette_button : TextureButton
@ -285,12 +286,15 @@ func _ready() -> void:
play_backwards = find_node_by_name(root, "PlayBackwards") play_backwards = find_node_by_name(root, "PlayBackwards")
frame_container = find_node_by_name(root, "FrameContainer") frame_container = find_node_by_name(root, "FrameContainer")
var layer_buttons = find_node_by_name(root, "LayerButtons") var layer_stuff_container = find_node_by_name(root, "LayerVBoxContainer")
var layer_buttons = find_node_by_name(layer_stuff_container, "LayerButtons")
remove_layer_button = find_node_by_name(layer_buttons, "RemoveLayer") remove_layer_button = find_node_by_name(layer_buttons, "RemoveLayer")
move_up_layer_button = find_node_by_name(layer_buttons, "MoveUpLayer") move_up_layer_button = find_node_by_name(layer_buttons, "MoveUpLayer")
move_down_layer_button = find_node_by_name(layer_buttons, "MovwDownLayer") move_down_layer_button = find_node_by_name(layer_buttons, "MovwDownLayer")
merge_down_layer_button = find_node_by_name(layer_buttons, "MergeDownLayer") merge_down_layer_button = find_node_by_name(layer_buttons, "MergeDownLayer")
vbox_layer_container = find_node_by_name(root, "VBoxLayerContainer")
layer_opacity_slider = find_node_by_name(layer_stuff_container, "OpacitySlider")
vbox_layer_container = find_node_by_name(layer_stuff_container, "VBoxLayerContainer")
add_palette_button = find_node_by_name(root, "AddPalette") add_palette_button = find_node_by_name(root, "AddPalette")
remove_palette_button = find_node_by_name(root, "RemovePalette") remove_palette_button = find_node_by_name(root, "RemovePalette")

View file

@ -43,9 +43,10 @@ func changed_selection() -> void:
child.label.visible = true child.label.visible = true
child.line_edit.visible = false child.line_edit.visible = false
child.line_edit.editable = false child.line_edit.editable = false
if Global.canvas.current_layer_index == child.i: if Global.canvas.current_layer_index == child.i: # The selected layer
child.currently_selected = true child.currently_selected = true
child.pressed = true child.pressed = true
Global.layer_opacity_slider.value = Global.canvas.layers[child.i][4] * 100
if Global.canvas.current_layer_index < Global.canvas.layers.size() - 1: if Global.canvas.current_layer_index < Global.canvas.layers.size() - 1:
Global.move_up_layer_button.disabled = false Global.move_up_layer_button.disabled = false

View file

@ -387,8 +387,10 @@ func _on_OpenSprite_file_selected(path : String) -> void:
return return
var current_version : String = ProjectSettings.get_setting("application/config/Version") var current_version : String = ProjectSettings.get_setting("application/config/Version")
var current_version_number = float(current_version.substr(1, 3)) # Example, "0.6"
var version := file.get_line() var version := file.get_line()
if current_version != version: var version_number = float(version.substr(1, 3)) # Example, "0.6"
if current_version_number < 0.5:
OS.alert("File is from an older version of Pixelorama, as such it might not work properly") OS.alert("File is from an older version of Pixelorama, as such it might not work properly")
var frame := 0 var frame := 0
var frame_line := file.get_line() var frame_line := file.get_line()
@ -403,12 +405,15 @@ func _on_OpenSprite_file_selected(path : String) -> void:
while layer_line == "-": #Load layers while layer_line == "-": #Load layers
var buffer := file.get_buffer(width * height * 4) var buffer := file.get_buffer(width * height * 4)
var layer_name := file.get_line() var layer_name := file.get_line()
var layer_transparency := 1.0
if version_number > 0.5:
layer_transparency = file.get_float()
var image := Image.new() var image := Image.new()
image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer) image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer)
image.lock() image.lock()
var tex := ImageTexture.new() var tex := ImageTexture.new()
tex.create_from_image(image, 0) tex.create_from_image(image, 0)
canvas.layers.append([image, tex, layer_name, true]) canvas.layers.append([image, tex, layer_name, true, layer_transparency])
layer_line = file.get_line() layer_line = file.get_line()
var guide_line := file.get_line() #"guideline" no pun intended var guide_line := file.get_line() #"guideline" no pun intended
@ -475,14 +480,15 @@ func _on_SaveSprite_file_selected(path) -> void:
var err := file.open(path, File.WRITE) var err := file.open(path, File.WRITE)
if err == 0: if err == 0:
file.store_line(ProjectSettings.get_setting("application/config/Version")) file.store_line(ProjectSettings.get_setting("application/config/Version"))
for canvas in Global.canvases: #Store frames for canvas in Global.canvases: # Store frames
file.store_line("--") file.store_line("--")
file.store_16(canvas.size.x) file.store_16(canvas.size.x)
file.store_16(canvas.size.y) file.store_16(canvas.size.y)
for layer in canvas.layers: #Store layers for layer in canvas.layers: # Store layers
file.store_line("-") file.store_line("-")
file.store_buffer(layer[0].get_data()) file.store_buffer(layer[0].get_data())
file.store_line(layer[2]) file.store_line(layer[2]) # Layer name
file.store_float(layer[4]) # Layer transparency
file.store_line("END_LAYERS") file.store_line("END_LAYERS")
for child in canvas.get_children(): #Store guides for child in canvas.get_children(): #Store guides
@ -544,8 +550,8 @@ func _on_ImportSprites_files_selected(paths) -> void:
image.lock() image.lock()
var tex := ImageTexture.new() var tex := ImageTexture.new()
tex.create_from_image(image, 0) tex.create_from_image(image, 0)
#Store [Image, ImageTexture, Layer Name, Visibity boolean] #Store [Image, ImageTexture, Layer Name, Visibity boolean, Opacity]
canvas.layers.append([image, tex, "Layer 0", true]) canvas.layers.append([image, tex, "Layer 0", true, 1])
canvas.frame = i canvas.frame = i
Global.canvases.append(canvas) Global.canvases.append(canvas)
Global.canvas_parent.add_child(canvas) Global.canvas_parent.add_child(canvas)
@ -606,7 +612,16 @@ func save_sprite(canvas : Canvas, path : String) -> void:
whole_image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8) whole_image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
whole_image.lock() whole_image.lock()
for layer in canvas.layers: for layer in canvas.layers:
canvas.blend_rect(whole_image, layer[0], Rect2(canvas.position, canvas.size), Vector2.ZERO) var img : Image = layer[0]
img.lock()
if layer[4] < 1: # If we have layer transparency
for xx in img.get_size().x:
for yy in img.get_size().y:
var pixel_color := img.get_pixel(xx, yy)
var alpha : float = pixel_color.a * layer[4]
img.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha))
canvas.blend_rect(whole_image, img, Rect2(canvas.position, canvas.size), Vector2.ZERO)
layer[0].lock() layer[0].lock()
var err = whole_image.save_png(path) var err = whole_image.save_png(path)
if err != OK: if err != OK:
@ -635,8 +650,18 @@ func save_spritesheet() -> void:
var dst := Vector2.ZERO var dst := Vector2.ZERO
for canvas in Global.canvases: for canvas in Global.canvases:
for layer in canvas.layers: for layer in canvas.layers:
canvas.blend_rect(whole_image, layer[0], Rect2(canvas.position, canvas.size), dst) var img : Image = layer[0]
img.lock()
if layer[4] < 1: # If we have layer transparency
for xx in img.get_size().x:
for yy in img.get_size().y:
var pixel_color := img.get_pixel(xx, yy)
var alpha : float = pixel_color.a * layer[4]
img.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha))
canvas.blend_rect(whole_image, img, Rect2(canvas.position, canvas.size), dst)
layer[0].lock() layer[0].lock()
if export_vertical_spritesheet.pressed: if export_vertical_spritesheet.pressed:
dst += Vector2(0, canvas.size.y) dst += Vector2(0, canvas.size.y)
else: else:
@ -691,7 +716,7 @@ func _on_OutlineDialog_confirmed() -> void:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + Vector2.RIGHT * i new_pos = pos + Vector2.RIGHT * i
if new_pos.x < Global.canvas.size.x - 1: if new_pos.x < Global.canvas.size.x:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
@ -703,7 +728,7 @@ func _on_OutlineDialog_confirmed() -> void:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + Vector2.DOWN * i new_pos = pos + Vector2.DOWN * i
if new_pos.y < Global.canvas.size.y - 1: if new_pos.y < Global.canvas.size.y:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
@ -828,7 +853,7 @@ func add_layer(is_new := true) -> void:
new_layer_tex.create_from_image(new_layer, 0) new_layer_tex.create_from_image(new_layer, 0)
var new_layers := Global.canvas.layers.duplicate() var new_layers := Global.canvas.layers.duplicate()
new_layers.append([new_layer, new_layer_tex, null, true]) new_layers.append([new_layer, new_layer_tex, null, true, 1])
Global.undos += 1 Global.undos += 1
Global.undo_redo.create_action("Add Layer") Global.undo_redo.create_action("Add Layer")
Global.undo_redo.add_do_property(Global.canvas, "layers", new_layers) Global.undo_redo.add_do_property(Global.canvas, "layers", new_layers)
@ -1103,6 +1128,9 @@ func _on_RightHorizontalMirroring_toggled(button_pressed) -> void:
func _on_RightVerticalMirroring_toggled(button_pressed) -> void: func _on_RightVerticalMirroring_toggled(button_pressed) -> void:
Global.right_vertical_mirror = button_pressed Global.right_vertical_mirror = button_pressed
func _on_OpacitySlider_value_changed(value) -> void:
Global.canvas.layers[Global.canvas.current_layer_index][4] = value / 100
func _on_QuitDialog_confirmed() -> void: func _on_QuitDialog_confirmed() -> void:
# Darken the UI to denote that the application is currently exiting # Darken the UI to denote that the application is currently exiting
# (it won't respond to user input in this state). # (it won't respond to user input in this state).
@ -1110,7 +1138,7 @@ func _on_QuitDialog_confirmed() -> void:
get_tree().quit() get_tree().quit()
func _on_AddPalette_pressed(): func _on_AddPalette_pressed() -> void:
Global.add_palette_button.get_child(0).popup(Rect2(Global.add_palette_button.rect_global_position, Vector2.ONE)) Global.add_palette_button.get_child(0).popup(Rect2(Global.add_palette_button.rect_global_position, Vector2.ONE))
func _on_RemovePalette_pressed() -> void: func _on_RemovePalette_pressed() -> void:

View file

@ -51,7 +51,7 @@ boot_splash/image="res://splash.png"
boot_splash/bg_color=Color( 0.145098, 0.145098, 0.164706, 1 ) boot_splash/bg_color=Color( 0.145098, 0.145098, 0.164706, 1 )
config/icon="res://icon.png" config/icon="res://icon.png"
config/description="A free & open-source 2D sprite editor" config/description="A free & open-source 2D sprite editor"
config/Version="v0.5" config/Version="v0.6"
[autoload] [autoload]