mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-02-18 19:43:14 +00:00
* Blend group layers on `DrawingAlgos.blend_layers()` * Support group layer blending on the canvas * Allow editing of group layer properties * Fix issues with group layer blending in canvas, and unite common code * Group layers can now be used as clipping masks * Make move tool preview work on child layers * Change OffsetImage's `blend_layers()` to support group layer blending * Support group layer blending in the canvas preview * Fix layer blending mode, clipping mask opacity and cel opacity not being updated automatically if the layer/cel changed is not selected * Add a pass through blending mode to layer groups Fingers crossed that no bugs were introduced * Fix issue with layers that belong to pass through groups not updating their textures on the canvas automatically on undo
166 lines
4.6 KiB
GDScript
166 lines
4.6 KiB
GDScript
class_name GroupLayer
|
|
extends BaseLayer
|
|
## A class for group layer properties
|
|
|
|
var expanded := true
|
|
|
|
|
|
func _init(_project: Project, _name := "") -> void:
|
|
project = _project
|
|
name = _name
|
|
|
|
|
|
## Blends all of the images of children layer of the group layer into a single image.
|
|
func blend_children(frame: Frame, origin := Vector2i.ZERO, apply_effects := true) -> Image:
|
|
var image := Image.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
|
|
var children := get_children(false)
|
|
if children.size() <= 0:
|
|
return image
|
|
var textures: Array[Image] = []
|
|
var metadata_image := Image.create(children.size(), 4, false, Image.FORMAT_RG8)
|
|
var current_child_index := 0
|
|
for i in children.size():
|
|
var layer := children[i]
|
|
if not layer.is_visible_in_hierarchy():
|
|
current_child_index += 1
|
|
continue
|
|
if layer is GroupLayer:
|
|
current_child_index = _blend_child_group(
|
|
image,
|
|
layer,
|
|
frame,
|
|
textures,
|
|
metadata_image,
|
|
current_child_index,
|
|
origin,
|
|
apply_effects
|
|
)
|
|
else:
|
|
_include_child_in_blending(
|
|
image,
|
|
layer,
|
|
frame,
|
|
textures,
|
|
metadata_image,
|
|
current_child_index,
|
|
origin,
|
|
apply_effects
|
|
)
|
|
current_child_index += 1
|
|
|
|
if DisplayServer.get_name() != "headless" and textures.size() > 0:
|
|
var texture_array := Texture2DArray.new()
|
|
texture_array.create_from_images(textures)
|
|
var params := {
|
|
"layers": texture_array,
|
|
"metadata": ImageTexture.create_from_image(metadata_image),
|
|
"origin_x_positive": origin.x > 0,
|
|
"origin_y_positive": origin.y > 0,
|
|
}
|
|
var gen := ShaderImageEffect.new()
|
|
gen.generate_image(image, DrawingAlgos.blend_layers_shader, params, project.size)
|
|
if apply_effects:
|
|
image = display_effects(frame.cels[index], image)
|
|
return image
|
|
|
|
|
|
func _include_child_in_blending(
|
|
image: Image,
|
|
layer: BaseLayer,
|
|
frame: Frame,
|
|
textures: Array[Image],
|
|
metadata_image: Image,
|
|
i: int,
|
|
origin: Vector2i,
|
|
apply_effects: bool
|
|
) -> void:
|
|
var cel := frame.cels[layer.index]
|
|
if DisplayServer.get_name() == "headless":
|
|
DrawingAlgos.blend_layers_headless(image, project, layer, cel, origin)
|
|
else:
|
|
var cel_image: Image
|
|
if apply_effects:
|
|
cel_image = layer.display_effects(cel)
|
|
else:
|
|
cel_image = cel.get_image()
|
|
textures.append(cel_image)
|
|
DrawingAlgos.set_layer_metadata_image(layer, cel, metadata_image, i)
|
|
if origin != Vector2i.ZERO:
|
|
# Only used as a preview for the move tool, when used on a group's children
|
|
var test_array := [project.frames.find(frame), project.layers.find(layer)]
|
|
if test_array in project.selected_cels:
|
|
var origin_fixed := Vector2(origin).abs() / Vector2(cel_image.get_size())
|
|
metadata_image.set_pixel(i, 2, Color(origin_fixed.x, origin_fixed.y, 0.0, 0.0))
|
|
|
|
|
|
## Include a child group in the blending process.
|
|
## If the child group is set to pass through mode, loop through its children
|
|
## and include them as separate images, instead of blending them all together.
|
|
## Gets called recursively if the child group has children groups of its own,
|
|
## and they are also set to pass through mode.
|
|
func _blend_child_group(
|
|
image: Image,
|
|
layer: BaseLayer,
|
|
frame: Frame,
|
|
textures: Array[Image],
|
|
metadata_image: Image,
|
|
i: int,
|
|
origin: Vector2i,
|
|
apply_effects: bool
|
|
) -> int:
|
|
var new_i := i
|
|
var blend_rect := Rect2i(Vector2i.ZERO, project.size)
|
|
var cel := frame.cels[layer.index]
|
|
if layer.blend_mode == BlendModes.PASS_THROUGH:
|
|
var children := layer.get_children(false)
|
|
for j in children.size():
|
|
var child := children[j]
|
|
if child is GroupLayer:
|
|
new_i = _blend_child_group(
|
|
image, child, frame, textures, metadata_image, i + j, origin, apply_effects
|
|
)
|
|
else:
|
|
new_i += j
|
|
metadata_image.crop(metadata_image.get_width() + 1, metadata_image.get_height())
|
|
_include_child_in_blending(
|
|
image, child, frame, textures, metadata_image, new_i, origin, apply_effects
|
|
)
|
|
else:
|
|
var blended_children := (layer as GroupLayer).blend_children(frame, origin)
|
|
if DisplayServer.get_name() == "headless":
|
|
image.blend_rect(blended_children, blend_rect, origin)
|
|
else:
|
|
textures.append(blended_children)
|
|
DrawingAlgos.set_layer_metadata_image(layer, cel, metadata_image, i)
|
|
return new_i
|
|
|
|
|
|
# Overridden Methods:
|
|
|
|
|
|
func serialize() -> Dictionary:
|
|
var data := super.serialize()
|
|
data["type"] = get_layer_type()
|
|
data["expanded"] = expanded
|
|
return data
|
|
|
|
|
|
func deserialize(dict: Dictionary) -> void:
|
|
super.deserialize(dict)
|
|
expanded = dict.expanded
|
|
|
|
|
|
func get_layer_type() -> int:
|
|
return Global.LayerTypes.GROUP
|
|
|
|
|
|
func new_empty_cel() -> BaseCel:
|
|
return GroupCel.new()
|
|
|
|
|
|
func set_name_to_default(number: int) -> void:
|
|
name = tr("Group") + " %s" % number
|
|
|
|
|
|
func accepts_child(_layer: BaseLayer) -> bool:
|
|
return true
|