mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +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:
parent
aa860960e2
commit
ed2e757c11
18
Main.tscn
18
Main.tscn
|
@ -158,12 +158,14 @@ anchor_bottom = 1.0
|
|||
custom_constants/separation = 0
|
||||
|
||||
[node name="TopMenuContainer" type="Panel" parent="MenuAndUI"]
|
||||
editor/display_folded = true
|
||||
margin_right = 1152.0
|
||||
margin_bottom = 28.0
|
||||
rect_min_size = Vector2( 0, 28 )
|
||||
custom_styles/panel = ExtResource( 3 )
|
||||
|
||||
[node name="MenuItems" type="HBoxContainer" parent="MenuAndUI/TopMenuContainer"]
|
||||
editor/display_folded = true
|
||||
margin_left = 2.0
|
||||
margin_top = 4.0
|
||||
margin_right = 1010.0
|
||||
|
@ -233,7 +235,6 @@ text = "[64×64]"
|
|||
align = 2
|
||||
|
||||
[node name="UI" type="HBoxContainer" parent="MenuAndUI"]
|
||||
editor/display_folded = true
|
||||
margin_top = 28.0
|
||||
margin_right = 1152.0
|
||||
margin_bottom = 648.0
|
||||
|
@ -1326,7 +1327,6 @@ margin_right = 224.0
|
|||
margin_bottom = 419.0
|
||||
|
||||
[node name="LayerVBoxContainer" type="VBoxContainer" parent="MenuAndUI/UI/LayerPanel/LayersAndMisc"]
|
||||
editor/display_folded = true
|
||||
margin_top = 423.0
|
||||
margin_right = 224.0
|
||||
margin_bottom = 604.0
|
||||
|
@ -1417,9 +1417,16 @@ texture_normal = ExtResource( 55 )
|
|||
texture_hover = ExtResource( 56 )
|
||||
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"]
|
||||
editor/display_folded = true
|
||||
margin_top = 38.0
|
||||
margin_top = 50.0
|
||||
margin_right = 224.0
|
||||
margin_bottom = 181.0
|
||||
size_flags_horizontal = 3
|
||||
|
@ -1688,9 +1695,9 @@ anchor_top = 0.5
|
|||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -92.0
|
||||
margin_top = -36.0
|
||||
margin_top = -27.0
|
||||
margin_right = 92.0
|
||||
margin_bottom = 5.0
|
||||
margin_bottom = -4.0
|
||||
custom_constants/vseparation = 4
|
||||
custom_constants/hseparation = 4
|
||||
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/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="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="confirmed" from="CreateNewImage" to="." method="_on_CreateNewImage_confirmed"]
|
||||
[connection signal="popup_hide" from="CreateNewImage" to="." method="_can_draw_true"]
|
||||
|
|
|
@ -36,8 +36,8 @@ func _ready() -> void:
|
|||
var tex := ImageTexture.new()
|
||||
tex.create_from_image(sprite, 0)
|
||||
|
||||
#Store [Image, ImageTexture, Layer Name, Visibity boolean]
|
||||
layers.append([sprite, tex, "Layer 0", true])
|
||||
#Store [Image, ImageTexture, Layer Name, Visibity boolean, Opacity]
|
||||
layers.append([sprite, tex, "Layer 0", true, 1])
|
||||
|
||||
generate_layer_panels()
|
||||
|
||||
|
@ -407,18 +407,19 @@ func _draw() -> void:
|
|||
|
||||
#Draw current frame layers
|
||||
for texture in layers:
|
||||
var modulate_color := Color(1, 1, 1, texture[4])
|
||||
if texture[3]: #if it's visible
|
||||
draw_texture(texture[1], location)
|
||||
draw_texture(texture[1], location, modulate_color)
|
||||
|
||||
if Global.tile_mode:
|
||||
draw_texture(texture[1], Vector2(location.x, location.y + size.y)) #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)) #Left
|
||||
draw_texture(texture[1], location - size) #Up left
|
||||
draw_texture(texture[1], Vector2(location.x, location.y - size.y)) #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)) #Right
|
||||
draw_texture(texture[1], location + size) #Down right
|
||||
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), modulate_color) #Down Left
|
||||
draw_texture(texture[1], Vector2(location.x - size.x, location.y), modulate_color) #Left
|
||||
draw_texture(texture[1], location - size, modulate_color) #Up left
|
||||
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), modulate_color) #Up right
|
||||
draw_texture(texture[1], Vector2(location.x + size.x, location.y), modulate_color) #Right
|
||||
draw_texture(texture[1], location + size, modulate_color) #Down right
|
||||
|
||||
#Idea taken from flurick (on GitHub)
|
||||
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(1).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)
|
||||
|
||||
func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button : String, current_action := "None") -> void:
|
||||
|
|
|
@ -46,7 +46,7 @@ func _on_PopupMenu_id_pressed(ID : int) -> void:
|
|||
sprite.lock()
|
||||
var tex := ImageTexture.new()
|
||||
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.undo_redo.create_action("Add Frame")
|
||||
|
|
|
@ -189,6 +189,7 @@ var remove_layer_button : BaseButton
|
|||
var move_up_layer_button : BaseButton
|
||||
var move_down_layer_button : BaseButton
|
||||
var merge_down_layer_button : BaseButton
|
||||
var layer_opacity_slider : HSlider
|
||||
|
||||
var add_palette_button : TextureButton
|
||||
var remove_palette_button : TextureButton
|
||||
|
@ -285,12 +286,15 @@ func _ready() -> void:
|
|||
play_backwards = find_node_by_name(root, "PlayBackwards")
|
||||
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")
|
||||
move_up_layer_button = find_node_by_name(layer_buttons, "MoveUpLayer")
|
||||
move_down_layer_button = find_node_by_name(layer_buttons, "MovwDownLayer")
|
||||
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")
|
||||
remove_palette_button = find_node_by_name(root, "RemovePalette")
|
||||
|
|
|
@ -43,9 +43,10 @@ func changed_selection() -> void:
|
|||
child.label.visible = true
|
||||
child.line_edit.visible = 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.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:
|
||||
Global.move_up_layer_button.disabled = false
|
||||
|
|
|
@ -387,8 +387,10 @@ func _on_OpenSprite_file_selected(path : String) -> void:
|
|||
return
|
||||
|
||||
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()
|
||||
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")
|
||||
var frame := 0
|
||||
var frame_line := file.get_line()
|
||||
|
@ -403,12 +405,15 @@ func _on_OpenSprite_file_selected(path : String) -> void:
|
|||
while layer_line == "-": #Load layers
|
||||
var buffer := file.get_buffer(width * height * 4)
|
||||
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()
|
||||
image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer)
|
||||
image.lock()
|
||||
var tex := ImageTexture.new()
|
||||
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()
|
||||
|
||||
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)
|
||||
if err == 0:
|
||||
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_16(canvas.size.x)
|
||||
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_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")
|
||||
|
||||
for child in canvas.get_children(): #Store guides
|
||||
|
@ -544,8 +550,8 @@ func _on_ImportSprites_files_selected(paths) -> void:
|
|||
image.lock()
|
||||
var tex := ImageTexture.new()
|
||||
tex.create_from_image(image, 0)
|
||||
#Store [Image, ImageTexture, Layer Name, Visibity boolean]
|
||||
canvas.layers.append([image, tex, "Layer 0", true])
|
||||
#Store [Image, ImageTexture, Layer Name, Visibity boolean, Opacity]
|
||||
canvas.layers.append([image, tex, "Layer 0", true, 1])
|
||||
canvas.frame = i
|
||||
Global.canvases.append(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.lock()
|
||||
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()
|
||||
var err = whole_image.save_png(path)
|
||||
if err != OK:
|
||||
|
@ -635,8 +650,18 @@ func save_spritesheet() -> void:
|
|||
var dst := Vector2.ZERO
|
||||
for canvas in Global.canvases:
|
||||
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()
|
||||
|
||||
if export_vertical_spritesheet.pressed:
|
||||
dst += Vector2(0, canvas.size.y)
|
||||
else:
|
||||
|
@ -691,7 +716,7 @@ func _on_OutlineDialog_confirmed() -> void:
|
|||
new_image.set_pixelv(new_pos, outline_color)
|
||||
|
||||
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)
|
||||
if new_pixel.a == 0:
|
||||
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_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)
|
||||
if new_pixel.a == 0:
|
||||
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)
|
||||
|
||||
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.undo_redo.create_action("Add Layer")
|
||||
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:
|
||||
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:
|
||||
# Darken the UI to denote that the application is currently exiting
|
||||
# (it won't respond to user input in this state).
|
||||
|
@ -1110,7 +1138,7 @@ func _on_QuitDialog_confirmed() -> void:
|
|||
|
||||
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))
|
||||
|
||||
func _on_RemovePalette_pressed() -> void:
|
||||
|
|
|
@ -51,7 +51,7 @@ boot_splash/image="res://splash.png"
|
|||
boot_splash/bg_color=Color( 0.145098, 0.145098, 0.164706, 1 )
|
||||
config/icon="res://icon.png"
|
||||
config/description="A free & open-source 2D sprite editor"
|
||||
config/Version="v0.5"
|
||||
config/Version="v0.6"
|
||||
|
||||
[autoload]
|
||||
|
||||
|
|
Loading…
Reference in a new issue