aseprite/tests/scripts/compose_groups.lua
Guilherme Belchior ffc3684b1b Compose groups separately from all other layers
Maintain hierarchical structure of sprite groups instead of flattening.
Allows opacity and blend mode to be applied correctly to groups.
Sets the foundation for future features like mask layers.

Note:
Requires full image rendering and impacts performance in some scenarios.
Avoids complex code changes for minor performance gains.

Co-authored-by: Guilherme Marcondes <guilherme.marcondes@tecnico.ulisboa.pt>
2024-06-24 18:16:42 -03:00

186 lines
5.8 KiB
Lua

-- Copyright (C) 2024 Igara Studio S.A.
--
-- This file is released under the terms of the MIT license.
-- Read LICENSE.txt for more information.
dofile('./test_utils.lua')
-- Enable experimental compose groups feature
app.preferences.experimental.compose_groups = true
function create_group_layer()
local s = Sprite(2, 2)
assert(#s.layers == 1)
-- create two layers and a group layer
local a = s.layers[1] a.name = "a"
assert(#s.layers == 1)
local b = s:newLayer() b.name = "b"
assert(#s.layers == 2)
local g = s:newGroup() g.name = "g"
assert(#s.layers == 3)
-- b is child of g
b.parent = g
assert(g.parent == s)
assert(b.parent == g)
assert(#s.layers == 2)
assert(s.layers[1] == a)
assert(s.layers[2] == g)
return s, a, b, g
end
-- Test groups opacity to impact on children layers
do
assert(app.preferences.experimental.compose_groups == true)
local s, a, b, g = create_group_layer()
-- draw in b layer
local cel = s:newCel(b, 1, Image(2, 2, ColorMode.RGB))
local img = cel.image
img:drawPixel(0, 0, Color(255, 0, 0, 255))
img:drawPixel(1, 0, Color(0, 255, 0, 255))
img:drawPixel(0, 1, Color(0, 0, 255, 255))
img:drawPixel(1, 1, Color(255, 255, 0, 255))
local r = Image(s.spec) -- render
r:drawSprite(s, 1, 0, 0)
expect_clr(r:getPixel(0, 0), app.pixelColor.rgba(255, 0, 0, 255))
expect_clr(r:getPixel(1, 0), app.pixelColor.rgba(0, 255, 0, 255))
expect_clr(r:getPixel(0, 1), app.pixelColor.rgba(0, 0, 255, 255))
expect_clr(r:getPixel(1, 1), app.pixelColor.rgba(255, 255, 0, 255))
-- Set opacity to 50%
g.opacity = 128
r = Image(s.spec)
r:drawSprite(s, 1, 0, 0)
print(g.opacity)
print(r:getPixel(0, 0), app.pixelColor.rgba(255, 0, 0, 255))
-- Assert that the image is drawn with 50% opacity
expect_clr(r:getPixel(0, 0), app.pixelColor.rgba(255, 0, 0, 128))
expect_clr(r:getPixel(1, 0), app.pixelColor.rgba(0, 255, 0, 128))
expect_clr(r:getPixel(0, 1), app.pixelColor.rgba(0, 0, 255, 128))
expect_clr(r:getPixel(1, 1), app.pixelColor.rgba(255, 255, 0, 128))
-- Set opacity to 100%
g.opacity = 255
r = Image(s.spec)
r:drawSprite(s, 1, 0, 0)
expect_eq(g.opacity, 255)
-- Assert that the image is drawn with 100% opacity
expect_clr(r:getPixel(0, 0), app.pixelColor.rgba(255, 0, 0, 255))
expect_clr(r:getPixel(1, 0), app.pixelColor.rgba(0, 255, 0, 255))
expect_clr(r:getPixel(0, 1), app.pixelColor.rgba(0, 0, 255, 255))
expect_clr(r:getPixel(1, 1), app.pixelColor.rgba(255, 255, 0, 255))
-- Set group opacity to 50% and layer opacity to 50%
g.opacity = 128
b.opacity = 128
r = Image(s.spec)
r:drawSprite(s, 1, 0, 0)
assert(g.opacity == 128)
assert(b.opacity == 128)
-- Assert that the image is drawn with 25% opacity
expect_clr(r:getPixel(0, 0), app.pixelColor.rgba(255, 0, 0, 64))
expect_clr(r:getPixel(1, 0), app.pixelColor.rgba(0, 255, 0, 64))
expect_clr(r:getPixel(0, 1), app.pixelColor.rgba(0, 0, 255, 64))
expect_clr(r:getPixel(1, 1), app.pixelColor.rgba(255, 255, 0, 64))
-- Create a new layer in front of the group and check that it's not affected by the group opacity
local c = s:newLayer()
c.name = "c"
-- draw in c layer
local cel = s:newCel(c, 1, Image(1, 1, ColorMode.RGB))
local img = cel.image
img:drawPixel(0, 0, Color(255, 0, 255, 255))
r = Image(s.spec)
r:drawSprite(s, 1, 0, 0)
-- Assert that the first pixel is drawn with 100% opacity and the remaining ones with 25% opacity
expect_clr(r:getPixel(0, 0), app.pixelColor.rgba(255, 0, 255, 255))
expect_clr(r:getPixel(1, 0), app.pixelColor.rgba(0, 255, 0, 64))
expect_clr(r:getPixel(0, 1), app.pixelColor.rgba(0, 0, 255, 64))
expect_clr(r:getPixel(1, 1), app.pixelColor.rgba(255, 255, 0, 64))
end
do -- test group blend to impact children layers
assert(app.preferences.experimental.compose_groups == true)
local s, a, b, g = create_group_layer()
-- draw all black in layer a
local cel = s:newCel(a, 1, Image(2, 2, ColorMode.RGB))
local img = cel.image
img:drawPixel(0, 0, Color(0, 0, 0, 255))
img:drawPixel(1, 0, Color(0, 0, 0, 255))
img:drawPixel(0, 1, Color(0, 0, 0, 255))
img:drawPixel(1, 1, Color(0, 0, 0, 255))
-- draw in b layer
local cel = s:newCel(b, 1, Image(2, 2, ColorMode.RGB))
local img = cel.image
img:drawPixel(0, 0, Color(255, 0, 0, 255))
img:drawPixel(1, 0, Color(0, 255, 0, 255))
img:drawPixel(0, 1, Color(0, 0, 255, 255))
img:drawPixel(1, 1, Color(255, 255, 0, 255))
local r = Image(s.spec) -- render
r:drawSprite(s, 1, 0, 0)
expect_clr(r:getPixel(0, 0), app.pixelColor.rgba(255, 0, 0, 255))
expect_clr(r:getPixel(1, 0), app.pixelColor.rgba(0, 255, 0, 255))
expect_clr(r:getPixel(0, 1), app.pixelColor.rgba(0, 0, 255, 255))
expect_clr(r:getPixel(1, 1), app.pixelColor.rgba(255, 255, 0, 255))
-- Set blend to MULTIPLY
g.blendMode = BlendMode.MULTIPLY
r = Image(s.spec)
r:drawSprite(s, 1, 0, 0)
-- Assert that the image is drawn with MULTIPLY blend mode
expect_clr(r:getPixel(0, 0), app.pixelColor.rgba(0, 0, 0, 255))
expect_clr(r:getPixel(1, 0), app.pixelColor.rgba(0, 0, 0, 255))
expect_clr(r:getPixel(0, 1), app.pixelColor.rgba(0, 0, 0, 255))
expect_clr(r:getPixel(1, 1), app.pixelColor.rgba(0, 0, 0, 255))
-- Create a new layer in front of the group and check that it's not affected by the group blend mode
local c = s:newLayer()
c.name = "c"
-- draw in c layer
local cel = s:newCel(c, 1, Image(1, 1, ColorMode.RGB))
local img = cel.image
img:drawPixel(0, 0, Color(255, 0, 255, 255))
r = Image(s.spec)
r:drawSprite(s, 1, 0, 0)
-- Assert that the first pixel is drawn with Normal blend mode and the remaining ones with Multiply blend mode
expect_clr(r:getPixel(0, 0), app.pixelColor.rgba(255, 0, 255, 255))
expect_clr(r:getPixel(1, 0), app.pixelColor.rgba(0, 0, 0, 255))
expect_clr(r:getPixel(0, 1), app.pixelColor.rgba(0, 0, 0, 255))
expect_clr(r:getPixel(1, 1), app.pixelColor.rgba(0, 0, 0, 255))
end