mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-04 13:59:46 +00:00
Merge remote-tracking branch 'tests/main'
This commit is contained in:
commit
c7cafca69a
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@ -64,13 +64,6 @@ jobs:
|
|||||||
if [[ "${{ runner.os }}" == "Linux" ]] ; then
|
if [[ "${{ runner.os }}" == "Linux" ]] ; then
|
||||||
export XVFB=xvfb-run
|
export XVFB=xvfb-run
|
||||||
fi
|
fi
|
||||||
if [[ "${{ github.base_ref }}" == "beta" ]] || [[ "${{ github.ref }}" == "refs/heads/beta" ]] ; then
|
export ASEPRITE=$PWD/build/bin/aseprite
|
||||||
export TESTS_BRANCH=beta
|
|
||||||
else
|
|
||||||
export TESTS_BRANCH=main
|
|
||||||
fi
|
|
||||||
cd build
|
|
||||||
export ASEPRITE=$PWD/bin/aseprite
|
|
||||||
git clone --branch $TESTS_BRANCH --recursive https://github.com/aseprite/tests.git
|
|
||||||
cd tests
|
cd tests
|
||||||
$XVFB bash run-tests.sh
|
$XVFB bash run-tests.sh
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
|||||||
|
[submodule "tests/third_party/json"]
|
||||||
|
path = tests/third_party/json
|
||||||
|
url = https://github.com/aseprite/json.lua
|
||||||
[submodule "third_party/pixman"]
|
[submodule "third_party/pixman"]
|
||||||
path = third_party/pixman
|
path = third_party/pixman
|
||||||
url = https://github.com/aseprite/pixman.git
|
url = https://github.com/aseprite/pixman.git
|
||||||
|
21
tests/LICENSE.txt
Normal file
21
tests/LICENSE.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Copyright (c) 2018-2022 Igara Studio S.A.
|
||||||
|
Copyright (c) 2018 David Capello
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
31
tests/README.md
Normal file
31
tests/README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Aseprite Tests
|
||||||
|
|
||||||
|
Test suite for [Aseprite](https://github.com/aseprite/aseprite)
|
||||||
|
to avoid breaking backward compatibility.
|
||||||
|
|
||||||
|
This project is cloned by the
|
||||||
|
[build.yml](https://github.com/aseprite/aseprite/blob/main/.github/workflows/build.yml) file
|
||||||
|
on Aseprite project to do several automated tests:
|
||||||
|
|
||||||
|
* Save/load file formats correctly. For this we have `.aseprite`, `.png`,
|
||||||
|
`.gif`, etc. files [sprites](https://github.com/aseprite/tests/tree/main/sprites)
|
||||||
|
folder.
|
||||||
|
* Test backward compatibility with [Aseprite CLI](https://www.aseprite.org/docs/cli/) options
|
||||||
|
* Future [scripting API](https://github.com/aseprite/api) using [scripts](https://github.com/aseprite/tests/tree/main/scripts)
|
||||||
|
|
||||||
|
## How to run tests?
|
||||||
|
|
||||||
|
You have to set the `ASEPRITE` environment variable pointing to the
|
||||||
|
Aseprite executable and then run `run-tests.sh` from Bash:
|
||||||
|
|
||||||
|
export ASEPRITE=$HOME/your-aseprite-build/bin/aseprite
|
||||||
|
git clone https://github.com/aseprite/tests.git
|
||||||
|
cd tests
|
||||||
|
bash run-tests.sh
|
||||||
|
|
||||||
|
You can filter some tests with a regex giving a parameter to
|
||||||
|
`run-tests.sh`, for example:
|
||||||
|
|
||||||
|
run-tests.sh color
|
||||||
|
|
||||||
|
Should run all tests which have the `color` word in their name.
|
61
tests/cli/file-formats.sh
Normal file
61
tests/cli/file-formats.sh
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
|
||||||
|
# Create a simple image and save it in all formats using scripts
|
||||||
|
d=$t/file-formats
|
||||||
|
mkdir $d
|
||||||
|
cat >$d/gen.lua <<EOF
|
||||||
|
local a = Sprite(32, 32)
|
||||||
|
app.useTool{ points={{0,0},{31,31}}, tool='filled_ellipse', color=Color(255,255,255) }
|
||||||
|
a:saveAs('$d/test.aseprite')
|
||||||
|
a:saveAs('$d/test.gif')
|
||||||
|
a:saveAs('$d/test.ico')
|
||||||
|
a:saveAs('$d/test.jpg')
|
||||||
|
a:saveAs('$d/test.pcx')
|
||||||
|
a:saveAs('$d/test.svg')
|
||||||
|
a:saveAs('$d/test.tga')
|
||||||
|
a:saveAs('$d/test.webp')
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/gen.lua" || exit 1
|
||||||
|
|
||||||
|
# Load image and save in all formats using CLI
|
||||||
|
$ASEPRITE -b "$d/test.aseprite" \
|
||||||
|
-save-as "$d/test2.gif" \
|
||||||
|
-save-as "$d/test2.ico" \
|
||||||
|
-save-as "$d/test2.jpg" \
|
||||||
|
-save-as "$d/test2.pcx" \
|
||||||
|
-save-as "$d/test2.svg" \
|
||||||
|
-save-as "$d/test2.tga" \
|
||||||
|
-save-as "$d/test2.webp" \
|
||||||
|
|| exit 1
|
||||||
|
|
||||||
|
# Compare that all images are the same/equivalent
|
||||||
|
# Note: app.open() and Sprite{fromFile:} are the same
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local a = Sprite{ fromFile="$d/test.aseprite" }
|
||||||
|
local b = {
|
||||||
|
app.open("$d/test.gif"), app.open("$d/test2.gif"),
|
||||||
|
app.open("$d/test.ico"), app.open("$d/test2.ico"),
|
||||||
|
app.open("$d/test.jpg"), app.open("$d/test2.jpg"),
|
||||||
|
app.open("$d/test.pcx"), app.open("$d/test2.pcx"),
|
||||||
|
--app.open("$d/test.svg"), -- we don't support loading SVG files
|
||||||
|
app.open("$d/test.tga"), app.open("$d/test2.tga"),
|
||||||
|
app.open("$d/test.webp"), app.open("$d/test2.webp")
|
||||||
|
}
|
||||||
|
for i,c in ipairs(b) do
|
||||||
|
if c.colorMode == ColorMode.INDEXED then
|
||||||
|
app.activeSprite = c
|
||||||
|
app.command.ChangePixelFormat{ format="rgb" }
|
||||||
|
end
|
||||||
|
assert(c.colorMode == ColorMode.RGB)
|
||||||
|
if c.layers[1].isBackground then -- jpg and pcx
|
||||||
|
app.activeSprite = c
|
||||||
|
app.command.LayerFromBackground()
|
||||||
|
-- tolerance is 1 to remove jpg noise
|
||||||
|
app.command.ReplaceColor{ from=Color(0, 0, 0, 255), to=Color(0, 0, 0, 0), tolerance=1 }
|
||||||
|
app.command.ReplaceColor{ from=Color(255, 255, 255, 255), to=Color(255, 255, 255, 255), tolerance=1 }
|
||||||
|
end
|
||||||
|
assert(a.cels[1].image:isEqual(c.cels[1].image))
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
7
tests/cli/help.sh
Normal file
7
tests/cli/help.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Copyright (C) 2018 Igara Studio S.A.
|
||||||
|
|
||||||
|
if ! $ASEPRITE --help | grep "\\-\\-help" > /dev/null ; then
|
||||||
|
echo "FAILED: --help doesn't include usage information"
|
||||||
|
exit 1
|
||||||
|
fi
|
10
tests/cli/list-layers.sh
Normal file
10
tests/cli/list-layers.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Copyright (C) 2018 Igara Studio S.A.
|
||||||
|
|
||||||
|
expect "bg
|
||||||
|
fg" "$ASEPRITE -b --list-layers sprites/1empty3.aseprite"
|
||||||
|
|
||||||
|
expect "a
|
||||||
|
b
|
||||||
|
c
|
||||||
|
d" "$ASEPRITE -b --list-layers sprites/abcd.aseprite"
|
5
tests/cli/list-tags.sh
Normal file
5
tests/cli/list-tags.sh
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Copyright (C) 2018 Igara Studio S.A.
|
||||||
|
|
||||||
|
expect "a
|
||||||
|
b" "$ASEPRITE -b --list-tags sprites/1empty3.aseprite"
|
256
tests/cli/save-as.sh
Normal file
256
tests/cli/save-as.sh
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Copyright (C) 2018-2021 Igara Studio S.A.
|
||||||
|
|
||||||
|
function list_files() {
|
||||||
|
oldwd=$(pwd $PWDARG)
|
||||||
|
cd $1 && ls -1 *.*
|
||||||
|
cd $oldwd
|
||||||
|
}
|
||||||
|
|
||||||
|
# --save-as
|
||||||
|
|
||||||
|
d=$t/save-as
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --save-as "$d/image00.png" || exit 1
|
||||||
|
expect "image00.png
|
||||||
|
image01.png
|
||||||
|
image02.png" "list_files $d"
|
||||||
|
|
||||||
|
# --ignore-empty --save-as
|
||||||
|
|
||||||
|
d=$t/save-as-ignore-empty
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --ignore-empty --save-as $d/image00.png || exit 1
|
||||||
|
expect "image00.png
|
||||||
|
image02.png" "list_files $d"
|
||||||
|
|
||||||
|
# --split-layers --save-as
|
||||||
|
|
||||||
|
d=$t/save-as-split-layers
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --split-layers --save-as $d/layer.png || exit 1
|
||||||
|
expect "layer (bg) 0.png
|
||||||
|
layer (bg) 1.png
|
||||||
|
layer (bg) 2.png
|
||||||
|
layer (fg) 0.png
|
||||||
|
layer (fg) 1.png
|
||||||
|
layer (fg) 2.png" "list_files $d"
|
||||||
|
|
||||||
|
# --save-as {layer}
|
||||||
|
|
||||||
|
d=$t/save-as-layer
|
||||||
|
mkdir $d # TODO why do we need this?
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --save-as $d/layer-{layer}.gif || exit 1
|
||||||
|
expect "layer-bg.gif
|
||||||
|
layer-fg.gif" "list_files $d"
|
||||||
|
|
||||||
|
# --save-as frame8-test.png
|
||||||
|
|
||||||
|
d=$t/save-as-frame8-test
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --save-as "$d/frame8-test.png" || exit 1
|
||||||
|
expect "frame8-test1.png
|
||||||
|
frame8-test2.png
|
||||||
|
frame8-test3.png" "list_files $d"
|
||||||
|
|
||||||
|
# --save-as frame-0.png
|
||||||
|
|
||||||
|
d=$t/save-as-frame-0
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --save-as "$d/frame-0.png" || exit 1
|
||||||
|
expect "frame-0.png
|
||||||
|
frame-1.png
|
||||||
|
frame-2.png" "list_files $d"
|
||||||
|
|
||||||
|
# --save-as frame-00.png
|
||||||
|
|
||||||
|
d=$t/save-as-frame-00
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --save-as "$d/frame-00.png" || exit 1
|
||||||
|
expect "frame-00.png
|
||||||
|
frame-01.png
|
||||||
|
frame-02.png" "list_files $d"
|
||||||
|
|
||||||
|
# --save-as frame-001.png
|
||||||
|
|
||||||
|
d=$t/save-as-frame-001
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --save-as "$d/frame-001.png" || exit 1
|
||||||
|
expect "frame-001.png
|
||||||
|
frame-002.png
|
||||||
|
frame-003.png" "list_files $d"
|
||||||
|
|
||||||
|
# --save-as frame-0032.png
|
||||||
|
|
||||||
|
d=$t/save-as-frame-0032
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --save-as "$d/frame-0032.png" || exit 1
|
||||||
|
expect "frame-0032.png
|
||||||
|
frame-0033.png
|
||||||
|
frame-0034.png" "list_files $d"
|
||||||
|
|
||||||
|
# --trim --save-as
|
||||||
|
|
||||||
|
d=$t/save-as-trim
|
||||||
|
$ASEPRITE -b --trim sprites/1empty3.aseprite --save-as "$d/trim-000.png" || exit 1
|
||||||
|
expect "trim-000.png
|
||||||
|
trim-001.png
|
||||||
|
trim-002.png" "list_files $d"
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local a = app.open("sprites/1empty3.aseprite")
|
||||||
|
assert(a.width == 32)
|
||||||
|
assert(a.height == 32)
|
||||||
|
app.command.FlattenLayers()
|
||||||
|
app.command.AutocropSprite()
|
||||||
|
assert(a.width == 22)
|
||||||
|
assert(a.height == 26)
|
||||||
|
local b = app.open("$d/trim-000.png")
|
||||||
|
assert(b.width == 22)
|
||||||
|
assert(b.height == 26)
|
||||||
|
local cleanImage = Image(b.spec)
|
||||||
|
cleanImage:clear()
|
||||||
|
for f = 1,3 do
|
||||||
|
local celA = a.layers[1]:cel(f)
|
||||||
|
local celB = b.layers[1]:cel(f)
|
||||||
|
if celA and celB then
|
||||||
|
assert(celA.image:isEqual(celB.image))
|
||||||
|
else
|
||||||
|
assert(not celA)
|
||||||
|
assert(not celB or celB.image:isEqual(cleanImage))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b --script "$d/compare.lua" || exit 1
|
||||||
|
|
||||||
|
# -split-layers -trim -save-as
|
||||||
|
|
||||||
|
d=$t/save-as-split-layers-trim
|
||||||
|
$ASEPRITE -batch -split-layers -trim sprites/1empty3.aseprite -save-as "$d/{layer}{frame}.png" || exit 1
|
||||||
|
expect "bg0.png
|
||||||
|
bg1.png
|
||||||
|
bg2.png
|
||||||
|
fg0.png
|
||||||
|
fg1.png
|
||||||
|
fg2.png" "list_files $d"
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local orig = app.open("sprites/1empty3.aseprite")
|
||||||
|
local bg = app.open("$d/bg0.png")
|
||||||
|
local fg = app.open("$d/fg0.png")
|
||||||
|
assert(bg.width == 22)
|
||||||
|
assert(bg.height == 11)
|
||||||
|
assert(fg.width == 19)
|
||||||
|
assert(fg.height == 11)
|
||||||
|
for f = 1,3 do
|
||||||
|
local origCelBG = orig.layers[1]:cel(f)
|
||||||
|
local origCelFG = orig.layers[2]:cel(f)
|
||||||
|
local celBG = bg.layers[1]:cel(f)
|
||||||
|
local celFG = fg.layers[1]:cel(f)
|
||||||
|
if origCelBG and celBG then
|
||||||
|
assert(origCelBG.image:isEqual(celBG.image))
|
||||||
|
else
|
||||||
|
local cleanImage = Image(celBG.image.spec)
|
||||||
|
cleanImage:clear()
|
||||||
|
assert(not origCelBG)
|
||||||
|
assert(celBG.image:isEqual(cleanImage))
|
||||||
|
end
|
||||||
|
if origCelFG and celFG then
|
||||||
|
assert(origCelFG.image:isEqual(celFG.image))
|
||||||
|
else
|
||||||
|
local cleanImage = Image(celFG.image.spec)
|
||||||
|
cleanImage:clear()
|
||||||
|
assert(not origCelFG)
|
||||||
|
assert(celFG.image:isEqual(cleanImage))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
|
||||||
|
# --save-as without path
|
||||||
|
# https://github.com/aseprite/aseprite/issues/591
|
||||||
|
|
||||||
|
d=$t/save-as-without-path
|
||||||
|
mkdir $d
|
||||||
|
oldwd=$(pwd $PWDARG)
|
||||||
|
cd $d
|
||||||
|
$ASEPRITE -b -split-layers $oldwd/sprites/abcd.aseprite -save-as issue591.png || exit 1
|
||||||
|
if [[ ! -f "issue591 (a).png" ||
|
||||||
|
! -f "issue591 (b).png" ||
|
||||||
|
! -f "issue591 (c).png" ||
|
||||||
|
! -f "issue591 (d).png" ]]; then
|
||||||
|
echo "FAIL: Regression detected (issue 591)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cd $oldwd
|
||||||
|
|
||||||
|
# --save-as group without showing hidden children
|
||||||
|
# https://github.com/aseprite/aseprite/issues/2084#issuecomment-525835889
|
||||||
|
|
||||||
|
if [[ "$(uname)" =~ "MINGW" ]] || [[ "$(uname)" =~ "MSYS" ]] ; then
|
||||||
|
# Ignore this test on Windows because we cannot give * as a parameter (?)
|
||||||
|
echo Do nothing
|
||||||
|
else
|
||||||
|
d=$t/save-as-groups-and-hidden
|
||||||
|
mkdir $d
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer \* -save-as "$d/g2-all.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer \* -ignore-layer items -save-as "$d/g2-all-without-items.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer \* -ignore-layer gun -save-as "$d/g2-all-without-gun1.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer \* -ignore-layer sword -save-as "$d/g2-all-without-sword1.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer \* -ignore-layer items/gun -save-as "$d/g2-all-without-gun2.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer \* -ignore-layer items/sword -save-as "$d/g2-all-without-sword2.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer \* -ignore-layer player -save-as "$d/g2-all-without-player.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer player -save-as "$d/g2-player.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer items -save-as "$d/g2-items.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer items/\* -save-as "$d/g2-items-all.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer sword -save-as "$d/g2-sword.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups2.aseprite -layer gun -save-as "$d/g2-gun.png" || exit 1
|
||||||
|
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer a -save-as "$d/g3-a.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer b -save-as "$d/g3-b.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer c -save-as "$d/g3-c.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer a/\* -save-as "$d/g3-a-all.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer b/\* -save-as "$d/g3-b-all.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer c/\* -save-as "$d/g3-c-all.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer a/a -save-as "$d/g3-aa.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer b/a -save-as "$d/g3-ba.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer c/a -save-as "$d/g3-ca.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer a/b -save-as "$d/g3-ab.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer b/b -save-as "$d/g3-bb.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer c/b -save-as "$d/g3-cb.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer a/c -save-as "$d/g3-ac.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer b/c -save-as "$d/g3-bc.png" || exit 1
|
||||||
|
$ASEPRITE -b sprites/groups3abc.aseprite -layer c/c -save-as "$d/g3-cc.png" || exit 1
|
||||||
|
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
dofile('scripts/test_utils.lua')
|
||||||
|
|
||||||
|
local g2 = app.open("sprites/groups2.aseprite")
|
||||||
|
local g3 = app.open("sprites/groups3abc.aseprite")
|
||||||
|
|
||||||
|
function img(name)
|
||||||
|
local i = Image{ fromFile="$d/" .. name .. ".png" }
|
||||||
|
if not i then error('file ' .. name .. '.png does not exist') end
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
|
||||||
|
expect_rendered_layers(img("g2-all"), g2, { "items/gun", "items/sword", "player/head", "player/body" })
|
||||||
|
expect_rendered_layers(img("g2-all-without-items"), g2, { "player/head", "player/body" })
|
||||||
|
expect_rendered_layers(img("g2-all-without-gun1"), g2, { "items/sword", "player/head", "player/body" })
|
||||||
|
expect_rendered_layers(img("g2-all-without-gun2"), g2, { "items/sword", "player/head", "player/body" })
|
||||||
|
expect_rendered_layers(img("g2-all-without-sword1"), g2, { "items/gun", "player/head", "player/body" })
|
||||||
|
expect_rendered_layers(img("g2-all-without-sword2"), g2, { "items/gun", "player/head", "player/body" })
|
||||||
|
expect_rendered_layers(img("g2-player"), g2, { "player/head", "player/body" })
|
||||||
|
expect_rendered_layers(img("g2-items"), g2, { "items/sword" })
|
||||||
|
expect_rendered_layers(img("g2-items-all"), g2, { "items/gun", "items/sword" })
|
||||||
|
expect_rendered_layers(img("g2-sword"), g2, { "items/sword" })
|
||||||
|
expect_rendered_layers(img("g2-gun"), g2, { "items/gun" })
|
||||||
|
|
||||||
|
expect_rendered_layers(img("g3-a"), g3, { "a/a", "a/b", "a/c" })
|
||||||
|
expect_rendered_layers(img("g3-b"), g3, { "b/a", "b/c" })
|
||||||
|
expect_rendered_layers(img("g3-c"), g3, { "c/c" })
|
||||||
|
expect_rendered_layers(img("g3-a-all"), g3, { "a/a", "a/b", "a/c" })
|
||||||
|
expect_rendered_layers(img("g3-b-all"), g3, { "b/a", "b/b", "b/c" })
|
||||||
|
expect_rendered_layers(img("g3-c-all"), g3, { "c/a", "c/b", "c/c" })
|
||||||
|
expect_rendered_layers(img("g3-aa"), g3, { "a/a" })
|
||||||
|
expect_rendered_layers(img("g3-ab"), g3, { "a/b" })
|
||||||
|
expect_rendered_layers(img("g3-ac"), g3, { "a/c" })
|
||||||
|
expect_rendered_layers(img("g3-ba"), g3, { "b/a" })
|
||||||
|
expect_rendered_layers(img("g3-bb"), g3, { "b/b" })
|
||||||
|
expect_rendered_layers(img("g3-bc"), g3, { "b/c" })
|
||||||
|
expect_rendered_layers(img("g3-ca"), g3, { "c/a" })
|
||||||
|
expect_rendered_layers(img("g3-cb"), g3, { "c/b" })
|
||||||
|
expect_rendered_layers(img("g3-cc"), g3, { "c/c" })
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
fi
|
402
tests/cli/sheet.sh
Normal file
402
tests/cli/sheet.sh
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
|
|
||||||
|
# $1 = first sprite sheet json file
|
||||||
|
# $2 = second sprite sheet json file
|
||||||
|
function compare_sheet_data() {
|
||||||
|
cat $1 | grep -v "\"image\"" > $1-tmp
|
||||||
|
cat $2 | grep -v "\"image\"" > $2-tmp
|
||||||
|
diff -u $1-tmp $2-tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
# --sheet and STDOUT
|
||||||
|
|
||||||
|
d=$t/sheet
|
||||||
|
mkdir $d # we need to create the directory because the >STDOUT redirection
|
||||||
|
if ! $ASEPRITE -b sprites/1empty3.aseprite --sheet "$d/sheet.png" > "$d/stdout.json" ; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local json = dofile('third_party/json/json.lua')
|
||||||
|
local data = json.decode(io.open('$d/stdout.json'):read('a'))
|
||||||
|
local frames = { data.frames['1empty3 0.aseprite'],
|
||||||
|
data.frames['1empty3 1.aseprite'],
|
||||||
|
data.frames['1empty3 2.aseprite'] }
|
||||||
|
assert(frames[1].frame.x == 0)
|
||||||
|
assert(frames[2].frame.x == 32)
|
||||||
|
assert(frames[3].frame.x == 64)
|
||||||
|
for i,v in ipairs(frames) do
|
||||||
|
assert(v.frame.y == 0)
|
||||||
|
assert(v.frame.w == 32)
|
||||||
|
assert(v.frame.h == 32)
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
|
||||||
|
# --sheet --data
|
||||||
|
|
||||||
|
d0=$d
|
||||||
|
d=$t/sheet-data
|
||||||
|
$ASEPRITE -b sprites/1empty3.aseprite --sheet "$d/sheet.png" --data "$d/sheet.json" || exit 1
|
||||||
|
compare_sheet_data $d0/stdout.json $d/sheet.json || exit 1
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local orig = app.open("sprites/1empty3.aseprite")
|
||||||
|
local sheet = app.open("$d/sheet.png")
|
||||||
|
local expected = Image(orig.width*3, orig.height, orig.colorMode)
|
||||||
|
expected:clear()
|
||||||
|
for f = 1,3 do
|
||||||
|
expected:drawSprite(orig, f, (f-1)*orig.width, 0)
|
||||||
|
end
|
||||||
|
assert(expected:isEqual(sheet.cels[1].image))
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
|
||||||
|
# vertical sprite sheet
|
||||||
|
|
||||||
|
d=$t/vertical-sheet
|
||||||
|
mkdir $d
|
||||||
|
# TODO this should be possible in a future
|
||||||
|
# $ASEPRITE -b sprites/1empty3.aseprite -sheet-type vertical --sheet "$d/sheet.png" --data "$d/sheet.json" || exit 1
|
||||||
|
cat >$d/create.lua <<EOF
|
||||||
|
local sprite = app.open("sprites/1empty3.aseprite")
|
||||||
|
app.command.ExportSpriteSheet {
|
||||||
|
type="vertical",
|
||||||
|
textureFilename="$d/sheet1.png",
|
||||||
|
dataFilename="$d/sheet1.json"
|
||||||
|
}
|
||||||
|
app.command.ExportSpriteSheet {
|
||||||
|
type=SpriteSheetType.VERTICAL,
|
||||||
|
textureFilename="$d/sheet2.png",
|
||||||
|
dataFilename="$d/sheet2.json"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/create.lua" || exit 1
|
||||||
|
compare_sheet_data "$d/sheet1.json" "$d/sheet2.json" || exit 1
|
||||||
|
cmp "$d/sheet1.png" "$d/sheet2.png" || exit 1
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local orig = app.open("sprites/1empty3.aseprite")
|
||||||
|
local sheet = app.open("$d/sheet1.png")
|
||||||
|
local expected = Image(orig.width, orig.height*3, orig.colorMode)
|
||||||
|
expected:clear()
|
||||||
|
for f = 1,3 do
|
||||||
|
expected:drawSprite(orig, f, 0, (f-1)*orig.height)
|
||||||
|
end
|
||||||
|
assert(expected:isEqual(sheet.cels[1].image))
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
|
||||||
|
# --split-layers --sheet --data
|
||||||
|
|
||||||
|
d=$t/split-layers-sheet-data
|
||||||
|
$ASEPRITE -b --split-layers sprites/1empty3.aseprite \
|
||||||
|
--filename-format "{layer}-{frame}" \
|
||||||
|
--sheet "$d/sheet.png" \
|
||||||
|
--data "$d/sheet.json" || exit 1
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local json = dofile('third_party/json/json.lua')
|
||||||
|
local data = json.decode(io.open('$d/sheet.json'):read('a'))
|
||||||
|
assert(data.meta.size.w == 96)
|
||||||
|
assert(data.meta.size.h == 64)
|
||||||
|
|
||||||
|
local orig = app.open("sprites/1empty3.aseprite")
|
||||||
|
local sheet = app.open("$d/sheet.png")
|
||||||
|
local expected = Image(orig.width*3, orig.height*2, orig.colorMode)
|
||||||
|
expected:clear()
|
||||||
|
for lay = 1,2 do
|
||||||
|
orig.layers[1].isVisible = (lay == 1)
|
||||||
|
orig.layers[2].isVisible = (lay == 2)
|
||||||
|
for frm = 1,3 do
|
||||||
|
local x, y = (frm-1)*orig.width, (lay-1)*orig.height
|
||||||
|
expected:drawSprite(orig, frm, x, y)
|
||||||
|
|
||||||
|
local frmData = data.frames[orig.layers[lay].name .. '-' .. (frm-1)]
|
||||||
|
assert(frmData.frame.x == x)
|
||||||
|
assert(frmData.frame.y == y)
|
||||||
|
assert(frmData.frame.w == 32)
|
||||||
|
assert(frmData.frame.h == 32)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(expected:isEqual(sheet.cels[1].image))
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
|
||||||
|
# Test that the transparent color persists in the output sheet
|
||||||
|
|
||||||
|
d=$t/sheet-custom-transparent-index
|
||||||
|
if ! $ASEPRITE -b sprites/bg-index-3.aseprite -sheet "$d/sheet.aseprite" -data "$d/sheet.json" ; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local original = Sprite{ fromFile='sprites/bg-index-3.aseprite' }
|
||||||
|
assert(original.transparentColor == 3)
|
||||||
|
local sheet = Sprite{ fromFile='$d/sheet.aseprite' }
|
||||||
|
assert(sheet.transparentColor == 3)
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
|
||||||
|
# Don't discard empty frames if -ignore-empty is not used (even if -trim is used)
|
||||||
|
# https://github.com/aseprite/aseprite/issues/2116
|
||||||
|
# -layer -trim -ignore-empty -list-tags -sheet -data
|
||||||
|
|
||||||
|
d=$t/sheet-trim-without-ignore-empty
|
||||||
|
$ASEPRITE -b \
|
||||||
|
-list-tags \
|
||||||
|
-layer "c" \
|
||||||
|
"sprites/tags3.aseprite" \
|
||||||
|
-trim \
|
||||||
|
-sheet-pack \
|
||||||
|
-sheet "$d/sheet1.png" \
|
||||||
|
-format json-array \
|
||||||
|
-data "$d/sheet1.json" || exit 1
|
||||||
|
$ASEPRITE -b \
|
||||||
|
-list-tags \
|
||||||
|
-layer "c" \
|
||||||
|
"sprites/tags3.aseprite" \
|
||||||
|
-trim -ignore-empty \
|
||||||
|
-sheet-pack \
|
||||||
|
-sheet "$d/sheet2.png" \
|
||||||
|
-format json-array \
|
||||||
|
-data "$d/sheet2.json" || exit 1
|
||||||
|
|
||||||
|
cat >$d/check.lua <<EOF
|
||||||
|
local json = dofile('third_party/json/json.lua')
|
||||||
|
local sheet1 = json.decode(io.open('$d/sheet1.json'):read('a'))
|
||||||
|
local sheet2 = json.decode(io.open('$d/sheet2.json'):read('a'))
|
||||||
|
assert(#sheet1.frames == 12)
|
||||||
|
assert(#sheet2.frames == 4)
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/check.lua" || exit 1
|
||||||
|
|
||||||
|
# -sheet -sheet-columns vs -sheet-rows
|
||||||
|
|
||||||
|
d=$t/sheet-columns-and-rows
|
||||||
|
$ASEPRITE -b -split-layers sprites/1empty3.aseprite \
|
||||||
|
-filename-format "{layer}{frame}" \
|
||||||
|
-sheet "$d/sheet1.png" \
|
||||||
|
-sheet-type rows \
|
||||||
|
-sheet-columns 3 \
|
||||||
|
-data "$d/sheet1.json" || exit $?
|
||||||
|
$ASEPRITE -b -split-layers sprites/1empty3.aseprite \
|
||||||
|
-filename-format "{layer}{frame}" \
|
||||||
|
-sheet "$d/sheet2.png" \
|
||||||
|
-sheet-type columns \
|
||||||
|
-sheet-rows 3 \
|
||||||
|
-data "$d/sheet2.json" || exit $?
|
||||||
|
$ASEPRITE -b \
|
||||||
|
-script-param file1=$d/sheet1.json \
|
||||||
|
-script-param file2=$d/sheet2.json \
|
||||||
|
-script scripts/compare_sprite_sheets.lua || exit $?
|
||||||
|
|
||||||
|
# -sheet -trim vs -trim-sprite
|
||||||
|
|
||||||
|
d=$t/sheet-columns-and-rows
|
||||||
|
$ASEPRITE -b -split-layers sprites/1empty3.aseprite \
|
||||||
|
-trim \
|
||||||
|
-filename-format "{layer}{frame}" \
|
||||||
|
-sheet "$d/sheet1.png" \
|
||||||
|
-data "$d/sheet1.json" || exit $?
|
||||||
|
|
||||||
|
$ASEPRITE -b -split-layers sprites/1empty3.aseprite \
|
||||||
|
-trim-sprite \
|
||||||
|
-filename-format "{layer}{frame}" \
|
||||||
|
-sheet "$d/sheet2.png" \
|
||||||
|
-data "$d/sheet2.json" || exit $?
|
||||||
|
$ASEPRITE -b \
|
||||||
|
-script-param file1=$d/sheet1.json \
|
||||||
|
-script-param file2=$d/sheet2.json \
|
||||||
|
-script scripts/compare_sprite_sheets.lua || exit $?
|
||||||
|
|
||||||
|
# Test all sprite sheet types
|
||||||
|
# -sheet horizontal/vertical/rows/columns/packed
|
||||||
|
d=$t/sheet-all-types
|
||||||
|
for type in horizontal vertical rows columns packed ; do
|
||||||
|
$ASEPRITE -b "sprites/tags3.aseprite" \
|
||||||
|
-sheet-type $type -sheet "$d/$type.png" \
|
||||||
|
-format json-array -data "$d/$type.json" || exit $?
|
||||||
|
|
||||||
|
$ASEPRITE -b -split-layers "sprites/tags3.aseprite" \
|
||||||
|
-sheet-type $type -sheet "$d/$type-layers.png" \
|
||||||
|
-format json-array -data "$d/$type-layers.json" || exit $?
|
||||||
|
|
||||||
|
$ASEPRITE -b -split-layers -merge-duplicates "sprites/tags3.aseprite" \
|
||||||
|
-sheet-type $type -sheet "$d/$type-layers-merge-duplicates.png" \
|
||||||
|
-format json-array -data "$d/$type-layers-merge-duplicates.json" || exit $?
|
||||||
|
|
||||||
|
$ASEPRITE -b -split-tags "sprites/tags3.aseprite" \
|
||||||
|
-sheet-type $type -sheet "$d/$type-tags.png" \
|
||||||
|
-format json-array -data "$d/$type-tags.json" || exit $?
|
||||||
|
|
||||||
|
$ASEPRITE -b -split-tags -trim "sprites/tags3.aseprite" \
|
||||||
|
-sheet-type $type -sheet "$d/$type-tags-trim.png" \
|
||||||
|
-format json-array -data "$d/$type-tags-trim.json" || exit $?
|
||||||
|
|
||||||
|
$ASEPRITE -b -split-layers -split-tags "sprites/tags3.aseprite" \
|
||||||
|
-sheet-type $type -sheet "$d/$type-layer-tags.png" \
|
||||||
|
-format json-array -data "$d/$type-layer-tags.json" || exit $?
|
||||||
|
done
|
||||||
|
|
||||||
|
for type in horizontal vertical rows columns ; do
|
||||||
|
for subtype in "" "-layers" "-layers-merge-duplicates" "-tags" "-tags-trim" "-layer-tags" ; do
|
||||||
|
$ASEPRITE -b \
|
||||||
|
-script-param file1=$d/packed$subtype.json \
|
||||||
|
-script-param file2=$d/$type$subtype.json \
|
||||||
|
-script scripts/compare_sprite_sheets.lua || exit $?
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# "Trim Cels" (-trim) with -merge-duplicates didn't generate the
|
||||||
|
# correct "spriteSourceSize" for each frame.
|
||||||
|
# https://igarastudio.zendesk.com/agent/tickets/407
|
||||||
|
d=$t/ticket-407
|
||||||
|
for layer in a b ; do
|
||||||
|
$ASEPRITE -b -layer "$layer" "sprites/point4frames.aseprite" \
|
||||||
|
-trim \
|
||||||
|
-data "$d/data1-$layer.json" \
|
||||||
|
-format json-array -sheet "$d/sheet1-$layer.png" || exit 1
|
||||||
|
$ASEPRITE -b -layer "$layer" "sprites/point4frames.aseprite" \
|
||||||
|
-trim -merge-duplicates \
|
||||||
|
-data "$d/data2-$layer.json" \
|
||||||
|
-format json-array -sheet "$d/sheet2-$layer.png" || exit 1
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local json = dofile('third_party/json/json.lua')
|
||||||
|
local data1 = json.decode(io.open('$d/data1-$layer.json'):read('a'))
|
||||||
|
local data2 = json.decode(io.open('$d/data2-$layer.json'):read('a'))
|
||||||
|
assert(#data1.frames == #data2.frames)
|
||||||
|
for i = 1,#data1.frames do
|
||||||
|
local a = data1.frames[i].spriteSourceSize
|
||||||
|
local b = data2.frames[i].spriteSourceSize
|
||||||
|
assert(a.x == b.x)
|
||||||
|
assert(a.y == b.y)
|
||||||
|
assert(a.w == b.w)
|
||||||
|
assert(a.h == b.h)
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Same problem as in ticket 407 but with "sourceSize" field and
|
||||||
|
# different sprites in the same texture atlas.
|
||||||
|
d=$t/ticket-407-w-atlas
|
||||||
|
$ASEPRITE -b \
|
||||||
|
-layer a "sprites/point4frames.aseprite" \
|
||||||
|
"sprites/point2frames.aseprite" \
|
||||||
|
-data "$d/data1.json" \
|
||||||
|
-format json-array -sheet "$d/sheet1.png" || exit 1
|
||||||
|
$ASEPRITE -b \
|
||||||
|
-layer a "sprites/point4frames.aseprite" \
|
||||||
|
"sprites/point2frames.aseprite" \
|
||||||
|
-trim \
|
||||||
|
-data "$d/data2.json" \
|
||||||
|
-format json-array -sheet-pack -sheet "$d/sheet2.png" || exit 1
|
||||||
|
cat >$d/compare.lua <<EOF
|
||||||
|
local json = dofile('third_party/json/json.lua')
|
||||||
|
local data1 = json.decode(io.open('$d/data1.json'):read('a'))
|
||||||
|
local data2 = json.decode(io.open('$d/data2.json'):read('a'))
|
||||||
|
assert(#data1.frames == #data2.frames)
|
||||||
|
for i = 1,#data1.frames do
|
||||||
|
local a = data1.frames[i].sourceSize
|
||||||
|
local b = data2.frames[i].sourceSize
|
||||||
|
assert(a.w == b.w)
|
||||||
|
assert(a.h == b.h)
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/compare.lua" || exit 1
|
||||||
|
|
||||||
|
# https://github.com/aseprite/aseprite/issues/2380
|
||||||
|
# Check that -split-layers and -list-layers include group information
|
||||||
|
d=$t/issue-2380
|
||||||
|
$ASEPRITE -b -trim -all-layers "sprites/groups3abc.aseprite" -data "$d/sheet1.json" -format json-array -sheet "$d/sheet1.png" -list-layers
|
||||||
|
$ASEPRITE -b -trim -all-layers -split-layers "sprites/groups3abc.aseprite" -data "$d/sheet2.json" -format json-array -sheet "$d/sheet2.png" -list-layers
|
||||||
|
cat >$d/check.lua <<EOF
|
||||||
|
local json = dofile('third_party/json/json.lua')
|
||||||
|
local sheet1 = json.decode(io.open('$d/sheet1.json'):read('a'))
|
||||||
|
local sheet2 = json.decode(io.open('$d/sheet2.json'):read('a'))
|
||||||
|
assert(#sheet1.meta.layers == 12)
|
||||||
|
assert(#sheet2.meta.layers == 12)
|
||||||
|
assert(json.encode(sheet1.meta.layers) == json.encode(sheet2.meta.layers))
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/check.lua" || exit 1
|
||||||
|
|
||||||
|
# https://github.com/aseprite/aseprite/issues/2432
|
||||||
|
# -ignore-layer is ignoring extra layers when -split-layers is used
|
||||||
|
d=$t/issue-2432
|
||||||
|
$ASEPRITE -b -trim -ignore-layer "c" -all-layers "sprites/groups3abc.aseprite" -data "$d/sheet1.json" -format json-array -sheet "$d/sheet1.png" -list-layers
|
||||||
|
$ASEPRITE -b -trim -ignore-layer "c" -all-layers -split-layers "sprites/groups3abc.aseprite" -data "$d/sheet2.json" -format json-array -sheet "$d/sheet2.png" -list-layers
|
||||||
|
cat >$d/check.lua <<EOF
|
||||||
|
local json = dofile('third_party/json/json.lua')
|
||||||
|
local sheet1 = json.decode(io.open('$d/sheet1.json'):read('a'))
|
||||||
|
local sheet2 = json.decode(io.open('$d/sheet2.json'):read('a'))
|
||||||
|
assert(#sheet1.meta.layers == 8)
|
||||||
|
assert(#sheet2.meta.layers == 8)
|
||||||
|
assert(json.encode(sheet1.meta.layers) == json.encode(sheet2.meta.layers))
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/check.lua" || exit 1
|
||||||
|
|
||||||
|
# https://github.com/aseprite/aseprite/issues/2600
|
||||||
|
# -merge-duplicates -split-layers -trim give incorrect 'frame' coordinates on linked cels
|
||||||
|
d=$t/issue-2600
|
||||||
|
$ASEPRITE -b -list-layers -format json-array -trim -merge-duplicates -split-layers -all-layers "sprites/link.aseprite" -data "$d/sheet.json" -sheet "$d/sheet.png"
|
||||||
|
cat >$d/check.lua <<EOF
|
||||||
|
local json = dofile('third_party/json/json.lua')
|
||||||
|
local sheet = json.decode(io.open('$d/sheet.json'):read('a'))
|
||||||
|
local restoredSprite = Sprite(sheet.frames[1].sourceSize.w, sheet.frames[1].sourceSize.h, ColorMode.RGB)
|
||||||
|
local spriteSheet = Image{ fromFile="$d/sheet.png" }
|
||||||
|
local lay = 1
|
||||||
|
repeat
|
||||||
|
local layerName = sheet.meta.layers[lay].name
|
||||||
|
local layer = restoredSprite.layers[lay]
|
||||||
|
for i=1, #sheet.frames do
|
||||||
|
if string.find(sheet.frames[i].filename, layerName) ~= nil then
|
||||||
|
local sample = sheet.frames[i]
|
||||||
|
local dotAseIndex = string.find(sample.filename, ".ase")
|
||||||
|
local frame = (string.sub(sample.filename, dotAseIndex - 2, dotAseIndex - 1)) + 1
|
||||||
|
for f=#restoredSprite.frames, frame-1 do
|
||||||
|
restoredSprite:newEmptyFrame()
|
||||||
|
end
|
||||||
|
local image = Image(sample.frame.w, sample.frame.h)
|
||||||
|
for y=0,image.height-1 do
|
||||||
|
for x=0,image.width-1 do
|
||||||
|
image:drawPixel(x, y, spriteSheet:getPixel(sample.frame.x + x, sample.frame.y + y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
restoredSprite:newCel(layer, frame, image, Point(sample.spriteSourceSize.x, sample.spriteSourceSize.y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if lay < #sheet.meta.layers then
|
||||||
|
restoredSprite:newLayer()
|
||||||
|
end
|
||||||
|
lay = lay + 1
|
||||||
|
until(lay > #sheet.meta.layers)
|
||||||
|
|
||||||
|
app.activeSprite = restoredSprite
|
||||||
|
app.activeLayer = restoredSprite.layers[#restoredSprite.layers]
|
||||||
|
for i=1,#restoredSprite.layers-1 do
|
||||||
|
app.command.MergeDownLayer()
|
||||||
|
end
|
||||||
|
|
||||||
|
local orig = app.open("sprites/link.aseprite")
|
||||||
|
app.activeSprite = orig
|
||||||
|
app.activeLayer = orig.layers[#orig.layers]
|
||||||
|
for i=1,#orig.layers-1 do
|
||||||
|
app.command.MergeDownLayer()
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(orig.width == restoredSprite.width)
|
||||||
|
assert(orig.height == restoredSprite.height)
|
||||||
|
assert(#orig.frames == #restoredSprite.frames)
|
||||||
|
for fr=1,#restoredSprite.frames do
|
||||||
|
for celIndex1=1,#restoredSprite.cels do
|
||||||
|
if restoredSprite.cels[celIndex1].frameNumber == fr then
|
||||||
|
for celIndex2=1,#orig.cels do
|
||||||
|
if orig.cels[celIndex2].frameNumber == fr then
|
||||||
|
assert(orig.cels[celIndex2].position == restoredSprite.cels[celIndex1].position)
|
||||||
|
if orig.cels[celIndex2].image ~= nil and restoredSprite.cels[celIndex1].image ~= nil then
|
||||||
|
assert(orig.cels[celIndex2].image:isEqual(restoredSprite.cels[celIndex1].image))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
$ASEPRITE -b -script "$d/check.lua" || exit 1
|
7
tests/cli/version.sh
Normal file
7
tests/cli/version.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Copyright (C) 2018 Igara Studio S.A.
|
||||||
|
|
||||||
|
if ! $ASEPRITE --version | grep "Aseprite 1\\." > /dev/null ; then
|
||||||
|
echo "FAILED: --version doesn't include 'Aseprite 1.' string"
|
||||||
|
exit 1
|
||||||
|
fi
|
107
tests/run-tests.sh
Executable file
107
tests/run-tests.sh
Executable file
@ -0,0 +1,107 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Copyright (C) 2018 Igara Studio S.A.
|
||||||
|
# Copyright (C) 2018 David Capello
|
||||||
|
|
||||||
|
if [[ "$ASEPRITE" == "" ]]; then
|
||||||
|
echo ASEPRITE env var must be pointing to the Aseprite executable
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
function fail() {
|
||||||
|
echo FAIL
|
||||||
|
echo $BASH_SOURCE:$BASH_LINENO: error: $*
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function expect() {
|
||||||
|
if [[ $1 != "$($2 | tr -d "\r")" ]] ; then
|
||||||
|
echo "FAILED: $2"
|
||||||
|
echo "EXPECTED: $1"
|
||||||
|
echo "RESULT: $($2)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# General information
|
||||||
|
echo ----------------------------------------------------------------------
|
||||||
|
echo $ASEPRITE --version
|
||||||
|
$ASEPRITE --version
|
||||||
|
|
||||||
|
filter="$*"
|
||||||
|
if [[ "$filter" != "" ]]; then
|
||||||
|
echo Filter: $filter
|
||||||
|
fi
|
||||||
|
|
||||||
|
t=$(mktemp -d)
|
||||||
|
if [[ "$(uname)" =~ "MINGW" ]] || [[ "$(uname)" =~ "MSYS" ]] ; then
|
||||||
|
PWDARG=-W
|
||||||
|
t=$(cd "$t" && pwd $PWDARG)
|
||||||
|
else
|
||||||
|
PWDARG=
|
||||||
|
fi
|
||||||
|
echo Temp dir: $t
|
||||||
|
export ASEPRITE_USER_FOLDER=$t
|
||||||
|
|
||||||
|
if [[ "$filter" == "" ]] || [[ "console" =~ $filter ]]; then
|
||||||
|
echo ----------------------------------------------------------------------
|
||||||
|
echo "Testing console..."
|
||||||
|
echo "uname=$(uname)"
|
||||||
|
|
||||||
|
$ASEPRITE -b --script scripts/console_assert.lua >$t/tmp 2>&1
|
||||||
|
! grep -q "this should be in the output" $t/tmp && fail "print() text not found in output"
|
||||||
|
! grep -q "assertion failed" $t/tmp && fail "assert() text not found in output"
|
||||||
|
grep -q "this should not be in the output" $t/tmp && fail "text that shouldn't be in the output is"
|
||||||
|
|
||||||
|
if [[ "$(uname)" =~ "MINGW" ]] || [[ "$(uname)" =~ "MSYS" ]] ; then
|
||||||
|
echo Ignore console tests on Windows
|
||||||
|
else
|
||||||
|
$ASEPRITE -b --script scripts/console_print.lua >$t/tmp 2>&1
|
||||||
|
cat >$t/tmp_expected <<EOF
|
||||||
|
hello world
|
||||||
|
1 2 3
|
||||||
|
EOF
|
||||||
|
! diff -u $t/tmp $t/tmp_expected && fail
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
first=0
|
||||||
|
result=0
|
||||||
|
for script in scripts/*.lua ; do
|
||||||
|
[[ $script =~ console ]] && continue
|
||||||
|
if [[ "$filter" != "" ]]; then
|
||||||
|
[[ $script =~ $filter ]] || continue
|
||||||
|
fi
|
||||||
|
if [ $first == 0 ]; then
|
||||||
|
echo ----------------------------------------------------------------------
|
||||||
|
echo "Testing scripts..."
|
||||||
|
first=1
|
||||||
|
fi
|
||||||
|
echo "Running $script"
|
||||||
|
if ! $ASEPRITE -b --script $script >$t/tmp 2>&1 ; then
|
||||||
|
echo FAILED && cat $t/tmp
|
||||||
|
result=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
first=0
|
||||||
|
for script in cli/*.sh ; do
|
||||||
|
if [[ "$filter" == "" ]] || [[ $script =~ $filter ]]; then
|
||||||
|
if [ $first == 0 ]; then
|
||||||
|
echo ----------------------------------------------------------------------
|
||||||
|
echo "Testing CLI..."
|
||||||
|
first=1
|
||||||
|
fi
|
||||||
|
echo "Running $script"
|
||||||
|
source $script
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ----------------------------------------------------------------------
|
||||||
|
if [ $result == 0 ] ; then
|
||||||
|
echo Done
|
||||||
|
else
|
||||||
|
echo FAILED
|
||||||
|
fi
|
||||||
|
echo ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
exit $result
|
25
tests/scripts/app_active.lua
Normal file
25
tests/scripts/app_active.lua
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
-- Copyright (C) 2018-2019 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local s = Sprite(32, 64)
|
||||||
|
assert(s == app.activeSprite)
|
||||||
|
assert(s == app.site.sprite)
|
||||||
|
assert(s == app.activeFrame.sprite)
|
||||||
|
assert(s == app.site.frame.sprite)
|
||||||
|
assert(1 == app.activeFrame.frameNumber)
|
||||||
|
assert(1 == app.site.frame.frameNumber)
|
||||||
|
assert(1 == app.site.frameNumber)
|
||||||
|
assert(0.100 == app.activeFrame.duration) -- Default frame duration
|
||||||
|
assert(0.100 == app.site.frame.duration)
|
||||||
|
assert(s == app.activeLayer.sprite)
|
||||||
|
assert(s == app.site.layer.sprite)
|
||||||
|
assert(s == app.activeCel.sprite)
|
||||||
|
assert(s == app.site.cel.sprite)
|
||||||
|
|
||||||
|
app.activeFrame.duration = 0.8
|
||||||
|
|
||||||
|
app.command.NewFrame()
|
||||||
|
assert(2 == app.activeFrame.frameNumber)
|
||||||
|
assert(0.8 == app.activeFrame.duration) -- Copy frame duration of previous frame
|
606
tests/scripts/app_command.lua
Normal file
606
tests/scripts/app_command.lua
Normal file
@ -0,0 +1,606 @@
|
|||||||
|
-- Copyright (C) 2019-2020 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
dofile('./test_utils.lua')
|
||||||
|
|
||||||
|
local rgba = app.pixelColor.rgba
|
||||||
|
local rgbaR = app.pixelColor.rgbaR
|
||||||
|
local rgbaG = app.pixelColor.rgbaG
|
||||||
|
local rgbaB = app.pixelColor.rgbaB
|
||||||
|
|
||||||
|
do -- Undo/Redo commands (like app.undo/redo())
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(s.width == 32)
|
||||||
|
assert(s.height == 32)
|
||||||
|
|
||||||
|
s:resize(50, 40)
|
||||||
|
assert(s.width == 50)
|
||||||
|
assert(s.height == 40)
|
||||||
|
|
||||||
|
app.command.Undo()
|
||||||
|
assert(s.width == 32)
|
||||||
|
assert(s.height == 32)
|
||||||
|
|
||||||
|
app.command.Redo()
|
||||||
|
assert(s.width == 50)
|
||||||
|
assert(s.height == 40)
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- NewSprite
|
||||||
|
local s1 = app.activeSprite
|
||||||
|
app.command.NewFile{ }
|
||||||
|
assert(s1 == app.activeSprite)
|
||||||
|
app.command.NewFile{ width=256, height=128, colorMode=ColorMode.INDEXED }
|
||||||
|
local s2 = app.activeSprite
|
||||||
|
assert(s1 ~= s2)
|
||||||
|
assert(s2.width == 256)
|
||||||
|
assert(s2.height == 128)
|
||||||
|
assert(s2.colorMode == ColorMode.INDEXED)
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- ExportSpriteSheet
|
||||||
|
local s = Sprite{ fromFile="sprites/2f-index-3x3.aseprite" }
|
||||||
|
app.command.ExportSpriteSheet {
|
||||||
|
type="horizontal",
|
||||||
|
textureFilename="_test_export_spritesheet1.png",
|
||||||
|
shapePadding=1
|
||||||
|
}
|
||||||
|
local i = Image{ fromFile="_test_export_spritesheet1.png" }
|
||||||
|
expect_img(i, {
|
||||||
|
11,8,11,21,8,11,11,
|
||||||
|
11,8,11,21,11,8,11,
|
||||||
|
11,8,11,21,11,11,8,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- NewLayer/RemoveLayer
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(#s.layers == 1)
|
||||||
|
local lay = s.layers[1]
|
||||||
|
app.command.NewLayer{top=true}
|
||||||
|
local lay2 = app.activeLayer
|
||||||
|
assert(#s.layers == 2)
|
||||||
|
assert(s.layers[2].isImage)
|
||||||
|
|
||||||
|
app.command.NewLayer{top=true, group=true}
|
||||||
|
local lay3 = app.activeLayer
|
||||||
|
assert(#s.layers == 3)
|
||||||
|
assert(s.layers[3].isGroup)
|
||||||
|
|
||||||
|
assert(app.activeLayer == lay3)
|
||||||
|
app.command.RemoveLayer()
|
||||||
|
assert(app.activeLayer == lay2)
|
||||||
|
assert(#s.layers == 2)
|
||||||
|
|
||||||
|
app.command.RemoveLayer()
|
||||||
|
assert(app.activeLayer == lay)
|
||||||
|
assert(#s.layers == 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Background/Transparent layers
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(s.layers[1].isTransparent)
|
||||||
|
assert(s.cels[1].image:getPixel(0, 0) == app.pixelColor.rgba(0, 0, 0, 0))
|
||||||
|
|
||||||
|
app.bgColor = Color(32, 64, 128)
|
||||||
|
app.command.BackgroundFromLayer() -- the layer will be filled with app.bgColor
|
||||||
|
assert(s.layers[1].isBackground)
|
||||||
|
assert(s.layers[1] == s.backgroundLayer)
|
||||||
|
assert(s.cels[1].image:getPixel(0, 0) == app.pixelColor.rgba(32, 64, 128, 255))
|
||||||
|
|
||||||
|
app.command.LayerFromBackground()
|
||||||
|
assert(s.layers[1].isTransparent)
|
||||||
|
assert(s.cels[1].image:getPixel(0, 0) == app.pixelColor.rgba(32, 64, 128, 255))
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Crop and Trim
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
s.selection:select(4, 5, 8, 10)
|
||||||
|
assert(s.cels[1].bounds == Rectangle(0, 0, 32, 32))
|
||||||
|
|
||||||
|
-- Crop
|
||||||
|
|
||||||
|
app.command.CropSprite()
|
||||||
|
assert(s.width == 8)
|
||||||
|
assert(s.height == 10)
|
||||||
|
assert(s.cels[1].bounds == Rectangle(-4, -5, 32, 32))
|
||||||
|
|
||||||
|
-- Autocrop (Trim)
|
||||||
|
|
||||||
|
app.command.AutocropSprite() -- Trim does nothing when we should remove all pixels
|
||||||
|
assert(s.width == 8)
|
||||||
|
assert(s.height == 10)
|
||||||
|
|
||||||
|
s.cels[1].image:putPixel(5, 5, Color(255, 0, 0))
|
||||||
|
s.cels[1].image:putPixel(4, 6, Color(255, 0, 0))
|
||||||
|
app.command.AutocropSprite()
|
||||||
|
assert(s.width == 2)
|
||||||
|
assert(s.height == 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Cel Opacity
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
local c = s.cels[1]
|
||||||
|
assert(c.opacity == 255)
|
||||||
|
|
||||||
|
app.command.CelOpacity{opacity=128}
|
||||||
|
assert(c.opacity == 128)
|
||||||
|
|
||||||
|
s.cels[1].opacity = 255
|
||||||
|
assert(c.opacity == 255)
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
assert(c.opacity == 128)
|
||||||
|
app.undo()
|
||||||
|
assert(c.opacity == 255)
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- PaletteSize
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(#s.palettes[1] == 256)
|
||||||
|
app.command.PaletteSize{ size=32 }
|
||||||
|
assert(#s.palettes[1] == 32)
|
||||||
|
app.command.PaletteSize{ size=8 }
|
||||||
|
assert(#s.palettes[1] == 8)
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- CanvasSize
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(s.bounds == Rectangle(0, 0, 32, 32))
|
||||||
|
app.command.CanvasSize{ left=2 }
|
||||||
|
assert(s.bounds == Rectangle(0, 0, 34, 32))
|
||||||
|
app.command.CanvasSize{ top=2, right=4, bottom=8 }
|
||||||
|
assert(s.bounds == Rectangle(0, 0, 38, 42))
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- ReplaceColor
|
||||||
|
local s = Sprite(4, 4)
|
||||||
|
local cel = app.activeCel
|
||||||
|
local red = Color(255, 0, 0)
|
||||||
|
local yellow = Color(255, 255, 0)
|
||||||
|
local blue = Color(0, 0, 255)
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local y = yellow.rgbaPixel
|
||||||
|
local b = blue.rgbaPixel
|
||||||
|
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0 })
|
||||||
|
|
||||||
|
app.useTool{ brush=Brush(1), color=red, points={Point(1,1)} }
|
||||||
|
app.useTool{ brush=Brush(1), color=yellow, points={Point(2,2)} }
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 1, 2, 2))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ r, 0,
|
||||||
|
0, y })
|
||||||
|
|
||||||
|
app.command.ReplaceColor{ from=red, to=blue }
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 1, 2, 2))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ b, 0,
|
||||||
|
0, y })
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Invert
|
||||||
|
local s = Sprite(2, 2)
|
||||||
|
local cel = app.activeCel
|
||||||
|
local aa = Color(255, 128, 128).rgbaPixel
|
||||||
|
local na = Color(0, 127, 127).rgbaPixel
|
||||||
|
local bb = Color(128, 128, 255).rgbaPixel
|
||||||
|
local nb = Color(127, 127, 0).rgbaPixel
|
||||||
|
local i = cel.image
|
||||||
|
|
||||||
|
i:drawPixel(0, 0, aa)
|
||||||
|
i:drawPixel(1, 0, bb)
|
||||||
|
i:drawPixel(0, 1, bb)
|
||||||
|
i:drawPixel(1, 1, aa)
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ aa, bb,
|
||||||
|
bb, aa })
|
||||||
|
|
||||||
|
app.command.InvertColor()
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ na, nb,
|
||||||
|
nb, na })
|
||||||
|
|
||||||
|
local Na = Color(0, 127, 128).rgbaPixel
|
||||||
|
local Ng = Color(127, 127, 255).rgbaPixel
|
||||||
|
app.command.InvertColor{ channels=FilterChannels.BLUE }
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ Na, Ng,
|
||||||
|
Ng, Na })
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Outline
|
||||||
|
local s = Sprite(4, 4)
|
||||||
|
local cel = app.activeCel
|
||||||
|
local red = Color(255, 0, 0)
|
||||||
|
local yellow = Color(255, 255, 0)
|
||||||
|
local blue = Color(0, 0, 255)
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local y = yellow.rgbaPixel
|
||||||
|
local b = blue.rgbaPixel
|
||||||
|
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0 })
|
||||||
|
|
||||||
|
app.useTool{ brush=Brush(1), color=red, points={Point(1,1)} }
|
||||||
|
app.useTool{ brush=Brush(1), color=yellow, points={Point(2,2)} }
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 1, 2, 2))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ r, 0,
|
||||||
|
0, y })
|
||||||
|
|
||||||
|
app.command.Outline{ color=blue }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 0, b, 0, 0,
|
||||||
|
b, r, b, 0,
|
||||||
|
0, b, y, b,
|
||||||
|
0, 0, b, 0 })
|
||||||
|
|
||||||
|
-- Test "bgColor", "matrix", "place" params
|
||||||
|
|
||||||
|
app.useTool{ tool='filled_rectangle', brush=Brush(1), color=blue, points={Point(0,0), Point(3,3)} }
|
||||||
|
app.useTool{ tool='filled_rectangle', brush=Brush(1), color=yellow, points={Point(1,1), Point(2,2)} }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ b, b, b, b,
|
||||||
|
b, y, y, b,
|
||||||
|
b, y, y, b,
|
||||||
|
b, b, b, b })
|
||||||
|
|
||||||
|
app.command.Outline{ color=red, bgColor=blue, matrix='circle' }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ b, r, r, b,
|
||||||
|
r, y, y, r,
|
||||||
|
r, y, y, r,
|
||||||
|
b, r, r, b })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.command.Outline{ color=red, bgColor=blue, matrix='square' }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ r, r, r, r,
|
||||||
|
r, y, y, r,
|
||||||
|
r, y, y, r,
|
||||||
|
r, r, r, r })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.command.Outline{ color=red, bgColor=blue, place='inside' }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ b, b, b, b,
|
||||||
|
b, r, r, b,
|
||||||
|
b, r, r, b,
|
||||||
|
b, b, b, b })
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- BrightnessContrast
|
||||||
|
local s = Sprite(2, 2)
|
||||||
|
local cel = app.activeCel
|
||||||
|
local c = { rgba(255, 128, 64), rgba(250, 225, 110),
|
||||||
|
rgba( 30, 60, 0), rgba(200, 100, 50), }
|
||||||
|
local i = cel.image
|
||||||
|
|
||||||
|
i:drawPixel(0, 0, c[1])
|
||||||
|
i:drawPixel(1, 0, c[2])
|
||||||
|
i:drawPixel(0, 1, c[3])
|
||||||
|
i:drawPixel(1, 1, c[4])
|
||||||
|
expect_img(i,
|
||||||
|
{ c[1], c[2],
|
||||||
|
c[3], c[4] })
|
||||||
|
|
||||||
|
app.command.BrightnessContrast() -- Do nothing by default
|
||||||
|
expect_img(i,
|
||||||
|
{ c[1], c[2],
|
||||||
|
c[3], c[4] })
|
||||||
|
|
||||||
|
local d = {}
|
||||||
|
for k,v in ipairs(c) do
|
||||||
|
d[k] = rgba(math.min(255, rgbaR(v)*1.5),
|
||||||
|
math.min(255, rgbaG(v)*1.5),
|
||||||
|
math.min(255, rgbaB(v)*1.5), 255)
|
||||||
|
end
|
||||||
|
app.command.BrightnessContrast{ brightness=50 } -- Do nothing by default
|
||||||
|
expect_img(i,
|
||||||
|
{ d[1], d[2],
|
||||||
|
d[3], d[4] })
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Despeckle
|
||||||
|
local s = Sprite(5, 5)
|
||||||
|
local white = Color(255, 255, 255)
|
||||||
|
local red = Color(255, 0, 0)
|
||||||
|
|
||||||
|
app.bgColor = white
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
|
||||||
|
local cel = app.activeCel
|
||||||
|
local i = cel.image
|
||||||
|
local b = white.rgbaPixel
|
||||||
|
local c = red.rgbaPixel
|
||||||
|
expect_img(i,
|
||||||
|
{ b,b,b,b,b,
|
||||||
|
b,b,b,b,b,
|
||||||
|
b,b,b,b,b,
|
||||||
|
b,b,b,b,b,
|
||||||
|
b,b,b,b,b })
|
||||||
|
|
||||||
|
app.useTool{ tool='filled_rectangle', brush=Brush(1), color=red,
|
||||||
|
points={Point(1,1),Point(3,3)} }
|
||||||
|
expect_img(i,
|
||||||
|
{ b,b,b,b,b,
|
||||||
|
b,c,c,c,b,
|
||||||
|
b,c,c,c,b,
|
||||||
|
b,c,c,c,b,
|
||||||
|
b,b,b,b,b })
|
||||||
|
|
||||||
|
app.command.Despeckle()
|
||||||
|
expect_img(i,
|
||||||
|
{ b,b,b,b,b,
|
||||||
|
b,b,c,b,b,
|
||||||
|
b,c,c,c,b,
|
||||||
|
b,b,c,b,b,
|
||||||
|
b,b,b,b,b })
|
||||||
|
|
||||||
|
app.command.Despeckle()
|
||||||
|
expect_img(i,
|
||||||
|
{ b,b,b,b,b,
|
||||||
|
b,b,b,b,b,
|
||||||
|
b,b,c,b,b,
|
||||||
|
b,b,b,b,b,
|
||||||
|
b,b,b,b,b })
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- HueSaturation
|
||||||
|
local s = Sprite(1, 1)
|
||||||
|
local cel = app.activeCel
|
||||||
|
local i = cel.image
|
||||||
|
local b = Color(255, 0, 0).rgbaPixel
|
||||||
|
|
||||||
|
i:drawPixel(0, 0, b)
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
app.command.HueSaturation{ hue=360 } -- Do nothing (change hue to a full 360 circle)
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
app.command.HueSaturation{ hue=60 }
|
||||||
|
b = Color(255, 255, 0).rgbaPixel
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
app.command.HueSaturation{ hue=60 }
|
||||||
|
b = Color(0, 255, 0).rgbaPixel
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
app.command.HueSaturation{ saturation=-50 }
|
||||||
|
b = Color(64, 191, 64).rgbaPixel
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
app.command.HueSaturation{ saturation=-100 }
|
||||||
|
b = Color(128, 128, 128).rgbaPixel
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
app.command.HueSaturation{ saturation=-50, mode='hsv' }
|
||||||
|
b = Color(128, 255, 128).rgbaPixel
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
app.command.HueSaturation{ value=75 }
|
||||||
|
b = Color(191, 255, 191).rgbaPixel
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
app.command.HueSaturation{ alpha=-50 }
|
||||||
|
b = Color(0, 255, 0, 127).rgbaPixel
|
||||||
|
expect_img(i, { b })
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- ColorCurve
|
||||||
|
local s = Sprite(2, 1)
|
||||||
|
local cel = app.activeCel
|
||||||
|
local i = cel.image
|
||||||
|
|
||||||
|
i:drawPixel(0, 0, rgba(255, 128, 0))
|
||||||
|
i:drawPixel(1, 0, rgba(64, 0, 32))
|
||||||
|
expect_img(i, { rgba(255, 128, 0), rgba(64, 0, 32) })
|
||||||
|
|
||||||
|
app.command.ColorCurve() -- Do nothing
|
||||||
|
expect_img(i, { rgba(255, 128, 0), rgba(64, 0, 32) })
|
||||||
|
|
||||||
|
app.command.ColorCurve{ curve={{0,0},{255,128}} }
|
||||||
|
expect_img(i, { rgba(128, 64, 0), rgba(32, 0, 16) })
|
||||||
|
|
||||||
|
app.command.ColorCurve{ channels=FilterChannels.ALPHA, curve={{0,0},{255,128}} }
|
||||||
|
expect_img(i, { rgba(128, 64, 0, 128), rgba(32, 0, 16, 128) })
|
||||||
|
|
||||||
|
app.command.ColorCurve{ channels=FilterChannels.RGBA, curve={{0,255},{255,255}} }
|
||||||
|
expect_img(i, { rgba(255, 255, 255), rgba(255, 255, 255) })
|
||||||
|
|
||||||
|
app.command.ColorCurve{ channels=FilterChannels.GREEN, curve={{0,0},{255,0}} }
|
||||||
|
expect_img(i, { rgba(255, 0, 255), rgba(255, 0, 255) })
|
||||||
|
|
||||||
|
app.command.ColorCurve{ channels=FilterChannels.BLUE, curve="0,128,255,128" }
|
||||||
|
expect_img(i, { rgba(255, 0, 128), rgba(255, 0, 128) })
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- ConvolutionMatrix
|
||||||
|
local s = Sprite(3, 3)
|
||||||
|
local cel = app.activeCel
|
||||||
|
local i = cel.image
|
||||||
|
local b = rgba(0, 0, 0)
|
||||||
|
local w = rgba(255, 255, 255)
|
||||||
|
|
||||||
|
app.bgColor = Color(255, 255, 255)
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
i:drawPixel(1, 1, b)
|
||||||
|
expect_img(i, { w, w, w,
|
||||||
|
w, b, w,
|
||||||
|
w, w, w })
|
||||||
|
|
||||||
|
local u = rgba(239, 239, 239)
|
||||||
|
local v = rgba(223, 223, 223)
|
||||||
|
local w = rgba(191, 191, 191)
|
||||||
|
app.command.ConvolutionMatrix{ fromResource="blur-3x3" }
|
||||||
|
expect_img(i, { u, v, u,
|
||||||
|
v, w, v,
|
||||||
|
u, v, u })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- MoveColors and CopyColors
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32, ColorMode.INDEXED)
|
||||||
|
local p = Palette(4)
|
||||||
|
p:setColor(0, Color(0, 0, 0))
|
||||||
|
p:setColor(1, Color(255, 0, 0))
|
||||||
|
p:setColor(2, Color(0, 255, 0))
|
||||||
|
p:setColor(3, Color(0, 0, 255))
|
||||||
|
s:setPalette(p)
|
||||||
|
assert(#app.range.colors == 0)
|
||||||
|
app.range.colors = { 0, 2 }
|
||||||
|
assert(#app.range.colors == 2)
|
||||||
|
assert(app.range.colors[1] == 0)
|
||||||
|
assert(app.range.colors[2] == 2)
|
||||||
|
app.command.MoveColors{ before=0 }
|
||||||
|
p = s.palettes[1]
|
||||||
|
p:setColor(0, Color(0, 0, 0))
|
||||||
|
p:setColor(1, Color(0, 255, 0))
|
||||||
|
p:setColor(2, Color(255, 0, 0))
|
||||||
|
p:setColor(3, Color(0, 0, 255))
|
||||||
|
|
||||||
|
app.range.colors = { 0, 1 }
|
||||||
|
assert(#app.range.colors == 2)
|
||||||
|
assert(app.range.colors[1] == 0)
|
||||||
|
assert(app.range.colors[2] == 1)
|
||||||
|
app.command.CopyColors{ before=4 }
|
||||||
|
p = s.palettes[1]
|
||||||
|
p:setColor(0, Color(0, 0, 0))
|
||||||
|
p:setColor(1, Color(0, 255, 0))
|
||||||
|
p:setColor(2, Color(255, 0, 0))
|
||||||
|
p:setColor(3, Color(0, 0, 255))
|
||||||
|
p:setColor(4, Color(0, 0, 0))
|
||||||
|
p:setColor(5, Color(0, 255, 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- AddColor
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
local p = s.palettes[1]
|
||||||
|
|
||||||
|
function testAddColor(color)
|
||||||
|
assert(p:getColor(#p-1) ~= color)
|
||||||
|
app.command.AddColor{ color=color }
|
||||||
|
assert(p:getColor(#p-1) == color)
|
||||||
|
end
|
||||||
|
testAddColor(Color(255, 0, 0))
|
||||||
|
testAddColor(Color(0, 255, 0))
|
||||||
|
testAddColor(Color(0, 0, 255))
|
||||||
|
|
||||||
|
local color = Color(128, 0, 0)
|
||||||
|
app.preferences.color_bar.fg_color = color
|
||||||
|
app.command.AddColor{ source="fg" }
|
||||||
|
assert(p:getColor(#p-1) == color)
|
||||||
|
|
||||||
|
local color = Color(0, 0, 128)
|
||||||
|
app.preferences.color_bar.bg_color = color
|
||||||
|
app.command.AddColor{ source="bg" }
|
||||||
|
assert(p:getColor(#p-1) == color)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Flip
|
||||||
|
do
|
||||||
|
local s = Sprite(4, 2, ColorMode.INDEXED)
|
||||||
|
local i = s.cels[1].image
|
||||||
|
array_to_pixels({ 0, 1, 2, 3,
|
||||||
|
4, 5, 6, 7 }, i)
|
||||||
|
app.command.Flip{ orientation="horizontal" }
|
||||||
|
expect_img(i, { 3, 2, 1, 0,
|
||||||
|
7, 6, 5, 4 })
|
||||||
|
|
||||||
|
app.command.Flip{ orientation="vertical" }
|
||||||
|
expect_img(i, { 7, 6, 5, 4,
|
||||||
|
3, 2, 1, 0 })
|
||||||
|
|
||||||
|
s.selection:select{ 1, 0, 2, 2 }
|
||||||
|
app.command.Flip{ orientation="horizontal", target="mask" }
|
||||||
|
expect_img(i, { 7, 5, 6, 4,
|
||||||
|
3, 1, 2, 0 })
|
||||||
|
|
||||||
|
s:newFrame()
|
||||||
|
|
||||||
|
assert(app.activeCel.frameNumber == 2)
|
||||||
|
local j = app.activeImage
|
||||||
|
app.command.Flip{ orientation="vertical", target="mask" }
|
||||||
|
expect_img(i, { 7, 5, 6, 4,
|
||||||
|
3, 1, 2, 0 })
|
||||||
|
expect_img(j, { 7, 1, 2, 4,
|
||||||
|
3, 5, 6, 0 })
|
||||||
|
|
||||||
|
app.range.frames = { 1, 2 }
|
||||||
|
app.command.Flip{ orientation="horizontal", target="mask" }
|
||||||
|
expect_img(i, { 7, 6, 5, 4,
|
||||||
|
3, 2, 1, 0 })
|
||||||
|
expect_img(j, { 7, 2, 1, 4,
|
||||||
|
3, 6, 5, 0 })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fill
|
||||||
|
do
|
||||||
|
local s = Sprite(4, 2, ColorMode.INDEXED)
|
||||||
|
local c = s.cels[1]
|
||||||
|
local i = c.image
|
||||||
|
i:clear(1)
|
||||||
|
array_to_pixels({ 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1 }, i)
|
||||||
|
app.fgColor = Color{ index=0 }
|
||||||
|
s.selection = Selection(Rectangle(1, 1, 2, 1))
|
||||||
|
app.command.Fill()
|
||||||
|
expect_eq(Rectangle(0, 0, 4, 2), c.bounds)
|
||||||
|
expect_img(i, { 1, 1, 1, 1,
|
||||||
|
1, 0, 0, 1 })
|
||||||
|
|
||||||
|
c.position = { x=0, y=1 }
|
||||||
|
app.fgColor = Color{ index=2 }
|
||||||
|
s.selection = Selection(Rectangle(1, 0, 2, 2))
|
||||||
|
app.command.Fill()
|
||||||
|
expect_eq(Rectangle(0, 0, 4, 3), c.bounds)
|
||||||
|
expect_img(i, { 0, 2, 2, 0,
|
||||||
|
1, 2, 2, 1,
|
||||||
|
1, 0, 0, 1 })
|
||||||
|
|
||||||
|
app.fgColor = Color{ index=0 }
|
||||||
|
s.selection = Selection(Rectangle(0, 0, 3, 3))
|
||||||
|
app.command.Fill()
|
||||||
|
expect_eq(Rectangle(3, 1, 1, 2), c.bounds)
|
||||||
|
expect_img(i, { 1,
|
||||||
|
1 })
|
||||||
|
|
||||||
|
app.undo() -- undo Fill
|
||||||
|
expect_eq(Rectangle(0, 0, 4, 3), c.bounds)
|
||||||
|
expect_img(i, { 0, 2, 2, 0,
|
||||||
|
1, 2, 2, 1,
|
||||||
|
1, 0, 0, 1 })
|
||||||
|
|
||||||
|
expect_eq(Rectangle(0, 0, 3, 3), s.selection.bounds)
|
||||||
|
app.undo() -- undo selection change
|
||||||
|
expect_eq(Rectangle(1, 0, 2, 2), s.selection.bounds)
|
||||||
|
app.undo() -- undo Fill
|
||||||
|
expect_eq(Rectangle(0, 1, 4, 2), c.bounds)
|
||||||
|
expect_img(i, { 1, 1, 1, 1,
|
||||||
|
1, 0, 0, 1 })
|
||||||
|
end
|
77
tests/scripts/app_fs.lua
Normal file
77
tests/scripts/app_fs.lua
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local fs = app.fs
|
||||||
|
local sep = fs.pathSeparator
|
||||||
|
|
||||||
|
assert('' == fs.filePath('first.png'))
|
||||||
|
assert('path' == fs.filePath('path/second.png'))
|
||||||
|
assert('C:\\path' == fs.filePath('C:\\path\\third.png'))
|
||||||
|
|
||||||
|
assert('first.png' == fs.fileName('first.png'))
|
||||||
|
assert('second.png' == fs.fileName('path/second.png'))
|
||||||
|
assert('third.png' == fs.fileName('C:\\path\\third.png'))
|
||||||
|
|
||||||
|
assert('png' == fs.fileExtension('path/file.png'))
|
||||||
|
|
||||||
|
assert('first' == fs.fileTitle('first.png'))
|
||||||
|
assert('second' == fs.fileTitle('path/second.png'))
|
||||||
|
assert('third' == fs.fileTitle('C:\\path\\third.png'))
|
||||||
|
|
||||||
|
assert('first' == fs.filePathAndTitle('first.png'))
|
||||||
|
assert('path/second' == fs.filePathAndTitle('path/second.png'))
|
||||||
|
assert('C:\\path\\third' == fs.filePathAndTitle('C:\\path\\third.png'))
|
||||||
|
|
||||||
|
assert('hi/bye' == fs.joinPath('hi/', 'bye'))
|
||||||
|
assert('hi/bye' .. sep .. 'smth.png' == fs.joinPath('hi/', 'bye', 'smth.png'))
|
||||||
|
|
||||||
|
local pwd = fs.currentPath
|
||||||
|
assert(pwd ~= nil)
|
||||||
|
assert(fs.isDirectory(pwd))
|
||||||
|
assert(not fs.isFile(pwd))
|
||||||
|
assert(fs.isFile(fs.joinPath(pwd, 'run-tests.sh')))
|
||||||
|
|
||||||
|
do
|
||||||
|
local runTestsFound = false
|
||||||
|
local readmeFound = false
|
||||||
|
local files = fs.listFiles(pwd)
|
||||||
|
for i in pairs(files) do
|
||||||
|
if files[i] == 'run-tests.sh' then
|
||||||
|
runTestsFound = true
|
||||||
|
elseif files[i] == 'README.md' then
|
||||||
|
readmeFound = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local fullFs = fs.joinPath(pwd, files[i])
|
||||||
|
if fs.isFile(fullFs) then
|
||||||
|
assert(fs.fileSize(fullFs) > 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(runTestsFound)
|
||||||
|
assert(readmeFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create directories
|
||||||
|
do
|
||||||
|
assert(fs.makeDirectory("_tmp"))
|
||||||
|
assert(fs.isDirectory("_tmp"))
|
||||||
|
|
||||||
|
assert(fs.makeAllDirectories("_tmp/a/b"))
|
||||||
|
assert(fs.isDirectory("_tmp/a"))
|
||||||
|
assert(fs.isDirectory("_tmp/a/b"))
|
||||||
|
|
||||||
|
assert(fs.removeDirectory("_tmp/a/b"))
|
||||||
|
assert(not fs.isDirectory("_tmp/a/b"))
|
||||||
|
assert(fs.isDirectory("_tmp/a"))
|
||||||
|
|
||||||
|
assert(not fs.removeDirectory("_tmp")) -- Should fail
|
||||||
|
assert(fs.isDirectory("_tmp/a"))
|
||||||
|
assert(fs.isDirectory("_tmp"))
|
||||||
|
|
||||||
|
assert(fs.removeDirectory("_tmp/a"))
|
||||||
|
assert(fs.removeDirectory("_tmp"))
|
||||||
|
assert(not fs.isDirectory("_tmp/a"))
|
||||||
|
assert(not fs.isDirectory("_tmp"))
|
||||||
|
end
|
12
tests/scripts/app_pixel_color.lua
Normal file
12
tests/scripts/app_pixel_color.lua
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local pc = app.pixelColor
|
||||||
|
assert(0 == pc.rgba(0, 0, 0, 0))
|
||||||
|
assert(1 == pc.rgbaR(pc.rgba(1, 2, 3, 4)))
|
||||||
|
assert(2 == pc.rgbaG(pc.rgba(1, 2, 3, 4)))
|
||||||
|
assert(3 == pc.rgbaB(pc.rgba(1, 2, 3, 4)))
|
||||||
|
assert(4 == pc.rgbaA(pc.rgba(1, 2, 3, 4)))
|
||||||
|
assert(0xff104080 == pc.rgba(0x80, 0x40, 0x10, 0xff))
|
140
tests/scripts/app_preferences.lua
Normal file
140
tests/scripts/app_preferences.lua
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
-- Copyright (C) 2019-2021 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
-- Preferences for tools
|
||||||
|
do
|
||||||
|
-- The first time we get the tool preferences in CLI mode, we get
|
||||||
|
-- the default options for this tool (in GUI, we get the current
|
||||||
|
-- user-defined options).
|
||||||
|
local t = app.preferences.tool('pencil')
|
||||||
|
assert(t.opacity == 255)
|
||||||
|
assert(t.tolerance == 0)
|
||||||
|
assert(t.contiguous == true)
|
||||||
|
assert(t.brush.type == BrushType.CIRCLE)
|
||||||
|
assert(t.brush.size == 1)
|
||||||
|
t.brush.size = 2
|
||||||
|
assert(t.brush.size == 2)
|
||||||
|
|
||||||
|
-- Getting the tool again must give us the configuration that was
|
||||||
|
-- set inside the script
|
||||||
|
t = app.preferences.tool('pencil')
|
||||||
|
assert(t.brush.size == 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Preferences for documents
|
||||||
|
do
|
||||||
|
local defPref = app.preferences.document(nil)
|
||||||
|
defPref.grid.bounds = Rectangle(0, 0, 16, 16)
|
||||||
|
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
local p = app.preferences.document(s)
|
||||||
|
assert(s.gridBounds == Rectangle(0, 0, 16, 16))
|
||||||
|
assert(p.grid.bounds == Rectangle(0, 0, 16, 16))
|
||||||
|
assert(p.grid.color == Color(0, 0, 255))
|
||||||
|
p.grid.color = Color(255, 0, 0)
|
||||||
|
assert(p.grid.color == Color(255, 0, 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Default & doc preferences combinations (related to https://community.aseprite.org/t/4305)
|
||||||
|
do
|
||||||
|
-- Set default preferences
|
||||||
|
local defPref = app.preferences.document(nil)
|
||||||
|
defPref.grid.bounds = Rectangle(0, 0, 10, 10)
|
||||||
|
defPref.grid.color = Color(255, 255, 0) -- Yellow
|
||||||
|
assert(defPref.grid.bounds == Rectangle(0, 0, 10, 10))
|
||||||
|
assert(defPref.grid.color == Color(255, 255, 0))
|
||||||
|
|
||||||
|
do -- File with default preferences
|
||||||
|
local doc = Sprite(32, 32)
|
||||||
|
local docPref = app.preferences.document(doc)
|
||||||
|
assert(doc.gridBounds == Rectangle(0, 0, 10, 10))
|
||||||
|
assert(docPref.grid.bounds == Rectangle(0, 0, 10, 10))
|
||||||
|
assert(docPref.grid.color == Color(255, 255, 0))
|
||||||
|
doc:saveAs('_test_pref.png')
|
||||||
|
doc:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- File with specific preferences
|
||||||
|
local doc = Sprite(32, 32)
|
||||||
|
local docPref = app.preferences.document(doc)
|
||||||
|
docPref.grid.color = Color(0, 128, 0) -- Green
|
||||||
|
assert(docPref.grid.bounds == Rectangle(0, 0, 10, 10))
|
||||||
|
assert(docPref.grid.color == Color(0, 128, 0))
|
||||||
|
doc:saveAs('_test_pref2.png')
|
||||||
|
doc:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Now we change default preferences
|
||||||
|
defPref.grid.bounds = Rectangle(0, 0, 64, 64)
|
||||||
|
defPref.grid.color = Color(255, 0, 0) -- Red
|
||||||
|
assert(defPref.grid.bounds == Rectangle(0, 0, 64, 64))
|
||||||
|
assert(defPref.grid.color == Color(255, 0, 0))
|
||||||
|
do -- A new document should have the new default preferences
|
||||||
|
local doc = Sprite(32, 32)
|
||||||
|
local docPref = app.preferences.document(doc)
|
||||||
|
assert(docPref.grid.bounds == Rectangle(0, 0, 64, 64))
|
||||||
|
assert(docPref.grid.color == Color(255, 0, 0))
|
||||||
|
doc:close()
|
||||||
|
end
|
||||||
|
do -- The first document should have the new default preferences (because it was saved with the defaults)
|
||||||
|
|
||||||
|
-- TODO maybe related to https://community.aseprite.org/t/grid-for-new-documents/3303
|
||||||
|
-- should we get the new defaults or the values when we saved the document?
|
||||||
|
-- (e.g. even if we didn't change the grid values, it looks
|
||||||
|
-- like if the user changed something about the grid or the
|
||||||
|
-- background colors, the expected behavior would be to
|
||||||
|
-- restore the exact same colors, no the new defaults)
|
||||||
|
|
||||||
|
local doc = Sprite{ fromFile="_test_pref.png" }
|
||||||
|
local docPref = app.preferences.document(doc)
|
||||||
|
assert(docPref.grid.bounds == Rectangle(0, 0, 64, 64))
|
||||||
|
assert(docPref.grid.color == Color(255, 0, 0))
|
||||||
|
doc:close()
|
||||||
|
end
|
||||||
|
do -- The second document should have the new specific preferences for the grid color
|
||||||
|
local doc = Sprite{ fromFile="_test_pref2.png" }
|
||||||
|
local docPref = app.preferences.document(doc)
|
||||||
|
assert(docPref.grid.bounds == Rectangle(0, 0, 64, 64))
|
||||||
|
assert(docPref.grid.color == Color(0, 128, 0))
|
||||||
|
doc:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Test that undoing grid bounds, updates the grid in the preferences correctly
|
||||||
|
local doc = Sprite(32, 32)
|
||||||
|
assert(doc.gridBounds == Rectangle(0, 0, 64, 64))
|
||||||
|
assert(app.preferences.document(doc).grid.bounds == Rectangle(0, 0, 64, 64))
|
||||||
|
|
||||||
|
doc.gridBounds = Rectangle(0, 0, 4, 4)
|
||||||
|
assert(doc.gridBounds == Rectangle(0, 0, 4, 4))
|
||||||
|
assert(app.preferences.document(doc).grid.bounds == Rectangle(0, 0, 4, 4))
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
assert(doc.gridBounds == Rectangle(0, 0, 64, 64))
|
||||||
|
assert(app.preferences.document(doc).grid.bounds == Rectangle(0, 0, 64, 64))
|
||||||
|
|
||||||
|
app.redo()
|
||||||
|
assert(doc.gridBounds == Rectangle(0, 0, 4, 4))
|
||||||
|
assert(app.preferences.document(doc).grid.bounds == Rectangle(0, 0, 4, 4))
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Test symmetry preferences
|
||||||
|
do -- File with default preferences
|
||||||
|
local doc = Sprite(200, 100)
|
||||||
|
local docPref = app.preferences.document(doc)
|
||||||
|
assert(docPref.symmetry.x_axis == 100)
|
||||||
|
assert(docPref.symmetry.y_axis == 50)
|
||||||
|
docPref.symmetry.x_axis = 25
|
||||||
|
doc:saveAs('_test_symmetry.png')
|
||||||
|
doc:close()
|
||||||
|
end
|
||||||
|
do -- File with default preferences
|
||||||
|
local doc = Sprite{ fromFile='_test_symmetry.png' }
|
||||||
|
local docPref = app.preferences.document(doc)
|
||||||
|
assert(docPref.symmetry.x_axis == 25)
|
||||||
|
assert(docPref.symmetry.y_axis == 50)
|
||||||
|
doc:close()
|
||||||
|
end
|
||||||
|
end
|
40
tests/scripts/app_transaction.lua
Normal file
40
tests/scripts/app_transaction.lua
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local s = Sprite(16, 32)
|
||||||
|
assert(s.width == 16)
|
||||||
|
assert(s.height == 32)
|
||||||
|
|
||||||
|
s.width = 20
|
||||||
|
assert(s.width == 20)
|
||||||
|
assert(s.height == 32)
|
||||||
|
|
||||||
|
s.height = 40
|
||||||
|
assert(s.width == 20)
|
||||||
|
assert(s.height == 40)
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
assert(s.width == 20)
|
||||||
|
assert(s.height == 32)
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
assert(s.width == 16)
|
||||||
|
assert(s.height == 32)
|
||||||
|
|
||||||
|
app.transaction(
|
||||||
|
function()
|
||||||
|
s.width = 20
|
||||||
|
s.height = 40
|
||||||
|
end)
|
||||||
|
assert(s.width == 20)
|
||||||
|
assert(s.height == 40)
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
assert(s.width == 16)
|
||||||
|
assert(s.height == 32)
|
||||||
|
|
||||||
|
app.redo()
|
||||||
|
assert(s.width == 20)
|
||||||
|
assert(s.height == 40)
|
74
tests/scripts/brush.lua
Normal file
74
tests/scripts/brush.lua
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
-- Copyright (C) 2019 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')
|
||||||
|
|
||||||
|
do
|
||||||
|
local b = Brush()
|
||||||
|
assert(b.type == BrushType.CIRCLE)
|
||||||
|
assert(b.size == 1)
|
||||||
|
assert(b.angle == 0)
|
||||||
|
assert(b.center == Point{ x=0, y=0 })
|
||||||
|
assert(b.pattern == BrushPattern.NONE)
|
||||||
|
assert(b.patternOrigin == Point{ x=0, y=0 })
|
||||||
|
|
||||||
|
local c = Brush(3)
|
||||||
|
assert(c.type == BrushType.CIRCLE)
|
||||||
|
assert(c.size == 3)
|
||||||
|
assert(c.center == Point{ x=1, y=1 })
|
||||||
|
|
||||||
|
local d = Brush(4)
|
||||||
|
assert(d.type == BrushType.CIRCLE)
|
||||||
|
assert(d.size == 4)
|
||||||
|
assert(d.center == Point{ x=2, y=2 })
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local b = Brush{ type=BrushType.SQUARE, size=4 }
|
||||||
|
assert(b.type == BrushType.SQUARE)
|
||||||
|
assert(b.size == 4)
|
||||||
|
assert(b.angle == 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local b = Brush{ type=BrushType.LINE, size=5, angle=90 }
|
||||||
|
assert(b.type == BrushType.LINE)
|
||||||
|
assert(b.size == 5)
|
||||||
|
assert(b.angle == 90)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local b = Brush{ type=BrushType.IMAGE, image=Image(4, 8) }
|
||||||
|
local c = Brush{ image=Image(4, 8) }
|
||||||
|
assert(b.type == BrushType.IMAGE)
|
||||||
|
assert(c.type == BrushType.IMAGE)
|
||||||
|
assert(b.image.width == 4)
|
||||||
|
assert(b.image.height == 8)
|
||||||
|
assert(b.pattern == BrushPattern.NONE)
|
||||||
|
assert(b.patternOrigin.x == 0)
|
||||||
|
assert(b.patternOrigin.y == 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local rgba = app.pixelColor.rgba
|
||||||
|
local r = rgba(255, 0, 0)
|
||||||
|
local g = rgba(0, 128, 0)
|
||||||
|
local b = rgba(0, 0, 255)
|
||||||
|
|
||||||
|
local img = Image(2, 2)
|
||||||
|
img:putPixel(0, 0, r)
|
||||||
|
img:putPixel(1, 0, b)
|
||||||
|
img:putPixel(0, 1, b)
|
||||||
|
img:putPixel(1, 1, r)
|
||||||
|
|
||||||
|
local brush = Brush{ image=img }
|
||||||
|
expect_img(brush.image, { r, b, b, r })
|
||||||
|
|
||||||
|
brush:setFgColor(g)
|
||||||
|
expect_img(brush.image, { r, g, g, r })
|
||||||
|
|
||||||
|
brush:setBgColor(b)
|
||||||
|
expect_img(brush.image, { b, g, g, b })
|
||||||
|
end
|
29
tests/scripts/cel.lua
Normal file
29
tests/scripts/cel.lua
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local s = Sprite(32, 64)
|
||||||
|
assert(#s.layers == 1)
|
||||||
|
assert(#s.cels == 1)
|
||||||
|
|
||||||
|
local c = s.cels[1]
|
||||||
|
assert(c.sprite == s)
|
||||||
|
assert(c.layer == s.layers[1])
|
||||||
|
assert(c.frame == s.frames[1])
|
||||||
|
assert(c.frame.frameNumber == 1)
|
||||||
|
assert(c.frameNumber == 1)
|
||||||
|
assert(c.image)
|
||||||
|
assert(c.bounds == Rectangle(0, 0, 32, 64))
|
||||||
|
assert(c.position == Point(0, 0))
|
||||||
|
assert(c.color == Color())
|
||||||
|
assert(c.data == "")
|
||||||
|
|
||||||
|
c.color = Color{ r=255, g=100, b=20 }
|
||||||
|
c.data = "test"
|
||||||
|
assert(c.color == Color{ r=255, g=100, b=20 })
|
||||||
|
assert(c.data == "test")
|
||||||
|
|
||||||
|
c.position = Point(2, 4)
|
||||||
|
assert(c.position == Point(2, 4))
|
||||||
|
assert(c.bounds == Rectangle(2, 4, 32, 64))
|
86
tests/scripts/cels.lua
Normal file
86
tests/scripts/cels.lua
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
-- Copyright (C) 2020 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
dofile('./test_utils.lua')
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
for i = 1,3 do s:newFrame() end
|
||||||
|
assert(#s.frames == 4)
|
||||||
|
|
||||||
|
-- Layer a and b
|
||||||
|
local a = s.layers[1]
|
||||||
|
local b = s:newLayer()
|
||||||
|
|
||||||
|
local ca = { s.cels[1],
|
||||||
|
s.cels[2],
|
||||||
|
s.cels[3] }
|
||||||
|
|
||||||
|
local cb = { s:newCel(b, 1),
|
||||||
|
s:newCel(b, 2, Image(8, 8), 4, 4),
|
||||||
|
s:newCel(b, 3, Image(32, 10), 16, 10) }
|
||||||
|
|
||||||
|
assert(cb[1].bounds == Rectangle(0, 0, 32, 32))
|
||||||
|
assert(cb[2].bounds == Rectangle(4, 4, 8, 8))
|
||||||
|
assert(cb[3].bounds == Rectangle(16, 10, 32, 10))
|
||||||
|
|
||||||
|
-- Check how layer cels are updated when we delete a cel in the middle
|
||||||
|
|
||||||
|
assert(cb[1] == b.cels[1])
|
||||||
|
assert(cb[2] == b.cels[2])
|
||||||
|
assert(cb[3] == b.cels[3])
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
for k,v in ipairs(b.cels) do
|
||||||
|
assert(i == k)
|
||||||
|
assert(v == b.cels[k])
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
|
||||||
|
s:deleteCel(cb[2])
|
||||||
|
assert(cb[1] == b.cels[1])
|
||||||
|
assert(cb[3] == b.cels[2])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Some extra tests of newCel() and deleteCel()
|
||||||
|
do
|
||||||
|
local s = Sprite(4, 4, ColorMode.INDEXED)
|
||||||
|
local layer = app.activeLayer
|
||||||
|
app.bgColor = 0
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
expect_img(s.cels[1].image, { 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0 })
|
||||||
|
|
||||||
|
-- Crash in old versions undoing newCel() in a background layer
|
||||||
|
s:newCel(layer, 1)
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Check that newCel clears with bgColor in background layer
|
||||||
|
local img = Image(ImageSpec{ width=2, height=2,
|
||||||
|
colorMode=ColorMode.INDEXED })
|
||||||
|
array_to_pixels({ 0, 1,
|
||||||
|
2, 3 }, img)
|
||||||
|
|
||||||
|
app.bgColor = Color(1) -- bgColor used to clear the background cel
|
||||||
|
s:newCel(layer, 1, img, Point(1, 1))
|
||||||
|
expect_img(s.cels[1].image, { 1, 1, 1, 1,
|
||||||
|
1, 0, 1, 1,
|
||||||
|
1, 2, 3, 1,
|
||||||
|
1, 1, 1, 1 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Check deleteCel()
|
||||||
|
app.bgColor = Color(2)
|
||||||
|
s:deleteCel(layer, 1)
|
||||||
|
expect_img(s.cels[1].image, { 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
end
|
45
tests/scripts/color.lua
Normal file
45
tests/scripts/color.lua
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
-- Copyright (C) 2022 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local a, b
|
||||||
|
|
||||||
|
a = Color()
|
||||||
|
assert(a.red == 0)
|
||||||
|
assert(a.green == 0)
|
||||||
|
assert(a.blue == 0)
|
||||||
|
assert(a.alpha == 0)
|
||||||
|
|
||||||
|
a = Color{ r=100, g=50, b=10 }
|
||||||
|
b = Color(100, 50, 10)
|
||||||
|
assert(a.red == 100)
|
||||||
|
assert(a.green == 50)
|
||||||
|
assert(a.blue == 10)
|
||||||
|
assert(a.alpha == 255)
|
||||||
|
assert(a == b)
|
||||||
|
|
||||||
|
a = Color{ red=200, green=100, blue=20, alpha=200 }
|
||||||
|
b = Color(200, 100, 20, 200)
|
||||||
|
assert(a.red == 200)
|
||||||
|
assert(a.green == 100)
|
||||||
|
assert(a.blue == 20)
|
||||||
|
assert(a.alpha == 200)
|
||||||
|
assert(a == b)
|
||||||
|
print(a.rgbaPixel)
|
||||||
|
print(app.pixelColor.rgba(200, 100, 20, 200))
|
||||||
|
assert(a.rgbaPixel == app.pixelColor.rgba(200, 100, 20, 200))
|
||||||
|
|
||||||
|
a = Color{ h=180, s=0.4, v=0.5, a=200 }
|
||||||
|
b = Color{ hue=180, saturation=0.4, value=0.5, alpha=200 }
|
||||||
|
assert(a.hue == 180)
|
||||||
|
assert(a.saturation == 0.4)
|
||||||
|
assert(a.value == 0.5)
|
||||||
|
assert(a.alpha == 200)
|
||||||
|
assert(b.hue == 180)
|
||||||
|
assert(b.saturation == 0.4)
|
||||||
|
assert(b.value == 0.5)
|
||||||
|
assert(b.alpha == 200)
|
||||||
|
assert(a == b)
|
||||||
|
assert(a ~= 1) -- Comparing with other type fails
|
51
tests/scripts/color_convert.lua
Normal file
51
tests/scripts/color_convert.lua
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
-- Copyright (C) 2019-2022 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')
|
||||||
|
|
||||||
|
-- this tests and ensures that the alpha-ness of a background
|
||||||
|
-- layer is maintained when sprite conversion takes place from
|
||||||
|
-- Indexed to RGB
|
||||||
|
|
||||||
|
do
|
||||||
|
local sprite = Sprite(2, 2, ColorMode.INDEXED)
|
||||||
|
local pal = sprite.palettes[1]
|
||||||
|
|
||||||
|
assert(sprite.layers[1].isTransparent)
|
||||||
|
assert(sprite.colorMode == ColorMode.INDEXED)
|
||||||
|
assert(#pal == 256)
|
||||||
|
|
||||||
|
local color = pal:getColor(3)
|
||||||
|
color.alpha = 200
|
||||||
|
pal:setColor(3, color)
|
||||||
|
|
||||||
|
local image = sprite.cels[1].image
|
||||||
|
image:drawPixel(0, 0, pal:getColor(2))
|
||||||
|
image:drawPixel(0, 1, pal:getColor(3))
|
||||||
|
image:drawPixel(1, 0, pal:getColor(4))
|
||||||
|
image:drawPixel(1, 1, pal:getColor(5))
|
||||||
|
|
||||||
|
app.bgColor = Color{ index=0 }
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
|
||||||
|
local layer = sprite.layers[1]
|
||||||
|
assert(layer.isTransparent == false)
|
||||||
|
assert(layer.name == "Background")
|
||||||
|
|
||||||
|
-- change color mode from Indexed to RGB
|
||||||
|
app.command.ChangePixelFormat {
|
||||||
|
format="rgb"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sprite.colorMode == ColorMode.RGB)
|
||||||
|
image = sprite.cels[1].image
|
||||||
|
|
||||||
|
for x=0, 1, 1 do
|
||||||
|
for y=0, 1, 1 do
|
||||||
|
local pixel = image:getPixel(x, y)
|
||||||
|
assert(app.pixelColor.rgbaA(pixel) == 255)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
201
tests/scripts/color_quantization.lua
Normal file
201
tests/scripts/color_quantization.lua
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
-- Copyright (C) 2019-2022 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")
|
||||||
|
|
||||||
|
local rgba = app.pixelColor.rgba
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- app.command.ColorQuantization
|
||||||
|
|
||||||
|
do
|
||||||
|
-- One sprite with a background layer
|
||||||
|
local s = Sprite(2, 2)
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
|
||||||
|
local i = s.cels[1].image
|
||||||
|
local p = s.palettes[1]
|
||||||
|
assert(#p == 256)
|
||||||
|
assert(s.colorMode == ColorMode.RGB)
|
||||||
|
app.command.ColorQuantization{ algorithm="rgb5a3" }
|
||||||
|
assert(#p == 1)
|
||||||
|
|
||||||
|
array_to_pixels({ rgba(255, 255, 0), rgba(255, 255, 0),
|
||||||
|
rgba(255, 255, 0), rgba(255, 255, 0) }, i)
|
||||||
|
app.command.ColorQuantization{ algorithm="rgb5a3" }
|
||||||
|
assert(#p == 1)
|
||||||
|
assert(p:getColor(0) == Color(255, 255, 0))
|
||||||
|
|
||||||
|
array_to_pixels({ rgba(255, 0, 0), rgba(255, 0, 0),
|
||||||
|
rgba(255, 255, 0), rgba(255, 255, 0) }, i)
|
||||||
|
app.command.ColorQuantization{ algorithm="rgb5a3" }
|
||||||
|
assert(#p == 2)
|
||||||
|
assert(p:getColor(0) == Color(255, 0, 0))
|
||||||
|
assert(p:getColor(1) == Color(255, 255, 0))
|
||||||
|
|
||||||
|
array_to_pixels({ rgba(255, 0, 0), rgba(255, 0, 0),
|
||||||
|
rgba(255, 255, 0), rgba(0, 0, 255) }, i)
|
||||||
|
app.command.ColorQuantization{ algorithm="rgb5a3" }
|
||||||
|
assert(#p == 3)
|
||||||
|
assert(p:getColor(0) == Color(255, 0, 0))
|
||||||
|
assert(p:getColor(1) == Color(255, 255, 0))
|
||||||
|
assert(p:getColor(2) == Color(0, 0, 255))
|
||||||
|
|
||||||
|
-- Convert the background layer to a transparent layer
|
||||||
|
|
||||||
|
app.command.LayerFromBackground()
|
||||||
|
app.command.ColorQuantization{ algorithm="rgb5a3", withAlpha=false }
|
||||||
|
assert(#p == 4) -- One extra color for transparent layer
|
||||||
|
assert(p:getColor(0) == Color(0, 0, 0))
|
||||||
|
assert(p:getColor(1) == Color(255, 0, 0))
|
||||||
|
assert(p:getColor(2) == Color(255, 255, 0))
|
||||||
|
assert(p:getColor(3) == Color(0, 0, 255))
|
||||||
|
|
||||||
|
app.command.ColorQuantization()
|
||||||
|
assert(#p == 4)
|
||||||
|
assert(p:getColor(0) == Color(0, 0, 0, 0))
|
||||||
|
assert(p:getColor(1) == Color(255, 0, 0))
|
||||||
|
assert(p:getColor(2) == Color(255, 255, 0))
|
||||||
|
assert(p:getColor(3) == Color(0, 0, 255))
|
||||||
|
|
||||||
|
array_to_pixels({ rgba(0, 0, 0), rgba(255, 0, 0),
|
||||||
|
rgba(255, 0, 0), rgba(0, 0, 255) }, i)
|
||||||
|
app.command.ColorQuantization{ algorithm="rgb5a3", withAlpha=false }
|
||||||
|
assert(#p == 4)
|
||||||
|
assert(p:getColor(0) == Color(0, 0, 0))
|
||||||
|
assert(p:getColor(1) == Color(0, 0, 0))
|
||||||
|
assert(p:getColor(2) == Color(255, 0, 0))
|
||||||
|
assert(p:getColor(3) == Color(0, 0, 255))
|
||||||
|
|
||||||
|
app.command.ColorQuantization{ algorithm="rgb5a3" }
|
||||||
|
assert(#p == 4)
|
||||||
|
assert(p:getColor(0) == Color(0, 0, 0, 0))
|
||||||
|
assert(p:getColor(1) == Color(0, 0, 0))
|
||||||
|
assert(p:getColor(2) == Color(255, 0, 0))
|
||||||
|
assert(p:getColor(3) == Color(0, 0, 255))
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
-- One sprite with a transparent layer + a background layer
|
||||||
|
local s = Sprite(2, 2)
|
||||||
|
local p = s.palettes[1]
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
local bg = s.cels[1].image
|
||||||
|
local fg = s:newCel(s:newLayer(), 1).image
|
||||||
|
|
||||||
|
assert(#s.frames == 1)
|
||||||
|
assert(#s.layers == 2)
|
||||||
|
assert(#s.cels == 2)
|
||||||
|
|
||||||
|
array_to_pixels({ rgba(0, 0, 0, 0), rgba(0, 255, 0),
|
||||||
|
rgba(255, 0, 0), rgba(0, 0, 0, 0) }, fg)
|
||||||
|
array_to_pixels({ rgba(0, 0, 0), rgba(0, 0, 0),
|
||||||
|
rgba(0, 0, 0), rgba(0, 0, 255) }, bg)
|
||||||
|
|
||||||
|
app.command.ColorQuantization{ algorithm="rgb5a3" }
|
||||||
|
assert(#p == 5)
|
||||||
|
assert(p:getColor(0) == Color(0, 0, 0, 0))
|
||||||
|
assert(p:getColor(1) == Color(0, 0, 0))
|
||||||
|
assert(p:getColor(2) == Color(0, 255, 0))
|
||||||
|
assert(p:getColor(3) == Color(255, 0, 0))
|
||||||
|
assert(p:getColor(4) == Color(0, 0, 255))
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- app.command.ChangePixelFormat
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(2, 2, ColorMode.RGB)
|
||||||
|
local p = Palette(4)
|
||||||
|
p:setColor(0, Color(0, 0, 0))
|
||||||
|
p:setColor(1, Color(101, 90, 200))
|
||||||
|
p:setColor(2, Color(102, 91, 201))
|
||||||
|
p:setColor(3, Color(103, 92, 203))
|
||||||
|
s:setPalette(p)
|
||||||
|
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
|
||||||
|
local bg = s.cels[1].image
|
||||||
|
array_to_pixels({ rgba(0, 0, 0), rgba(101, 90, 200),
|
||||||
|
rgba(102, 91, 201), rgba(103, 92, 203) }, bg)
|
||||||
|
|
||||||
|
app.command.ChangePixelFormat{ format="indexed", rgbmap="rgb5a3" }
|
||||||
|
-- Using the 5-bit precision of RGB5A3 will match everything with
|
||||||
|
-- the first palette entry.
|
||||||
|
bg = s.cels[1].image
|
||||||
|
expect_img(bg, { 0, 1,
|
||||||
|
1, 1 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.command.ChangePixelFormat{ format="indexed", rgbmap="octree" }
|
||||||
|
bg = s.cels[1].image
|
||||||
|
expect_img(bg, { 0, 1,
|
||||||
|
2, 3 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
p:setColor(0, Color(0, 0, 0, 0))
|
||||||
|
bg = s.cels[1].image
|
||||||
|
array_to_pixels({ rgba(101, 90, 200, 0), rgba(101, 90, 200),
|
||||||
|
rgba(102, 91, 201), rgba(103, 92, 203, 0) }, bg)
|
||||||
|
app.command.ChangePixelFormat{ format="indexed", rgbmap="octree" }
|
||||||
|
bg = s.cels[1].image
|
||||||
|
expect_img(bg, { 0, 1,
|
||||||
|
2, 0 })
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- Tests for issue aseprite/aseprite#3207
|
||||||
|
-- Conversion RGB to INDEXED color mode, in transparent layers, always
|
||||||
|
-- picks index 0 as transparent color, even if the mask color is present
|
||||||
|
-- in the palette.
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(2, 3, ColorMode.RGB)
|
||||||
|
local p = Palette(4)
|
||||||
|
p:setColor(0, Color(0, 0, 0))
|
||||||
|
p:setColor(1, Color(255, 0, 0))
|
||||||
|
p:setColor(2, Color(0, 0, 0, 0))
|
||||||
|
p:setColor(3, Color(0, 255, 0))
|
||||||
|
s:setPalette(p)
|
||||||
|
|
||||||
|
local bg = s.cels[1].image
|
||||||
|
array_to_pixels({ rgba(0, 0, 0),rgba(255, 0, 0),
|
||||||
|
rgba(255, 0, 0), rgba(0, 0, 0, 0),
|
||||||
|
rgba(0, 0, 0, 0), rgba(0, 0, 0, 0), }, bg)
|
||||||
|
|
||||||
|
app.command.ChangePixelFormat{ format="indexed", rgbmap="rgb5a3" }
|
||||||
|
-- Using the 5-bit precision of RGB5A3 will match everything with
|
||||||
|
-- the first palette entry.
|
||||||
|
bg = s.cels[1].image
|
||||||
|
expect_img(bg, { 0, 1,
|
||||||
|
1, 2,
|
||||||
|
2, 2 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.command.ChangePixelFormat{ format="indexed", rgbmap="octree" }
|
||||||
|
bg = s.cels[1].image
|
||||||
|
expect_img(bg, { 0, 1,
|
||||||
|
1, 2,
|
||||||
|
2, 2 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
p:setColor(2, Color(0, 0, 255))
|
||||||
|
s:setPalette(p)
|
||||||
|
bg = s.cels[1].image
|
||||||
|
|
||||||
|
app.command.ChangePixelFormat{ format="indexed", rgbmap="rgb5a3" }
|
||||||
|
bg = s.cels[1].image
|
||||||
|
expect_img(bg, { 2, 1,
|
||||||
|
1, 0,
|
||||||
|
0, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.command.ChangePixelFormat{ format="indexed", rgbmap="octree" }
|
||||||
|
bg = s.cels[1].image
|
||||||
|
expect_img(bg, { 2, 1,
|
||||||
|
1, 0,
|
||||||
|
0, 0 })
|
||||||
|
end
|
21
tests/scripts/color_space.lua
Normal file
21
tests/scripts/color_space.lua
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local none = ColorSpace() -- None
|
||||||
|
local srgb = ColorSpace{ sRGB=true }
|
||||||
|
local none2 = ColorSpace{ sRGB=false }
|
||||||
|
assert(none ~= srgb)
|
||||||
|
assert(none == none2)
|
||||||
|
|
||||||
|
local spr = Sprite(32, 32)
|
||||||
|
local cs1 = spr.colorSpace
|
||||||
|
local cs2 = spr.spec.colorSpace
|
||||||
|
assert(cs1 == cs2)
|
||||||
|
assert(cs1 ~= none)
|
||||||
|
assert(cs1 == srgb) -- Default color profile: sRGB
|
||||||
|
|
||||||
|
local spr3 = Sprite(32, 32)
|
||||||
|
local cs3 = spr.spec.colorSpace
|
||||||
|
assert(cs1 == cs3)
|
60
tests/scripts/compare_sprite_sheets.lua
Normal file
60
tests/scripts/compare_sprite_sheets.lua
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local file1 = app.params["file1"]
|
||||||
|
local file2 = app.params["file2"]
|
||||||
|
if file1 == nil or file2 == nil then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local json = dofile('../third_party/json/json.lua')
|
||||||
|
local data1 = json.decode(io.open(file1):read('a'))
|
||||||
|
local data2 = json.decode(io.open(file2):read('a'))
|
||||||
|
|
||||||
|
if data1 == nil then
|
||||||
|
print('Cannot read file ' .. file1)
|
||||||
|
return 1
|
||||||
|
elseif data2 == nil then
|
||||||
|
print('Cannot read file ' .. file2)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function replace_filename(fn, newfn)
|
||||||
|
return string.gsub(fn, "(.*)[/\\]([^/\\]+)", "%1/"..newfn)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sheet1 = app.open(replace_filename(file1, data1.meta.image))
|
||||||
|
local sheet2 = app.open(replace_filename(file2, data2.meta.image))
|
||||||
|
|
||||||
|
for k,v in pairs(data1.frames) do
|
||||||
|
local fr1 = data1.frames[k]
|
||||||
|
local fr2 = data2.frames[k]
|
||||||
|
if fr1.duration ~= fr2.duration then
|
||||||
|
print('Frame '..k..' doesn\'t match duration')
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
if fr1.sourceSize.w ~= fr2.sourceSize.w or
|
||||||
|
fr1.sourceSize.h ~= fr2.sourceSize.h then
|
||||||
|
print('Frame '..k..' doesn\'t match sourceSize')
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local celImage1 = Image(fr1.frame.w, fr1.frame.h, sheet1.colorMode)
|
||||||
|
local celImage2 = Image(fr2.frame.w, fr2.frame.h, sheet2.colorMode)
|
||||||
|
celImage1:drawSprite(sheet1, 1, -fr1.frame.x, -fr1.frame.y)
|
||||||
|
celImage2:drawSprite(sheet2, 1, -fr2.frame.x, -fr2.frame.y)
|
||||||
|
|
||||||
|
local frImage1 = Image(fr1.sourceSize.w, fr1.sourceSize.h, sheet1.colorMode)
|
||||||
|
local frImage2 = Image(fr2.sourceSize.w, fr2.sourceSize.h, sheet2.colorMode)
|
||||||
|
frImage1:drawImage(celImage1, fr1.spriteSourceSize.x, fr1.spriteSourceSize.y)
|
||||||
|
frImage2:drawImage(celImage2, fr2.spriteSourceSize.x, fr2.spriteSourceSize.y)
|
||||||
|
|
||||||
|
-- To debug this function
|
||||||
|
--frImage1:saveAs(replace_filename(file1, k .. "-fr1.png"))
|
||||||
|
--frImage2:saveAs(replace_filename(file2, k .. "-fr2.png"))
|
||||||
|
--print(k, "fr1", fr1.frame.x, fr1.frame.y, "fr2", fr2.frame.x, fr2.frame.y)
|
||||||
|
|
||||||
|
assert(frImage1:isEqual(frImage2))
|
||||||
|
end
|
9
tests/scripts/console_assert.lua
Normal file
9
tests/scripts/console_assert.lua
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
assert(true)
|
||||||
|
print("this should be in the output")
|
||||||
|
assert(false)
|
||||||
|
print("this should not be in the output")
|
7
tests/scripts/console_print.lua
Normal file
7
tests/scripts/console_print.lua
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
print("hello world")
|
||||||
|
print(1, 2, 3)
|
8
tests/scripts/constants.lua
Normal file
8
tests/scripts/constants.lua
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
assert(ColorMode.RGB == 0)
|
||||||
|
assert(ColorMode.GRAYSCALE == 1)
|
||||||
|
assert(ColorMode.INDEXED == 2)
|
83
tests/scripts/drawing.lua
Normal file
83
tests/scripts/drawing.lua
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
-- Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local pc = app.pixelColor
|
||||||
|
|
||||||
|
-- Image:clear
|
||||||
|
local function test_clear(colorMode, transparentColor)
|
||||||
|
local i = Image(ImageSpec{ width=2, height=2, colorMode=colorMode, transparentColor=transparentColor })
|
||||||
|
i:putPixel(0, 0, 1)
|
||||||
|
i:putPixel(1, 0, 2)
|
||||||
|
i:putPixel(0, 1, 3)
|
||||||
|
i:putPixel(1, 1, 4)
|
||||||
|
assert(1 == i:getPixel(0, 0))
|
||||||
|
assert(2 == i:getPixel(1, 0))
|
||||||
|
assert(3 == i:getPixel(0, 1))
|
||||||
|
assert(4 == i:getPixel(1, 1))
|
||||||
|
i:clear(5)
|
||||||
|
assert(5 == i:getPixel(0, 0))
|
||||||
|
assert(5 == i:getPixel(1, 0))
|
||||||
|
assert(5 == i:getPixel(0, 1))
|
||||||
|
assert(5 == i:getPixel(1, 1))
|
||||||
|
|
||||||
|
print("transparentColor = ", transparentColor)
|
||||||
|
assert(transparentColor == i.spec.transparentColor)
|
||||||
|
|
||||||
|
i:clear() -- Image:clear() clears with i.spec.transparentColor by default
|
||||||
|
assert(transparentColor == i:getPixel(0, 0))
|
||||||
|
assert(transparentColor == i:getPixel(1, 0))
|
||||||
|
assert(transparentColor == i:getPixel(0, 1))
|
||||||
|
assert(transparentColor == i:getPixel(1, 1))
|
||||||
|
end
|
||||||
|
test_clear(ColorMode.RGB, 0)
|
||||||
|
test_clear(ColorMode.GRAYSCALE, 0)
|
||||||
|
test_clear(ColorMode.INDEXED, 0)
|
||||||
|
test_clear(ColorMode.INDEXED, 255)
|
||||||
|
|
||||||
|
-- Image:drawSprite
|
||||||
|
do
|
||||||
|
local spr = Sprite(4, 4)
|
||||||
|
local cel = spr.cels[1]
|
||||||
|
cel.image:putPixel(0, 0, pc.rgba(255, 0, 0, 255))
|
||||||
|
cel.image:putPixel(1, 0, pc.rgba(0, 255, 0, 255))
|
||||||
|
cel.image:putPixel(0, 1, pc.rgba(0, 0, 255, 255))
|
||||||
|
cel.image:putPixel(1, 1, pc.rgba(255, 255, 0, 255))
|
||||||
|
|
||||||
|
local r = Image(spr.spec) -- render
|
||||||
|
r:drawSprite(spr, 1, 0, 0)
|
||||||
|
|
||||||
|
assert(r:getPixel(0, 0) == pc.rgba(255, 0, 0, 255))
|
||||||
|
assert(r:getPixel(1, 0) == pc.rgba(0, 255, 0, 255))
|
||||||
|
assert(r:getPixel(0, 1) == pc.rgba(0, 0, 255, 255))
|
||||||
|
assert(r:getPixel(1, 1) == pc.rgba(255, 255, 0, 255))
|
||||||
|
|
||||||
|
r = Image(3, 3, spr.colorMode)
|
||||||
|
r:drawSprite(spr, 1, Point{x=1, y=1})
|
||||||
|
assert(r:getPixel(0, 0) == pc.rgba(0, 0, 0, 0))
|
||||||
|
assert(r:getPixel(1, 0) == pc.rgba(0, 0, 0, 0))
|
||||||
|
assert(r:getPixel(2, 0) == pc.rgba(0, 0, 0, 0))
|
||||||
|
assert(r:getPixel(0, 1) == pc.rgba(0, 0, 0, 0))
|
||||||
|
assert(r:getPixel(1, 1) == pc.rgba(255, 0, 0, 255))
|
||||||
|
assert(r:getPixel(2, 1) == pc.rgba(0, 255, 0, 255))
|
||||||
|
assert(r:getPixel(0, 2) == pc.rgba(0, 0, 0, 0))
|
||||||
|
assert(r:getPixel(1, 2) == pc.rgba(0, 0, 255, 255))
|
||||||
|
assert(r:getPixel(2, 2) == pc.rgba(255, 255, 0, 255))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Image:drawPixel with indexed color
|
||||||
|
do
|
||||||
|
local a = Sprite(32, 32, ColorMode.INDEXED)
|
||||||
|
local i = a.cels[1].image
|
||||||
|
assert(i:getPixel(0, 0) == 0)
|
||||||
|
assert(i:getPixel(1, 0) == 0)
|
||||||
|
assert(i:getPixel(2, 0) == 0)
|
||||||
|
i:drawPixel(0, 0, Color{ index=2 })
|
||||||
|
i:drawPixel(1, 0, Color{ index=3 }.index)
|
||||||
|
i:drawPixel(2, 0, Color(4))
|
||||||
|
assert(i:getPixel(0, 0) == 2)
|
||||||
|
assert(i:getPixel(1, 0) == 3)
|
||||||
|
assert(i:getPixel(2, 0) == 4)
|
||||||
|
end
|
136
tests/scripts/events.lua
Normal file
136
tests/scripts/events.lua
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
-- Copyright (C) 2021 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')
|
||||||
|
|
||||||
|
-- Test app.events
|
||||||
|
do
|
||||||
|
local i = 0
|
||||||
|
local listener = app.events:on('sitechange',
|
||||||
|
function() i = i + 1 end)
|
||||||
|
assert(i == 0)
|
||||||
|
local a = Sprite(32, 32)
|
||||||
|
expect_eq(a, app.activeSprite)
|
||||||
|
expect_eq(1, i)
|
||||||
|
local b = Sprite(32, 32)
|
||||||
|
expect_eq(b, app.activeSprite)
|
||||||
|
expect_eq(2, i)
|
||||||
|
app.activeSprite = a
|
||||||
|
expect_eq(3, i)
|
||||||
|
app.events:off(listener)
|
||||||
|
app.activeSprite = b
|
||||||
|
expect_eq(3, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local pref = app.preferences
|
||||||
|
pref.color_bar.fg_color = Color(0, 0, 0)
|
||||||
|
pref.color_bar.bg_color = Color(0, 0, 0)
|
||||||
|
|
||||||
|
local fg, bg = 0, 0
|
||||||
|
local a = app.events:on('fgcolorchange', function() fg = fg + 1 end)
|
||||||
|
local b = app.events:on('bgcolorchange', function() bg = bg + 1 end)
|
||||||
|
assert(fg == 0)
|
||||||
|
assert(bg == 0)
|
||||||
|
|
||||||
|
pref.color_bar.fg_color = Color(255, 0, 0)
|
||||||
|
pref.color_bar.bg_color = Color(255, 0, 0)
|
||||||
|
assert(fg == 1)
|
||||||
|
assert(bg == 1)
|
||||||
|
pref.color_bar.fg_color = Color(255, 0, 0) -- No change (same color)
|
||||||
|
assert(fg == 1)
|
||||||
|
pref.color_bar.fg_color = Color(0, 0, 0)
|
||||||
|
assert(fg == 2)
|
||||||
|
app.events:off(a)
|
||||||
|
app.events:off(b)
|
||||||
|
pref.color_bar.fg_color = Color(255, 0, 0)
|
||||||
|
assert(fg == 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test Sprite.events
|
||||||
|
do
|
||||||
|
local spr = Sprite(32, 64)
|
||||||
|
local changes = 0
|
||||||
|
function incChanges() changes = changes + 1 end
|
||||||
|
spr.events:on('change', incChanges)
|
||||||
|
expect_eq(0, changes)
|
||||||
|
spr.width = 64
|
||||||
|
expect_eq(1, changes)
|
||||||
|
app.undo()
|
||||||
|
expect_eq(2, changes)
|
||||||
|
app.redo()
|
||||||
|
expect_eq(3, changes)
|
||||||
|
spr.events:off(incChanges)
|
||||||
|
app.undo()
|
||||||
|
expect_eq(3, changes)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Multiple listeners
|
||||||
|
do
|
||||||
|
local spr = Sprite(2, 2)
|
||||||
|
local ai, bi = 0, 0
|
||||||
|
function a() ai = ai + 1 end
|
||||||
|
function b() bi = bi + 1 end
|
||||||
|
|
||||||
|
spr.events:on('change', a)
|
||||||
|
spr.events:on('change', b)
|
||||||
|
spr.width = 4
|
||||||
|
expect_eq(1, ai)
|
||||||
|
expect_eq(1, bi)
|
||||||
|
|
||||||
|
spr.events:off(a)
|
||||||
|
spr.width = 8
|
||||||
|
expect_eq(1, ai)
|
||||||
|
expect_eq(2, bi)
|
||||||
|
|
||||||
|
spr.events:off(b)
|
||||||
|
spr.width = 16
|
||||||
|
expect_eq(1, ai)
|
||||||
|
expect_eq(2, bi)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Avoid removing invalid listener when we use Events:off(function)
|
||||||
|
do
|
||||||
|
local spr = Sprite(2, 2)
|
||||||
|
|
||||||
|
local i = 0
|
||||||
|
function inc() i = i + 1 end
|
||||||
|
spr.events:on('change', inc)
|
||||||
|
|
||||||
|
spr.width = 4
|
||||||
|
expect_eq(1, i)
|
||||||
|
|
||||||
|
app.events:off(inc)
|
||||||
|
spr.width = 8
|
||||||
|
|
||||||
|
-- If this fails is because app.events:off(inc) removed the sprite
|
||||||
|
-- listener instead of doing nothing.
|
||||||
|
expect_eq(2, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Accessing Sprite.events when closing the same sprite will call
|
||||||
|
-- push_sprite_events() creating a new app::script::SpriteEvents
|
||||||
|
-- instance again even when we've just destroyed the old one (because
|
||||||
|
-- we're just closing the sprite).
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
function onSpriteChange()
|
||||||
|
-- Do nothing
|
||||||
|
end
|
||||||
|
-- Here we access s.events for first time, creating the
|
||||||
|
-- app::script::SpriteEvents for this sprite.
|
||||||
|
s.events:on('change', onSpriteChange)
|
||||||
|
function onSiteChange()
|
||||||
|
-- Accessing s.events again on 'sitechange' when we're just
|
||||||
|
-- closing the sprite, re-generating its SpriteEvents instance.
|
||||||
|
-- We've to have special care of this case.
|
||||||
|
s.events:off(onSpriteChange)
|
||||||
|
end
|
||||||
|
app.events:on('sitechange', onSiteChange)
|
||||||
|
-- Closing the sprite will create a 'sitechange' event calling
|
||||||
|
-- onSiteChange() function.
|
||||||
|
s:close()
|
||||||
|
app.events:off(onSiteChange)
|
||||||
|
end
|
95
tests/scripts/frames.lua
Normal file
95
tests/scripts/frames.lua
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
-- Copyright (C) 2018 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local a = Sprite(32, 32)
|
||||||
|
assert(#a.frames == 1)
|
||||||
|
assert(a.frames[1].frameNumber == 1)
|
||||||
|
assert(a.frames[1].duration == 0.1)
|
||||||
|
a.frames[1].duration = 0.2
|
||||||
|
assert(a.frames[1].duration == 0.2)
|
||||||
|
assert(a.layers[1]:cel(1) ~= nil)
|
||||||
|
|
||||||
|
-- Sprite:newEmptyFrame()
|
||||||
|
local fr0 = a:newEmptyFrame()
|
||||||
|
assert(fr0.frameNumber == 2) -- returned the second frame
|
||||||
|
assert(#a.frames == 2)
|
||||||
|
assert(a.frames[1].frameNumber == 1)
|
||||||
|
assert(a.frames[2].frameNumber == 2)
|
||||||
|
assert(a.frames[1].duration == 0.2)
|
||||||
|
assert(a.frames[2].duration == 0.2) -- the duration is copied
|
||||||
|
assert(a.layers[1]:cel(1) ~= nil)
|
||||||
|
assert(a.layers[1]:cel(fr0) == nil) -- no cel
|
||||||
|
assert(fr0 == a.frames[2])
|
||||||
|
a:deleteFrame(fr0)
|
||||||
|
assert(#a.frames == 1)
|
||||||
|
|
||||||
|
-- Sprite:newFrame() without arguments
|
||||||
|
local fr = a:newFrame()
|
||||||
|
assert(fr.frameNumber == 2) -- returned the second frame
|
||||||
|
assert(#a.frames == 2)
|
||||||
|
assert(a.frames[1].frameNumber == 1)
|
||||||
|
assert(a.frames[2].frameNumber == 2)
|
||||||
|
assert(a.frames[1].duration == 0.2)
|
||||||
|
assert(a.frames[2].duration == 0.2)
|
||||||
|
assert(fr == a.frames[2])
|
||||||
|
|
||||||
|
fr.duration = 0.3
|
||||||
|
assert(a.frames[1].duration == 0.2)
|
||||||
|
assert(a.frames[2].duration == 0.3)
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
for k,v in ipairs(a.frames) do
|
||||||
|
assert(i == k)
|
||||||
|
assert(v == a.frames[k])
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
|
||||||
|
a:deleteFrame(1)
|
||||||
|
assert(#a.frames == 1)
|
||||||
|
assert(a.frames[1].duration == 0.3)
|
||||||
|
|
||||||
|
-- TODO This is a big issue, if we add/delete frames, we don't
|
||||||
|
-- update frame objects, they are still pointing to the same frame
|
||||||
|
-- number, which could lead to confusion.
|
||||||
|
assert(fr.frameNumber == 2)
|
||||||
|
fr.duration = 1 -- This is a do nothing operation
|
||||||
|
|
||||||
|
-- Sprite:newEmptyFrame(n)
|
||||||
|
local fr2 = a:newEmptyFrame(1)
|
||||||
|
assert(#a.frames == 2)
|
||||||
|
assert(fr2.frameNumber == 1) -- returned the first frame
|
||||||
|
print(a.frames[1].duration)
|
||||||
|
assert(a.frames[1].duration == 0.3) -- the duration is copied from the frame
|
||||||
|
assert(a.frames[2].duration == 0.3)
|
||||||
|
assert(fr2 == a.frames[1])
|
||||||
|
assert(a.layers[1]:cel(1) == nil)
|
||||||
|
assert(a.layers[1]:cel(2) ~= nil)
|
||||||
|
|
||||||
|
-- Sprite:newFrame(n)
|
||||||
|
local fr3 = a:newFrame(2)
|
||||||
|
assert(#a.frames == 3)
|
||||||
|
assert(fr3.frameNumber == 2) -- returned the second frame
|
||||||
|
assert(a.frames[1].duration == 0.3)
|
||||||
|
assert(a.frames[2].duration == 0.3) -- copied duration from old frame 2
|
||||||
|
assert(a.frames[3].duration == 0.3)
|
||||||
|
local cel1 = a.layers[1]:cel(1)
|
||||||
|
local cel2 = a.layers[1]:cel(2)
|
||||||
|
local cel3 = a.layers[1]:cel(3)
|
||||||
|
assert(cel1 == nil)
|
||||||
|
assert(cel2 ~= nil)
|
||||||
|
assert(cel3 ~= nil)
|
||||||
|
print(cel2.image.spec.colorMode)
|
||||||
|
print(cel2.image.spec.width)
|
||||||
|
print(cel2.image.spec.height)
|
||||||
|
print(cel3.image.spec.colorMode)
|
||||||
|
print(cel3.image.spec.width)
|
||||||
|
print(cel3.image.spec.height)
|
||||||
|
assert(cel2.image.spec == cel3.image.spec)
|
||||||
|
assert(fr3.previous == a.frames[1])
|
||||||
|
assert(fr3 == a.frames[2])
|
||||||
|
assert(fr3.next == a.frames[3])
|
||||||
|
end
|
276
tests/scripts/image.lua
Normal file
276
tests/scripts/image.lua
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
-- Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
dofile('./test_utils.lua')
|
||||||
|
|
||||||
|
local rgba = app.pixelColor.rgba
|
||||||
|
|
||||||
|
local a = Image(32, 64)
|
||||||
|
assert(a.width == 32)
|
||||||
|
assert(a.height == 64)
|
||||||
|
assert(a.colorMode == ColorMode.RGB) -- RGB by default
|
||||||
|
assert(a.rowStride == 32*4)
|
||||||
|
assert(a:isEmpty())
|
||||||
|
assert(a:isPlain(rgba(0, 0, 0, 0)))
|
||||||
|
assert(a:isPlain(0))
|
||||||
|
|
||||||
|
do
|
||||||
|
local b = Image(32, 64, ColorMode.INDEXED)
|
||||||
|
assert(b.width == 32)
|
||||||
|
assert(b.height == 64)
|
||||||
|
assert(b.colorMode == ColorMode.INDEXED)
|
||||||
|
assert(b.rowStride == 32*1)
|
||||||
|
|
||||||
|
local c = Image{ width=32, height=64, colorMode=ColorMode.INDEXED }
|
||||||
|
assert(c.width == 32)
|
||||||
|
assert(c.height == 64)
|
||||||
|
assert(c.colorMode == ColorMode.INDEXED)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get/put RGBA pixels
|
||||||
|
do
|
||||||
|
for y=0,a.height-1 do
|
||||||
|
for x=0,a.width-1 do
|
||||||
|
a:putPixel(x, y, rgba(x, y, x+y, x-y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(not a:isEmpty())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clone
|
||||||
|
do
|
||||||
|
local c = Image(a)
|
||||||
|
local d = a:clone()
|
||||||
|
assert(c.width == 32)
|
||||||
|
assert(c.height == 64)
|
||||||
|
assert(c.colorMode == ColorMode.RGB)
|
||||||
|
assert(c.width == d.width)
|
||||||
|
assert(c.height == d.height)
|
||||||
|
assert(c.colorMode == d.colorMode)
|
||||||
|
|
||||||
|
-- Get RGB pixels
|
||||||
|
for y=0,c.height-1 do
|
||||||
|
for x=0,c.width-1 do
|
||||||
|
local expectedColor = rgba(x, y, x+y, x-y)
|
||||||
|
assert(c:getPixel(x, y) == expectedColor)
|
||||||
|
assert(d:getPixel(x, y) == expectedColor)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clone a rectangle
|
||||||
|
local e = Image(c, Rectangle(1, 1, 4, 5))
|
||||||
|
print(e.width)
|
||||||
|
print(e.height)
|
||||||
|
assert(e.width == 4)
|
||||||
|
assert(e.height == 5)
|
||||||
|
|
||||||
|
-- Empty clone
|
||||||
|
assert(nil == Image(c, Rectangle(1, 1, 0, 0)))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Patch
|
||||||
|
do
|
||||||
|
local spr = Sprite(256, 256)
|
||||||
|
local image = app.site.image
|
||||||
|
local copy = image:clone()
|
||||||
|
assert(image:getPixel(0, 0) == 0)
|
||||||
|
for y=0,copy.height-1 do
|
||||||
|
for x=0,copy.width-1 do
|
||||||
|
copy:putPixel(x, y, rgba(255-x, 255-y, 0, 255))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
image:putImage(copy)
|
||||||
|
assert(image:getPixel(0, 0) == rgba(255, 255, 0, 255))
|
||||||
|
assert(image:getPixel(255, 255) == rgba(0, 0, 0, 255))
|
||||||
|
app.undo()
|
||||||
|
assert(image:getPixel(0, 0) == rgba(0, 0, 0, 0))
|
||||||
|
assert(image:getPixel(255, 255) == rgba(0, 0, 0, 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Load/Save
|
||||||
|
do
|
||||||
|
local a = Image{ fromFile="sprites/1empty3.aseprite" }
|
||||||
|
assert(a.width == 32)
|
||||||
|
assert(a.height == 32)
|
||||||
|
a:saveAs("_test_oneframe.png")
|
||||||
|
|
||||||
|
local b = Image{ fromFile="_test_oneframe.png" }
|
||||||
|
assert(b.width == 32)
|
||||||
|
assert(b.height == 32)
|
||||||
|
for y=0,a.height-1 do
|
||||||
|
for x=0,a.width-1 do
|
||||||
|
assert(a:getPixel(x, y) == b:getPixel(x, y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save indexed image and load and check that the palette is the same
|
||||||
|
do
|
||||||
|
local spr = Sprite{ fromFile="sprites/abcd.aseprite" }
|
||||||
|
local img = Image{ fromFile="sprites/abcd.aseprite" }
|
||||||
|
spr.cels[1].image:saveAs("_test_palette_a.png")
|
||||||
|
img:saveAs("_test_palette_b.png") -- This file will contain a black palette
|
||||||
|
img:saveAs{ filename="_test_palette_c.png", palette=spr.palettes[1] }
|
||||||
|
|
||||||
|
local a = Sprite{ fromFile="_test_palette_a.png" }
|
||||||
|
local b = Sprite{ fromFile="_test_palette_b.png" }
|
||||||
|
local c = Sprite{ fromFile="_test_palette_c.png" }
|
||||||
|
|
||||||
|
assert(a.width == 5)
|
||||||
|
assert(a.height == 7)
|
||||||
|
assert(b.width == 32)
|
||||||
|
assert(b.height == 32)
|
||||||
|
assert(c.width == 32)
|
||||||
|
assert(c.height == 32)
|
||||||
|
local bimg = b.cels[1].image
|
||||||
|
local cimg = c.cels[1].image
|
||||||
|
for y=0,31 do
|
||||||
|
for x=0,31 do
|
||||||
|
assert(bimg:getPixel(x, y) == cimg:getPixel(x, y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local apal = a.palettes[1]
|
||||||
|
local bpal = b.palettes[1]
|
||||||
|
local cpal = c.palettes[1]
|
||||||
|
-- Same palette in a and c
|
||||||
|
assert(#apal == #cpal)
|
||||||
|
for i=0,#apal-1 do
|
||||||
|
assert(apal:getColor(i) == cpal:getColor(i))
|
||||||
|
end
|
||||||
|
-- b should contain a complete black palette
|
||||||
|
assert(bpal:getColor(0) == Color(0, 0, 0, 0))
|
||||||
|
for i=1,#bpal-1 do
|
||||||
|
assert(bpal:getColor(i) == Color(0, 0, 0, 255))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resize image
|
||||||
|
do
|
||||||
|
local a = Sprite(3, 2)
|
||||||
|
local cel = a.cels[1]
|
||||||
|
assert(cel.bounds == Rectangle(0, 0, 3, 2))
|
||||||
|
local img = cel.image
|
||||||
|
local cols = { rgba(10, 60, 1), rgba(20, 50, 2), rgba(30, 40, 3),
|
||||||
|
rgba(40, 30, 4), rgba(50, 20, 5), rgba(60, 10, 6) }
|
||||||
|
array_to_pixels(cols, img)
|
||||||
|
expect_img(img, cols)
|
||||||
|
|
||||||
|
-- Test resize of a cel with origin=0,0
|
||||||
|
|
||||||
|
img:resize(img.width*2, img.height*2)
|
||||||
|
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 6, 4))
|
||||||
|
expect_eq(img.width, 6)
|
||||||
|
expect_eq(img.height, 4)
|
||||||
|
local cols2 = { cols[1],cols[1], cols[2],cols[2], cols[3],cols[3],
|
||||||
|
cols[1],cols[1], cols[2],cols[2], cols[3],cols[3],
|
||||||
|
cols[4],cols[4], cols[5],cols[5], cols[6],cols[6],
|
||||||
|
cols[4],cols[4], cols[5],cols[5], cols[6],cols[6] }
|
||||||
|
expect_img(img, cols2)
|
||||||
|
|
||||||
|
-- Undo
|
||||||
|
function undo()
|
||||||
|
app.undo()
|
||||||
|
img = cel.image -- TODO img shouldn't be invalidated, the resize operation should kept the image ID
|
||||||
|
end
|
||||||
|
undo()
|
||||||
|
|
||||||
|
-- Test a resize when cel origin > 0,0
|
||||||
|
cel.position = Point(2, 1)
|
||||||
|
expect_eq(cel.bounds, Rectangle(2, 1, 3, 2))
|
||||||
|
expect_img(img, cols)
|
||||||
|
img:resize{ width=6, height=4 }
|
||||||
|
expect_eq(cel.bounds, Rectangle(2, 1, 6, 4)) -- Position is not modified
|
||||||
|
expect_eq(img.width, 6)
|
||||||
|
expect_eq(img.height, 4)
|
||||||
|
|
||||||
|
undo()
|
||||||
|
img:resize{ size=Size(6, 4), pivot=Point(1, 1) }
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 0, 6, 4))
|
||||||
|
|
||||||
|
undo()
|
||||||
|
img:resize{ size=Size(6, 4), pivot=Point(3, 2) }
|
||||||
|
expect_eq(cel.bounds, Rectangle(-1, -1, 6, 4))
|
||||||
|
|
||||||
|
-- Test resize without cel
|
||||||
|
|
||||||
|
local img2 = Image(img)
|
||||||
|
expect_img(img2, cols2)
|
||||||
|
img2:resize(3, 2)
|
||||||
|
expect_img(img2, cols)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test v1.2.17 crashes
|
||||||
|
do
|
||||||
|
local defSpec = ImageSpec{ width=1, height=1, colorMode=ColorMode.RGB }
|
||||||
|
|
||||||
|
local img = Image() -- we create a 1x1 RGB image
|
||||||
|
assert(img ~= nil)
|
||||||
|
assert(img.spec == defSpec)
|
||||||
|
|
||||||
|
img = Image(nil)
|
||||||
|
assert(img ~= nil)
|
||||||
|
assert(img.spec == defSpec)
|
||||||
|
|
||||||
|
local spr = Sprite(32, 32, ColorMode.INDEXED)
|
||||||
|
spr.cels[1].image:putPixel(15, 15, 129)
|
||||||
|
img = Image(spr) -- we create a sprite render of the first frame
|
||||||
|
assert(img ~= nil)
|
||||||
|
assert(img.spec == spr.spec)
|
||||||
|
assert(img:getPixel(15, 15) == 129)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fix drawImage() when drawing in a cel image
|
||||||
|
do
|
||||||
|
local a = Image(3, 2, ColorMode.INDEXED)
|
||||||
|
array_to_pixels({ 0, 1, 2,
|
||||||
|
2, 3, 4 }, a)
|
||||||
|
|
||||||
|
local function test(b)
|
||||||
|
expect_img(b, { 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0 })
|
||||||
|
|
||||||
|
b:drawImage(a, Point(2, 1))
|
||||||
|
expect_img(b, { 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 1, 2,
|
||||||
|
0, 0, 2, 3, 4,
|
||||||
|
0, 0, 0, 0, 0 })
|
||||||
|
|
||||||
|
b:drawImage(a, Point(0, 1))
|
||||||
|
expect_img(b, { 0, 0, 0, 0, 0,
|
||||||
|
0, 1, 2, 1, 2,
|
||||||
|
2, 3, 4, 3, 4,
|
||||||
|
0, 0, 0, 0, 0 })
|
||||||
|
|
||||||
|
b:drawImage(a, Point(-1, 2))
|
||||||
|
expect_img(b, { 0, 0, 0, 0, 0,
|
||||||
|
0, 1, 2, 1, 2,
|
||||||
|
1, 2, 4, 3, 4,
|
||||||
|
3, 4, 0, 0, 0 })
|
||||||
|
|
||||||
|
b:drawImage(a, Point(0, 3))
|
||||||
|
expect_img(b, { 0, 0, 0, 0, 0,
|
||||||
|
0, 1, 2, 1, 2,
|
||||||
|
1, 2, 4, 3, 4,
|
||||||
|
0, 1, 2, 0, 0 })
|
||||||
|
|
||||||
|
b:drawImage(a, Point(0, 3)) -- Do nothing
|
||||||
|
expect_img(b, { 0, 0, 0, 0, 0,
|
||||||
|
0, 1, 2, 1, 2,
|
||||||
|
1, 2, 4, 3, 4,
|
||||||
|
0, 1, 2, 0, 0 })
|
||||||
|
end
|
||||||
|
|
||||||
|
local b = Image(5, 4, ColorMode.INDEXED)
|
||||||
|
test(b)
|
||||||
|
|
||||||
|
local s = Sprite(5, 4, ColorMode.INDEXED)
|
||||||
|
test(app.activeCel.image)
|
||||||
|
|
||||||
|
end
|
72
tests/scripts/image_iterator.lua
Normal file
72
tests/scripts/image_iterator.lua
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local pc = app.pixelColor
|
||||||
|
|
||||||
|
-- Iterate pixels
|
||||||
|
do
|
||||||
|
local spr = Sprite(2, 2)
|
||||||
|
local image = app.site.image
|
||||||
|
local colors = { pc.rgba(255, 0, 0, 255),
|
||||||
|
pc.rgba(0, 255, 0, 255),
|
||||||
|
pc.rgba(255, 0, 255, 255),
|
||||||
|
pc.rgba(255, 0, 255, 255) }
|
||||||
|
local xy = {
|
||||||
|
{ x=0, y=0 },
|
||||||
|
{ x=1, y=0 },
|
||||||
|
{ x=0, y=1 },
|
||||||
|
{ x=1, y=1 } }
|
||||||
|
|
||||||
|
local c = 1
|
||||||
|
for y=0,image.height-1 do
|
||||||
|
for x=0,image.width-1 do
|
||||||
|
image:putPixel(x, y, colors[c])
|
||||||
|
c = c+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
c = 1
|
||||||
|
for y=0,image.height-1 do
|
||||||
|
for x=0,image.width-1 do
|
||||||
|
assert(colors[c] == image:getPixel(x, y))
|
||||||
|
c = c+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
c = 1
|
||||||
|
for it in image:pixels() do
|
||||||
|
assert(colors[c] == it())
|
||||||
|
assert(xy[c].x == it.x)
|
||||||
|
assert(xy[c].y == it.y)
|
||||||
|
c = c+1
|
||||||
|
end
|
||||||
|
|
||||||
|
c = 0
|
||||||
|
for it in image:pixels{x=1, y=0, width=1, height=2} do
|
||||||
|
local i = 1 + it.y*2 + it.x
|
||||||
|
assert(colors[i] == it())
|
||||||
|
assert(xy[i].x == it.x)
|
||||||
|
assert(xy[i].y == it.y)
|
||||||
|
c = c + 1
|
||||||
|
end
|
||||||
|
assert(c == 2)
|
||||||
|
|
||||||
|
-- Iterating outside
|
||||||
|
for it in image:pixels{x=2, y=0, width=2, height=2} do
|
||||||
|
assert(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
c = 1
|
||||||
|
for it in image:pixels() do
|
||||||
|
it(pc.rgba(255, 32*c, 0, 255))
|
||||||
|
c = c+1
|
||||||
|
end
|
||||||
|
|
||||||
|
c = 1
|
||||||
|
for it in image:pixels() do
|
||||||
|
assert(pc.rgba(255, 32*c, 0, 255) == it())
|
||||||
|
c = c+1
|
||||||
|
end
|
||||||
|
end
|
47
tests/scripts/image_spec.lua
Normal file
47
tests/scripts/image_spec.lua
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
-- Copyright (C) 2018 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local spec = ImageSpec{colorMode=ColorMode.GRAY, width=32, height=64, transparentColor=2}
|
||||||
|
assert(spec.colorMode == ColorMode.GRAY)
|
||||||
|
assert(spec.width == 32)
|
||||||
|
assert(spec.height == 64)
|
||||||
|
assert(spec.transparentColor == 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local sprite = Sprite(32, 64, ColorMode.INDEXED)
|
||||||
|
assert(sprite.width == 32)
|
||||||
|
assert(sprite.height == 64)
|
||||||
|
assert(sprite.colorMode == ColorMode.INDEXED)
|
||||||
|
|
||||||
|
local sprite2 = Sprite(sprite.spec)
|
||||||
|
assert(sprite2.width == 32)
|
||||||
|
assert(sprite2.height == 64)
|
||||||
|
assert(sprite2.colorMode == ColorMode.INDEXED)
|
||||||
|
|
||||||
|
local spec = sprite.spec
|
||||||
|
assert(spec.width == 32)
|
||||||
|
assert(spec.height == 64)
|
||||||
|
assert(spec.colorMode == ColorMode.INDEXED)
|
||||||
|
|
||||||
|
spec.width = 30
|
||||||
|
spec.height = 40
|
||||||
|
spec.colorMode = ColorMode.RGB
|
||||||
|
assert(spec.width == 30)
|
||||||
|
assert(spec.height == 40)
|
||||||
|
assert(spec.colorMode == ColorMode.RGB)
|
||||||
|
|
||||||
|
local image = Image(spec)
|
||||||
|
assert(image.width == 30)
|
||||||
|
assert(image.height == 40)
|
||||||
|
assert(image.colorMode == ColorMode.RGB)
|
||||||
|
|
||||||
|
print(image.spec.width, image.spec.height, image.spec.colorMode)
|
||||||
|
assert(image.spec.width == 30)
|
||||||
|
assert(image.spec.height == 40)
|
||||||
|
assert(image.spec.colorMode == ColorMode.RGB)
|
||||||
|
end
|
75
tests/scripts/import_sprite_sheet_command.lua
Normal file
75
tests/scripts/import_sprite_sheet_command.lua
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
-- Copyright (C) 2021 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')
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(8, 4, ColorMode.INDEXED)
|
||||||
|
assert(#s.cels == 1)
|
||||||
|
|
||||||
|
local i = s.cels[1].image
|
||||||
|
array_to_pixels({ 0, 1, 2, 3, 3, 2, 1, 0,
|
||||||
|
1, 2, 3, 4, 4, 3, 2, 1,
|
||||||
|
1, 2, 3, 4, 4, 3, 2, 1,
|
||||||
|
0, 1, 2, 3, 3, 2, 1, 0 }, i)
|
||||||
|
|
||||||
|
app.command.ImportSpriteSheet{
|
||||||
|
ui=false,
|
||||||
|
type=SpriteSheetType.ROWS,
|
||||||
|
frameBounds=Rectangle(0, 0, 4, 4)
|
||||||
|
}
|
||||||
|
assert(#s.cels == 2)
|
||||||
|
expect_img(s.cels[1].image,
|
||||||
|
{ 0, 1, 2, 3,
|
||||||
|
1, 2, 3, 4,
|
||||||
|
1, 2, 3, 4,
|
||||||
|
0, 1, 2, 3 })
|
||||||
|
expect_img(s.cels[2].image,
|
||||||
|
{ 3, 2, 1, 0,
|
||||||
|
4, 3, 2, 1,
|
||||||
|
4, 3, 2, 1,
|
||||||
|
3, 2, 1, 0 })
|
||||||
|
|
||||||
|
app.undo();
|
||||||
|
app.command.ImportSpriteSheet{
|
||||||
|
ui=false,
|
||||||
|
type=SpriteSheetType.ROWS,
|
||||||
|
frameBounds=Rectangle(0, 0, 2, 3)
|
||||||
|
}
|
||||||
|
assert(#s.cels == 4)
|
||||||
|
expect_img(s.cels[1].image,
|
||||||
|
{ 0, 1,
|
||||||
|
1, 2,
|
||||||
|
1, 2 })
|
||||||
|
expect_img(s.cels[2].image,
|
||||||
|
{ 2, 3,
|
||||||
|
3, 4,
|
||||||
|
3, 4 })
|
||||||
|
expect_img(s.cels[3].image,
|
||||||
|
{ 3, 2,
|
||||||
|
4, 3,
|
||||||
|
4, 3 })
|
||||||
|
expect_img(s.cels[4].image,
|
||||||
|
{ 1, 0,
|
||||||
|
2, 1,
|
||||||
|
2, 1 })
|
||||||
|
|
||||||
|
|
||||||
|
app.undo();
|
||||||
|
app.command.ImportSpriteSheet{
|
||||||
|
ui=false,
|
||||||
|
type=SpriteSheetType.ROWS,
|
||||||
|
frameBounds=Rectangle(1, 1, 2, 2),
|
||||||
|
padding=Size(2, 0)
|
||||||
|
}
|
||||||
|
assert(#s.cels == 2)
|
||||||
|
expect_img(s.cels[1].image,
|
||||||
|
{ 2, 3,
|
||||||
|
2, 3 })
|
||||||
|
expect_img(s.cels[2].image,
|
||||||
|
{ 3, 2,
|
||||||
|
3, 2 })
|
||||||
|
|
||||||
|
end
|
285
tests/scripts/inks.lua
Normal file
285
tests/scripts/inks.lua
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
-- Copyright (C) 2020-2022 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')
|
||||||
|
|
||||||
|
local colorModes = { ColorMode.RGB,
|
||||||
|
ColorMode.GRAY,
|
||||||
|
ColorMode.INDEXED }
|
||||||
|
|
||||||
|
local pencil = "pencil"
|
||||||
|
local pc = app.pixelColor
|
||||||
|
|
||||||
|
local function gray(g)
|
||||||
|
return pc.graya(g, 255)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_inks(colorMode)
|
||||||
|
-- Test ink over a transparent sprite
|
||||||
|
local s = Sprite(3, 3, colorMode)
|
||||||
|
local p, a, b, c, d
|
||||||
|
if colorMode == ColorMode.GRAY then
|
||||||
|
p = s.palettes[1]
|
||||||
|
a, b, c, d = gray(0), gray(64), gray(128), gray(255)
|
||||||
|
else
|
||||||
|
p = Palette()
|
||||||
|
p:resize(4)
|
||||||
|
p:setColor(0, Color(0, 0, 0))
|
||||||
|
p:setColor(1, Color(64, 64, 64))
|
||||||
|
p:setColor(2, Color(128, 128, 128))
|
||||||
|
p:setColor(3, Color(255, 255, 255))
|
||||||
|
s:setPalette(p)
|
||||||
|
|
||||||
|
a, b, c, d = 0, 1, 2, 3
|
||||||
|
if colorMode == ColorMode.RGB then
|
||||||
|
a = p:getColor(a).rgbaPixel
|
||||||
|
b = p:getColor(b).rgbaPixel
|
||||||
|
c = p:getColor(c).rgbaPixel
|
||||||
|
d = p:getColor(d).rgbaPixel
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- With simple ink opacity doesn't have affect (always the color)
|
||||||
|
local opacities = { 0, 128, 255 }
|
||||||
|
for i = 1,#opacities do
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 0, 0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
0, 0, 0 })
|
||||||
|
app.useTool{ tool=pencil, color=d, points={ Point(0, 0), Point(2, 2) },
|
||||||
|
ink=Ink.SIMPLE, opacity=opacities[i] }
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ d, 0, 0,
|
||||||
|
0, d, 0,
|
||||||
|
0, 0, d })
|
||||||
|
if i < #opacities then app.undo() end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check that painting with transparent index (color) on a
|
||||||
|
-- transparent layer (using any value of opacity) with alpha
|
||||||
|
-- compositing doesn't modify pixels
|
||||||
|
for i = 1,#opacities do
|
||||||
|
app.useTool{ tool=pencil, color=0, points={ Point(1, 1) },
|
||||||
|
ink=Ink.ALPHA_COMPOSITING, opacity=opacities[i] }
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ d, 0, 0,
|
||||||
|
0, d, 0,
|
||||||
|
0, 0, d })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert to background layer
|
||||||
|
app.bgColor = Color{ index=0 }
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, color=d, points={ Point(0, 1), Point(2, 1) },
|
||||||
|
ink=Ink.ALPHA_COMPOSITING, opacity=64 }
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ d, a, a,
|
||||||
|
b, d, b,
|
||||||
|
a, a, d })
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, color=d, points={ Point(0, 1) },
|
||||||
|
ink=Ink.ALPHA_COMPOSITING, opacity=86 }
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ d, a, a,
|
||||||
|
c, d, b,
|
||||||
|
a, a, d })
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- Inks with custom brushes
|
||||||
|
|
||||||
|
function test_custom_brush_inks(brushColorMode)
|
||||||
|
-- Colors in the brush image (ba, bb, bc, bd)
|
||||||
|
local ba, bb, bc, bd
|
||||||
|
if brushColorMode == ColorMode.RGB then
|
||||||
|
ba = Color(0, 0, 0)
|
||||||
|
bb = Color(64, 64, 64)
|
||||||
|
bc = Color(128, 128, 128)
|
||||||
|
bd = Color(255, 255, 255)
|
||||||
|
elseif brushColorMode == ColorMode.GRAY then
|
||||||
|
ba, bb, bc, bd = gray(0), gray(64), gray(128), gray(255)
|
||||||
|
else
|
||||||
|
ba, bb, bc, bd = 0, 1, 2, 3
|
||||||
|
end
|
||||||
|
|
||||||
|
local brushImage = Image(2, 2, brushColorMode)
|
||||||
|
array_to_pixels({ 0, bd,
|
||||||
|
bc, 0 }, brushImage)
|
||||||
|
local brush = Brush(brushImage)
|
||||||
|
|
||||||
|
-- da, db, dc, dd are the final result after painting the custom
|
||||||
|
-- brush in the sprite
|
||||||
|
local ra, rb, rc, rd
|
||||||
|
if s.colorMode ~= ColorMode.INDEXED and
|
||||||
|
brushColorMode == ColorMode.INDEXED then
|
||||||
|
-- For indexed images we take the index of the brush and use the
|
||||||
|
-- sprite palette, we are not sure if this in the future might
|
||||||
|
-- change, e.g. having the original palette that was used to
|
||||||
|
-- create the brush integrated to the brush itself, in that case
|
||||||
|
-- we should convert the brush index using the same brush
|
||||||
|
-- palette (instead of the sprite palette).
|
||||||
|
--
|
||||||
|
-- TODO check BrushInkProcessingBase comment for more information
|
||||||
|
if s.colorMode == ColorMode.RGB then
|
||||||
|
ra, rb, rc, rd =
|
||||||
|
p:getColor(ba).rgbaPixel,
|
||||||
|
p:getColor(bb).rgbaPixel,
|
||||||
|
p:getColor(bc).rgbaPixel,
|
||||||
|
p:getColor(bd).rgbaPixel
|
||||||
|
else
|
||||||
|
ra, rb, rc, rd =
|
||||||
|
p:getColor(ba).grayPixel,
|
||||||
|
p:getColor(bb).grayPixel,
|
||||||
|
p:getColor(bc).grayPixel,
|
||||||
|
p:getColor(bd).grayPixel
|
||||||
|
end
|
||||||
|
else
|
||||||
|
ra, rb, rc, rd = a, b, c, d
|
||||||
|
end
|
||||||
|
|
||||||
|
array_to_pixels({ a, a, a,
|
||||||
|
a, a, a,
|
||||||
|
a, a, a }, app.activeImage)
|
||||||
|
|
||||||
|
-- Simple
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ a, a, a,
|
||||||
|
a, a, a,
|
||||||
|
a, a, a })
|
||||||
|
app.useTool{ tool=pencil, brush=brush, points={ Point(2, 2) },
|
||||||
|
ink=Ink.SIMPLE }
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ a, a, a,
|
||||||
|
a, a, rd,
|
||||||
|
a, rc, a })
|
||||||
|
|
||||||
|
-- Alpha Compositing
|
||||||
|
app.useTool{ tool=pencil, brush=brush, points={ Point(1, 1) },
|
||||||
|
ink=Ink.ALPHA_COMPOSITING, opacity=255 }
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ a, rd, a,
|
||||||
|
rc, a, rd,
|
||||||
|
a, rc, a })
|
||||||
|
|
||||||
|
local qc, qd
|
||||||
|
if s.colorMode == ColorMode.GRAY and
|
||||||
|
brushColorMode == ColorMode.INDEXED then
|
||||||
|
qc = gray(pc.grayaV(rc)/2)
|
||||||
|
qd = gray(pc.grayaV(rd)/2)
|
||||||
|
else
|
||||||
|
qc, qd = rb, rc
|
||||||
|
end
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=brush, points={ Point(1, 2) },
|
||||||
|
ink=Ink.ALPHA_COMPOSITING, opacity=128 }
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ a, rd, a,
|
||||||
|
rc, qd, rd,
|
||||||
|
qc, rc, a })
|
||||||
|
|
||||||
|
-- TODO test Lock Alpha, Copy Color+Alpha, Shading...
|
||||||
|
end
|
||||||
|
|
||||||
|
for j = 1,#colorModes do
|
||||||
|
test_custom_brush_inks(colorModes[j])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_alpha_compositing_on_indexed_with_full_opacity_and_repeated_colors_in_palette()
|
||||||
|
local s = Sprite(1, 1, ColorMode.INDEXED)
|
||||||
|
local p = Palette()
|
||||||
|
p:resize(5)
|
||||||
|
p:setColor(0, Color(0, 0, 0))
|
||||||
|
p:setColor(1, Color(64, 64, 64))
|
||||||
|
p:setColor(2, Color(128, 128, 128))
|
||||||
|
p:setColor(3, Color(128, 128, 128))
|
||||||
|
p:setColor(4, Color(255, 255, 255))
|
||||||
|
s:setPalette(p)
|
||||||
|
|
||||||
|
local inks = { Ink.SIMPLE, Ink.ALPHA_COMPOSITING }
|
||||||
|
|
||||||
|
-- k=1 -> transparent layer
|
||||||
|
-- k=2 -> background layer
|
||||||
|
for k=1,2 do
|
||||||
|
if k == 2 then app.command.BackgroundFromLayer() end
|
||||||
|
-- i=1 -> simple ink
|
||||||
|
-- i=2 -> alpha compositing ink
|
||||||
|
for i = 1,2 do
|
||||||
|
-- j=color index
|
||||||
|
for j = 0,4 do
|
||||||
|
expect_img(app.activeImage, { 0 })
|
||||||
|
app.useTool{ tool="pencil", color=j, points={ Point(0, 0) },
|
||||||
|
ink=inks[i], opacity=255 }
|
||||||
|
expect_img(app.activeImage, { j })
|
||||||
|
app.undo()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1,#colorModes do
|
||||||
|
test_inks(colorModes[i])
|
||||||
|
end
|
||||||
|
test_alpha_compositing_on_indexed_with_full_opacity_and_repeated_colors_in_palette()
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- Test painting with transparent color on indexed
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(2, 2, ColorMode.INDEXED)
|
||||||
|
s.transparentColor = 0
|
||||||
|
app.bgColor = 0
|
||||||
|
app.command.BackgroundFromLayer()
|
||||||
|
assert(app.activeLayer.isBackground)
|
||||||
|
expect_img(app.activeImage, { 0, 0,
|
||||||
|
0, 0 })
|
||||||
|
|
||||||
|
app.useTool{ tool="pencil", color=Color{r=0,g=0,b=0},
|
||||||
|
points={ Point(0, 0) },
|
||||||
|
ink=Ink.SIMPLE }
|
||||||
|
expect_img(app.activeImage, { 0, 0,
|
||||||
|
0, 0 })
|
||||||
|
|
||||||
|
-- Test that painting in the background layer with transparent color
|
||||||
|
-- with alpha compositing and all opacity=255, will use the transparent
|
||||||
|
-- index anyway. Reported here: https://github.com/aseprite/aseprite/issues/3047
|
||||||
|
app.useTool{ tool="pencil", color=0,
|
||||||
|
points={ Point(0, 0) },
|
||||||
|
ink=Ink.ALPHA_COMPOSITING,
|
||||||
|
opacity=255 }
|
||||||
|
expect_img(app.activeImage, { 0, 0,
|
||||||
|
0, 0 })
|
||||||
|
|
||||||
|
-- Other cases should keep working
|
||||||
|
local p = s.palettes[1]
|
||||||
|
|
||||||
|
-- palette with only 3 colors: white, gray (50%), black
|
||||||
|
p:setColor(0, Color{ r=255, g=255, b=255 })
|
||||||
|
p:setColor(1, Color{ r=128, g=128, b=128 })
|
||||||
|
p:setColor(2, Color{ r=0, g=0, b=0 })
|
||||||
|
app.useTool{ tool="paint_bucket", color=2,
|
||||||
|
points={ Point(0, 0) },
|
||||||
|
ink=Ink.SIMPLE }
|
||||||
|
expect_img(app.activeImage, { 2, 2,
|
||||||
|
2, 2 })
|
||||||
|
|
||||||
|
-- White over black w/opacity=50% => gray
|
||||||
|
app.useTool{ tool="pencil", color=0,
|
||||||
|
points={ Point(0, 0) },
|
||||||
|
ink=Ink.ALPHA_COMPOSITING,
|
||||||
|
opacity=128 }
|
||||||
|
expect_img(app.activeImage, { 1, 2,
|
||||||
|
2, 2 })
|
||||||
|
|
||||||
|
-- White over gray w/opacity=51% => white
|
||||||
|
app.useTool{ tool="pencil", color=0,
|
||||||
|
points={ Point(0, 0) },
|
||||||
|
ink=Ink.ALPHA_COMPOSITING,
|
||||||
|
opacity=129 }
|
||||||
|
expect_img(app.activeImage, { 0, 2,
|
||||||
|
2, 2 })
|
||||||
|
|
||||||
|
end
|
22
tests/scripts/layer.lua
Normal file
22
tests/scripts/layer.lua
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 64)
|
||||||
|
local l = s.layers[1]
|
||||||
|
assert(l.parent == s)
|
||||||
|
assert(l.opacity == 255)
|
||||||
|
assert(l.blendMode == BlendMode.NORMAL)
|
||||||
|
|
||||||
|
l.name = "My Layer"
|
||||||
|
l.opacity = 128
|
||||||
|
l.blendMode = BlendMode.MULTIPLY
|
||||||
|
assert(l.name == "My Layer")
|
||||||
|
assert(l.opacity == 128)
|
||||||
|
assert(l.blendMode == BlendMode.MULTIPLY)
|
||||||
|
|
||||||
|
l.data = "Data"
|
||||||
|
assert(l.data == "Data")
|
||||||
|
end
|
215
tests/scripts/layers.lua
Normal file
215
tests/scripts/layers.lua
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
-- Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(#s.layers == 1)
|
||||||
|
|
||||||
|
local a = s.layers[1]
|
||||||
|
local b = s:newLayer()
|
||||||
|
local c = s:newLayer()
|
||||||
|
|
||||||
|
assert(#s.layers == 3)
|
||||||
|
assert(s.layers[1] == a)
|
||||||
|
assert(s.layers[2] == b)
|
||||||
|
assert(s.layers[3] == c)
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
for k,v in ipairs(s.layers) do
|
||||||
|
assert(i == k)
|
||||||
|
assert(v == s.layers[k])
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
|
||||||
|
s:deleteLayer(b)
|
||||||
|
assert(#s.layers == 2)
|
||||||
|
assert(s.layers[1] == a)
|
||||||
|
assert(s.layers[2] == c)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test groups
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 64)
|
||||||
|
local l = s.layers[1]
|
||||||
|
assert(#s.layers == 1)
|
||||||
|
local g = s:newGroup()
|
||||||
|
assert(#s.layers == 2)
|
||||||
|
assert(l.parent == s)
|
||||||
|
assert(g.parent == s)
|
||||||
|
assert(s.layers[1] == l)
|
||||||
|
assert(s.layers[2] == g)
|
||||||
|
|
||||||
|
l.parent = g
|
||||||
|
assert(g.parent == s)
|
||||||
|
assert(l.parent == g)
|
||||||
|
|
||||||
|
assert(#s.layers == 1)
|
||||||
|
assert(s.layers[1] == g)
|
||||||
|
assert(#s.layers[1].layers == 1)
|
||||||
|
assert(s.layers[1].layers[1] == l)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(4, 4)
|
||||||
|
-- 4 layers
|
||||||
|
local a = s.layers[1] a.name = "a"
|
||||||
|
local b = s:newLayer() b.name = "b"
|
||||||
|
local c = s:newLayer() c.name = "c"
|
||||||
|
local d = s:newLayer() d.name = "d"
|
||||||
|
-- 3 groups
|
||||||
|
local e = s:newGroup() e.name = "e"
|
||||||
|
local f = s:newGroup() f.name = "f"
|
||||||
|
local g = s:newGroup() g.name = "g"
|
||||||
|
|
||||||
|
e.parent = f
|
||||||
|
a.parent = f
|
||||||
|
b.parent = f
|
||||||
|
c.parent = g
|
||||||
|
d.parent = g
|
||||||
|
|
||||||
|
assert(#s.layers == 2)
|
||||||
|
assert(s.layers[1] == f)
|
||||||
|
assert(s.layers[2] == g)
|
||||||
|
assert(s.layers["f"] == f)
|
||||||
|
assert(s.layers["g"] == g)
|
||||||
|
assert(f.stackIndex == 1)
|
||||||
|
assert(g.stackIndex == 2)
|
||||||
|
|
||||||
|
assert(#f.layers == 3)
|
||||||
|
assert(f.layers[1] == e)
|
||||||
|
assert(f.layers[2] == a)
|
||||||
|
assert(f.layers[3] == b)
|
||||||
|
assert(f.layers["e"] == e)
|
||||||
|
assert(f.layers["a"] == a)
|
||||||
|
assert(f.layers["b"] == b)
|
||||||
|
assert(e.stackIndex == 1)
|
||||||
|
assert(a.stackIndex == 2)
|
||||||
|
assert(b.stackIndex == 3)
|
||||||
|
|
||||||
|
assert(#g.layers == 2)
|
||||||
|
assert(g.layers[1] == c)
|
||||||
|
assert(g.layers[2] == d)
|
||||||
|
assert(g.layers["c"] == c)
|
||||||
|
assert(g.layers["d"] == d)
|
||||||
|
assert(c.stackIndex == 1)
|
||||||
|
assert(d.stackIndex == 2)
|
||||||
|
|
||||||
|
d.stackIndex = 1
|
||||||
|
assert(d.stackIndex == 1)
|
||||||
|
assert(c.stackIndex == 2)
|
||||||
|
|
||||||
|
d.stackIndex = 2
|
||||||
|
assert(c.stackIndex == 1)
|
||||||
|
assert(d.stackIndex == 2)
|
||||||
|
|
||||||
|
c.stackIndex = 2
|
||||||
|
assert(d.stackIndex == 1)
|
||||||
|
assert(c.stackIndex == 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test possible bugs with stackIndex
|
||||||
|
do
|
||||||
|
local s = Sprite(4, 4)
|
||||||
|
local a = s.layers[1] a.name = "a"
|
||||||
|
local b = s:newLayer() b.name = "b"
|
||||||
|
local c = s:newLayer() c.name = "c"
|
||||||
|
local d = s:newLayer() d.name = "d"
|
||||||
|
assert(d.stackIndex == 4)
|
||||||
|
assert(s.layers[4].name == "d")
|
||||||
|
|
||||||
|
d.stackIndex = d.stackIndex+1
|
||||||
|
assert(d.stackIndex == 4)
|
||||||
|
assert(s.layers[4].name == "d")
|
||||||
|
|
||||||
|
-- Go down in the stack
|
||||||
|
d.stackIndex = d.stackIndex-1
|
||||||
|
assert(s.layers[3].name == "d")
|
||||||
|
|
||||||
|
d.stackIndex = d.stackIndex-1
|
||||||
|
assert(s.layers[2].name == "d")
|
||||||
|
|
||||||
|
-- Without change
|
||||||
|
d.stackIndex = d.stackIndex
|
||||||
|
assert(s.layers[2].name == "d")
|
||||||
|
|
||||||
|
-- Go up
|
||||||
|
d.stackIndex = d.stackIndex+1
|
||||||
|
assert(d.stackIndex == 3)
|
||||||
|
assert(s.layers[3].name == "d")
|
||||||
|
|
||||||
|
d.stackIndex = d.stackIndex+1
|
||||||
|
assert(d.stackIndex == 4)
|
||||||
|
assert(s.layers[4].name == "d")
|
||||||
|
|
||||||
|
-- Go specific stack indexes
|
||||||
|
for i=1,4 do
|
||||||
|
d.stackIndex = i
|
||||||
|
assert(d.stackIndex == i)
|
||||||
|
assert(s.layers[i].name == "d")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test crash because ActiveSiteHandler::onBeforeRemoveLayer() didn't
|
||||||
|
-- update the selected range of layers correctly (i.e. removing
|
||||||
|
-- deleted layer from the selected layers in the active range).
|
||||||
|
do
|
||||||
|
local s = Sprite(4, 4)
|
||||||
|
local a = s:newGroup() a.name = "a"
|
||||||
|
local b = s:newGroup() b.name = "b"
|
||||||
|
local c = s:newGroup() c.name = "c"
|
||||||
|
local ca = s:newGroup() ca.name = "ca"
|
||||||
|
local cb = s:newGroup() cb.name = "cb"
|
||||||
|
local d = s:newGroup() d.name = "d"
|
||||||
|
|
||||||
|
d.parent = ca
|
||||||
|
ca.parent = c
|
||||||
|
cb.parent = c
|
||||||
|
c.parent = b
|
||||||
|
b.parent = a
|
||||||
|
|
||||||
|
assert(#a.layers == 1)
|
||||||
|
assert(#c.layers == 2)
|
||||||
|
|
||||||
|
app.range.layers = { b }
|
||||||
|
app.command.RemoveLayer()
|
||||||
|
assert(#a.layers == 0)
|
||||||
|
app.undo()
|
||||||
|
assert(#a.layers == 1)
|
||||||
|
assert(#c.layers == 2)
|
||||||
|
|
||||||
|
-- Crash selecting a layer that was removed and then brought back to
|
||||||
|
-- life with "undo"
|
||||||
|
app.range.layers = { b }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test layer name bug when iterating over layers where names given to
|
||||||
|
-- some layers are integers and also are valid ranges/indexes in the
|
||||||
|
-- list of layers
|
||||||
|
do
|
||||||
|
local layerNames = { "2", "4", "Non-integer", "1" }
|
||||||
|
local s = Sprite(4, 4)
|
||||||
|
local layer1 = s.layers[1] layer1.name = layerNames[1]
|
||||||
|
local layer2 = s:newLayer() layer2.name = layerNames[2]
|
||||||
|
local layer3 = s:newLayer() layer3.name = layerNames[3]
|
||||||
|
local layer4 = s:newLayer() layer4.name = layerNames[4]
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
for index, layer in ipairs(app.activeSprite.layers) do
|
||||||
|
assert(index == i)
|
||||||
|
assert(layer.name == layerNames[i])
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Compare layers vs sprites (just return false)
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(2, 2)
|
||||||
|
assert(s.layers[1].parent == s)
|
||||||
|
assert(s.layers[1] ~= s) -- Uses Layer_eq() to compare
|
||||||
|
assert(s ~= s.layers[1]) -- Uses Sprite_eq() to compare
|
||||||
|
end
|
10
tests/scripts/math.lua
Normal file
10
tests/scripts/math.lua
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
assert(100 == math.abs(-100))
|
||||||
|
assert(100 == math.min(100, 200, 300))
|
||||||
|
assert(300 == math.max(100, 200, 300))
|
||||||
|
assert(50 == math.fmod(250, 100))
|
||||||
|
assert(3141 == math.floor(1000*math.pi))
|
27
tests/scripts/merge_down_bugs.lua
Normal file
27
tests/scripts/merge_down_bugs.lua
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local red = Color{ r=255, g=0, b=0 }
|
||||||
|
local blue = Color{ r=0, g=0, b=255 }
|
||||||
|
|
||||||
|
-- Reproduces the bug reported in https://community.aseprite.org/t/2894
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
local a = s.layers[1]
|
||||||
|
app.useTool{ color=red, layer=a, points={ Point(2, 2) }}
|
||||||
|
|
||||||
|
local b = s:newLayer()
|
||||||
|
app.useTool{ color=blue, layer=b, points={ Point(1, 1) }}
|
||||||
|
|
||||||
|
a.isContinuous = true
|
||||||
|
b.isContinuous = true
|
||||||
|
|
||||||
|
app.command.NewFrame()
|
||||||
|
app.activeLayer = b
|
||||||
|
app.command.MergeDownLayer()
|
||||||
|
|
||||||
|
assert(#s.cels == 2)
|
||||||
|
assert(s.cels[1].image:isEqual(s.cels[2].image))
|
||||||
|
end
|
14
tests/scripts/os.lua
Normal file
14
tests/scripts/os.lua
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
assert("" ~= os.getenv("PATH"))
|
||||||
|
print("PATH", os.getenv("PATH"))
|
||||||
|
|
||||||
|
local start_clock = os.clock()
|
||||||
|
print("Start ", start_clock)
|
||||||
|
|
||||||
|
local end_clock = os.clock()
|
||||||
|
print("End ", end_clock, " Elapsed ", end_clock - start_clock)
|
||||||
|
assert(start_clock < end_clock)
|
55
tests/scripts/paint_bucket.lua
Normal file
55
tests/scripts/paint_bucket.lua
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
-- Copyright (C) 2020-2021 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')
|
||||||
|
|
||||||
|
app.activeTool = 'paint_bucket'
|
||||||
|
assert(app.activeTool.id == 'paint_bucket')
|
||||||
|
assert(app.activeBrush.type == BrushType.CIRCLE)
|
||||||
|
assert(app.activeBrush.size == 1)
|
||||||
|
assert(app.activeBrush.angle == 0)
|
||||||
|
assert(app.preferences.tool('paint_bucket').floodfill.pixel_connectivity == 0)
|
||||||
|
|
||||||
|
local function test_paint_bucket(colorMode, a, b, c)
|
||||||
|
local spr = Sprite(4, 4, colorMode)
|
||||||
|
local img = app.activeImage
|
||||||
|
|
||||||
|
array_to_pixels({ a, a, a, a,
|
||||||
|
a, b, b, a,
|
||||||
|
a, a, b, a,
|
||||||
|
a, a, a, b, }, img)
|
||||||
|
|
||||||
|
app.useTool{ points={Point(0, 0)}, color=b }
|
||||||
|
expect_img(img, { b, b, b, b,
|
||||||
|
b, b, b, b,
|
||||||
|
b, b, b, b,
|
||||||
|
b, b, b, b, })
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
-- FOUR_CONNECTED=0
|
||||||
|
app.preferences.tool('paint_bucket').floodfill.pixel_connectivity = 0
|
||||||
|
assert(app.preferences.tool('paint_bucket').floodfill.pixel_connectivity == 0)
|
||||||
|
app.useTool{ points={Point(1, 1)}, color=c }
|
||||||
|
expect_img(img, { a, a, a, a,
|
||||||
|
a, c, c, a,
|
||||||
|
a, a, c, a,
|
||||||
|
a, a, a, b, })
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
-- EIGHT_CONNECTED=1
|
||||||
|
app.preferences.tool('paint_bucket').floodfill.pixel_connectivity = 1
|
||||||
|
assert(app.preferences.tool('paint_bucket').floodfill.pixel_connectivity == 1)
|
||||||
|
app.useTool{ points={Point(1, 1)}, color=c }
|
||||||
|
expect_img(img, { a, a, a, a,
|
||||||
|
a, c, c, a,
|
||||||
|
a, a, c, a,
|
||||||
|
a, a, a, c, })
|
||||||
|
end
|
||||||
|
|
||||||
|
local rgba = app.pixelColor.rgba
|
||||||
|
local gray = app.pixelColor.graya
|
||||||
|
test_paint_bucket(ColorMode.RGB, rgba(0, 0, 0), rgba(128, 128, 128), rgba(255, 255, 255))
|
||||||
|
test_paint_bucket(ColorMode.GRAYSCALE, gray(0), gray(128), gray(255))
|
||||||
|
test_paint_bucket(ColorMode.INDEXED, 1, 2, 3)
|
87
tests/scripts/palette.lua
Normal file
87
tests/scripts/palette.lua
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local p = Palette()
|
||||||
|
assert(#p == 256)
|
||||||
|
for i = 0,#p-1 do
|
||||||
|
assert(p:getColor(i) == Color(0, 0, 0))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local p = Palette(32)
|
||||||
|
assert(#p == 32)
|
||||||
|
for i = 0,#p-1 do
|
||||||
|
assert(p:getColor(i) == Color(0, 0, 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
p:resize(4)
|
||||||
|
assert(#p == 4)
|
||||||
|
p:setColor(0, Color(255, 8, 32))
|
||||||
|
p:setColor(1, Color(250, 4, 30))
|
||||||
|
p:setColor(2, Color(240, 3, 20))
|
||||||
|
p:setColor(3, Color(210, 2, 10))
|
||||||
|
assert(p:getColor(0) == Color(255, 8, 32))
|
||||||
|
assert(p:getColor(1) == Color(250, 4, 30))
|
||||||
|
assert(p:getColor(2) == Color(240, 3, 20))
|
||||||
|
assert(p:getColor(3) == Color(210, 2, 10))
|
||||||
|
|
||||||
|
-- Check alpha
|
||||||
|
local c = Color{red=100, green=50, blue=10, alpha=128}
|
||||||
|
p:setColor(3, c)
|
||||||
|
assert(p:getColor(3) == c)
|
||||||
|
assert(p:getColor(3).alpha == 128)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Load/save
|
||||||
|
do
|
||||||
|
local p = Palette{ fromFile="sprites/abcd.aseprite" }
|
||||||
|
assert(#p == 5)
|
||||||
|
assert(p:getColor(0) == Color(0, 0, 0))
|
||||||
|
assert(p:getColor(1) == Color(25, 0, 255))
|
||||||
|
assert(p:getColor(2) == Color(255, 0, 0))
|
||||||
|
assert(p:getColor(3) == Color(255, 255, 0))
|
||||||
|
assert(p:getColor(4) == Color(0, 128, 0))
|
||||||
|
|
||||||
|
p:saveAs("_test_.gpl")
|
||||||
|
|
||||||
|
local q = Palette{ fromFile="_test_.gpl" }
|
||||||
|
assert(#p == #q)
|
||||||
|
for i=0,#q-1 do
|
||||||
|
assert(p:getColor(i) == q:getColor(i))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Default palette and resources
|
||||||
|
do
|
||||||
|
local db16 = Palette{ fromResource="DB16" }
|
||||||
|
local db32 = Palette{ fromResource="DB32" }
|
||||||
|
|
||||||
|
assert(#db16 == 16)
|
||||||
|
assert(#db32 == 32)
|
||||||
|
assert(db32:getColor(0) == Color(0, 0, 0))
|
||||||
|
assert(db32:getColor(31) == Color(138, 111, 48))
|
||||||
|
|
||||||
|
assert(app.defaultPalette == db32)
|
||||||
|
|
||||||
|
app.defaultPalette = db16
|
||||||
|
assert(app.defaultPalette == db16)
|
||||||
|
|
||||||
|
-- Default sprite palette is completely black
|
||||||
|
-- TODO should we use the app.defaultPalette as the default palette?
|
||||||
|
local spr = Sprite(32, 32, ColorMode.INDEXED)
|
||||||
|
local sprPal = spr.palettes[1];
|
||||||
|
assert(#sprPal == 256)
|
||||||
|
assert(sprPal ~= db16)
|
||||||
|
assert(sprPal ~= db32)
|
||||||
|
for i=0,255 do
|
||||||
|
assert(sprPal:getColor(i) == Color(0, 0,0))
|
||||||
|
end
|
||||||
|
|
||||||
|
spr:setPalette(db32)
|
||||||
|
assert(sprPal == db32)
|
||||||
|
end
|
361
tests/scripts/pixel_perfect.lua
Normal file
361
tests/scripts/pixel_perfect.lua
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
-- Copyright (C) 2019-2021 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')
|
||||||
|
|
||||||
|
local spr = Sprite(6, 6)
|
||||||
|
local cel = spr.cels[1]
|
||||||
|
|
||||||
|
-- Point size 1px, solid color, no symmetry, no tiled mode
|
||||||
|
do
|
||||||
|
local title = '1px, solid, no symmetry, no tiled'
|
||||||
|
local red = Color{ r=255, g=0, b=0 }
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local pixel=Brush{ size=1, type=BrushType.CIRCLE }
|
||||||
|
local testData = {
|
||||||
|
{
|
||||||
|
id='1 - ' .. title .. ': right then down',
|
||||||
|
points={ Point(2, 2), Point(3, 2), Point(3, 3) },
|
||||||
|
expected={ r, 0,
|
||||||
|
0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='2 - ' .. title .. ': down then right',
|
||||||
|
points={ Point(2, 2), Point(2, 3), Point(3, 3) },
|
||||||
|
expected={ r, 0,
|
||||||
|
0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='3 - ' .. title .. ': left then up',
|
||||||
|
points={ Point(2, 2), Point(1, 2), Point(1, 1) },
|
||||||
|
expected={ r, 0,
|
||||||
|
0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='4 - ' .. title .. ': up then left',
|
||||||
|
points={ Point(2, 2), Point(2, 1), Point(1, 1) },
|
||||||
|
expected={ r, 0,
|
||||||
|
0, r }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i,v in ipairs(testData) do
|
||||||
|
app.useTool{
|
||||||
|
tool='pencil',
|
||||||
|
freehandAlgorithm=1,
|
||||||
|
brush=pixel,
|
||||||
|
color=red,
|
||||||
|
points=v.points}
|
||||||
|
expect_img_msg(cel.image, v.expected, '\nTest \'' .. v.id .. '\' failed')
|
||||||
|
cel.image:clear(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Point size 2px, translucent color, no symmetry, no tiled mode
|
||||||
|
do
|
||||||
|
local title = '2px, translucent, no symmetry, no tiled'
|
||||||
|
local red = Color{ r=255, g=0, b=0, a=127 }
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local square=Brush{ size=2, type=BrushType.SQUARE }
|
||||||
|
local testData = {
|
||||||
|
{
|
||||||
|
id='1 - ' .. title .. ': right then down',
|
||||||
|
points={ Point(2, 2), Point(3, 2), Point(3, 3) },
|
||||||
|
expected={ r, r, 0,
|
||||||
|
r, r, r,
|
||||||
|
0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='2 - ' .. title .. ': down then right',
|
||||||
|
points={ Point(2, 2), Point(2, 3), Point(3, 3) },
|
||||||
|
expected={ r, r, 0,
|
||||||
|
r, r, r,
|
||||||
|
0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='3 - ' .. title .. ': left then up',
|
||||||
|
points={ Point(2, 2), Point(1, 2), Point(1, 1) },
|
||||||
|
expected={ r, r, 0,
|
||||||
|
r, r, r,
|
||||||
|
0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='4 - ' .. title .. ': up then left',
|
||||||
|
points={ Point(2, 2), Point(2, 1), Point(1, 1) },
|
||||||
|
expected={ r, r, 0,
|
||||||
|
r, r, r,
|
||||||
|
0, r, r }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i,v in ipairs(testData) do
|
||||||
|
app.useTool{
|
||||||
|
tool='pencil',
|
||||||
|
freehandAlgorithm=1,
|
||||||
|
brush=square,
|
||||||
|
color=red,
|
||||||
|
points=v.points}
|
||||||
|
expect_img_msg(cel.image, v.expected, '\nTest \'' .. v.id .. '\' failed')
|
||||||
|
cel.image:clear(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Point size 2px, translucent color, symmetry, no tiled mode
|
||||||
|
do
|
||||||
|
local pref = app.preferences
|
||||||
|
local docPref = pref.document(spr)
|
||||||
|
pref.symmetry_mode.enabled = true
|
||||||
|
docPref.symmetry.mode = 3
|
||||||
|
docPref.symmetry.x_axis = 3
|
||||||
|
docPref.symmetry.y_axis = 3
|
||||||
|
|
||||||
|
local title = '2px, translucent, symmetry on, no tiled'
|
||||||
|
local red = Color{ r=255, g=0, b=0, a=127 }
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local square=Brush{ size=2, type=BrushType.SQUARE }
|
||||||
|
local testData = {
|
||||||
|
{
|
||||||
|
id='1 - ' .. title .. ': right then down',
|
||||||
|
points={ Point(1, 1), Point(2, 1), Point(2, 2) },
|
||||||
|
expected={ r, r, 0, 0, r, r,
|
||||||
|
r, r, r, r, r, r,
|
||||||
|
0, r, r, r, r, 0,
|
||||||
|
0, r, r, r, r, 0,
|
||||||
|
r, r, r, r, r, r,
|
||||||
|
r, r, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='2 - ' .. title .. ': down then right',
|
||||||
|
points={ Point(1, 1), Point(1, 2), Point(2, 2) },
|
||||||
|
expected={ r, r, 0, 0, r, r,
|
||||||
|
r, r, r, r, r, r,
|
||||||
|
0, r, r, r, r, 0,
|
||||||
|
0, r, r, r, r, 0,
|
||||||
|
r, r, r, r, r, r,
|
||||||
|
r, r, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='3 - ' .. title .. ': left then up',
|
||||||
|
points={ Point(2, 2), Point(1, 2), Point(1, 1) },
|
||||||
|
expected={ r, r, 0, 0, r, r,
|
||||||
|
r, r, r, r, r, r,
|
||||||
|
0, r, r, r, r, 0,
|
||||||
|
0, r, r, r, r, 0,
|
||||||
|
r, r, r, r, r, r,
|
||||||
|
r, r, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='4 - ' .. title .. ': up then left',
|
||||||
|
points={ Point(2, 2), Point(2, 1), Point(1, 1) },
|
||||||
|
expected={ r, r, 0, 0, r, r,
|
||||||
|
r, r, r, r, r, r,
|
||||||
|
0, r, r, r, r, 0,
|
||||||
|
0, r, r, r, r, 0,
|
||||||
|
r, r, r, r, r, r,
|
||||||
|
r, r, 0, 0, r, r }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i,v in ipairs(testData) do
|
||||||
|
app.useTool{
|
||||||
|
tool='pencil',
|
||||||
|
freehandAlgorithm=1,
|
||||||
|
brush=square,
|
||||||
|
color=red,
|
||||||
|
points=v.points}
|
||||||
|
expect_img_msg(cel.image, v.expected, '\nTest \'' .. v.id .. '\' failed')
|
||||||
|
cel.image:clear(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Point size 2px, translucent color, no symmetry, tiled mode on
|
||||||
|
do
|
||||||
|
local pref = app.preferences
|
||||||
|
local docPref = pref.document(spr)
|
||||||
|
pref.symmetry_mode.enabled = false
|
||||||
|
docPref.tiled.mode = 3
|
||||||
|
|
||||||
|
local title = '2px, translucent, no symmetry, tiled'
|
||||||
|
local red = Color{ r=255, g=0, b=0, a=127 }
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local square=Brush{ size=2, type=BrushType.SQUARE }
|
||||||
|
local testData = {
|
||||||
|
-- Top left corner
|
||||||
|
{
|
||||||
|
id='1 - ' .. title .. ': on top left corner, right then down',
|
||||||
|
points={ Point(0, 0), Point(1, 0), Point(1, 1) },
|
||||||
|
expected={ r, r, 0, 0, 0, r,
|
||||||
|
r, r, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
r, 0, 0, 0, 0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='2 - ' .. title .. ': on top left corner, down then right',
|
||||||
|
points={ Point(0, 0), Point(0, 1), Point(1, 1) },
|
||||||
|
expected={ r, r, 0, 0, 0, r,
|
||||||
|
r, r, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
r, 0, 0, 0, 0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='3 - ' .. title .. ': on top left corner, left then up',
|
||||||
|
points={ Point(0, 0), Point(-1, 0), Point(-1, -1) },
|
||||||
|
expected={ r, 0, 0, 0, 0, r,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, r, r,
|
||||||
|
r, 0, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='4 - ' .. title .. ': on top left corner, up then left',
|
||||||
|
points={ Point(0, 0), Point(0, -1), Point(-1, -1) },
|
||||||
|
expected={ r, 0, 0, 0, 0, r,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, r, r,
|
||||||
|
r, 0, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
-- Top right corner
|
||||||
|
{
|
||||||
|
id='5 - ' .. title .. ': on top right corner, right then down',
|
||||||
|
points={ Point(6, 0), Point(7, 0), Point(7, 1) },
|
||||||
|
expected={ r, r, 0, 0, 0, r,
|
||||||
|
r, r, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
r, 0, 0, 0, 0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='6 - ' .. title .. ': on top right corner, down then right',
|
||||||
|
points={ Point(6, 0), Point(6, 1), Point(7, 1) },
|
||||||
|
expected={ r, r, 0, 0, 0, r,
|
||||||
|
r, r, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
r, 0, 0, 0, 0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='7 - ' .. title .. ': on top right corner, left then up',
|
||||||
|
points={ Point(6, 0), Point(5, 0), Point(5, -1) },
|
||||||
|
expected={ r, 0, 0, 0, 0, r,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, r, r,
|
||||||
|
r, 0, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='8 - ' .. title .. ': on top right corner, up then left',
|
||||||
|
points={ Point(6, 0), Point(5, 0), Point(5, -1) },
|
||||||
|
expected={ r, 0, 0, 0, 0, r,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, r, r,
|
||||||
|
r, 0, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
-- Bottom left corner
|
||||||
|
{
|
||||||
|
id='9 - ' .. title .. ': on bottom left corner, right then down',
|
||||||
|
points={ Point(0, 6), Point(1, 6), Point(1, 7) },
|
||||||
|
expected={ r, r, 0, 0, 0, r,
|
||||||
|
r, r, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
r, 0, 0, 0, 0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='10 - ' .. title .. ': on bottom left corner, down then right',
|
||||||
|
points={ Point(0, 6), Point(0, 7), Point(1, 7) },
|
||||||
|
expected={ r, r, 0, 0, 0, r,
|
||||||
|
r, r, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
r, 0, 0, 0, 0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='11 - ' .. title .. ': on bottom left corner, left then up',
|
||||||
|
points={ Point(0, 6), Point(-1, 6), Point(-1, 5) },
|
||||||
|
expected={ r, 0, 0, 0, 0, r,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, r, r,
|
||||||
|
r, 0, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='12 - ' .. title .. ': on bottom left corner, up then left',
|
||||||
|
points={ Point(0, 6), Point(0, 5), Point(-1, 5) },
|
||||||
|
expected={ r, 0, 0, 0, 0, r,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, r, r,
|
||||||
|
r, 0, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
-- Botomm right corner
|
||||||
|
{
|
||||||
|
id='13 - ' .. title .. ': on bottom right corner, right then down',
|
||||||
|
points={ Point(6, 6), Point(7, 6), Point(7, 7) },
|
||||||
|
expected={ r, r, 0, 0, 0, r,
|
||||||
|
r, r, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
r, 0, 0, 0, 0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='14 - ' .. title .. ': on bottom right corner, down then right',
|
||||||
|
points={ Point(6, 6), Point(6, 7), Point(7, 7) },
|
||||||
|
expected={ r, r, 0, 0, 0, r,
|
||||||
|
r, r, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
r, 0, 0, 0, 0, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='15 - ' .. title .. ': on bottom right corner, left then up',
|
||||||
|
points={ Point(6, 6), Point(5, 6), Point(5, 5) },
|
||||||
|
expected={ r, 0, 0, 0, 0, r,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, r, r,
|
||||||
|
r, 0, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id='16 - ' .. title .. ': on bottom right corner, up then left',
|
||||||
|
points={ Point(6, 6), Point(6, 5), Point(5, 5) },
|
||||||
|
expected={ r, 0, 0, 0, 0, r,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, r, r,
|
||||||
|
r, 0, 0, 0, r, r }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i,v in ipairs(testData) do
|
||||||
|
app.useTool{
|
||||||
|
tool='pencil',
|
||||||
|
freehandAlgorithm=1,
|
||||||
|
brush=square,
|
||||||
|
color=red,
|
||||||
|
points=v.points}
|
||||||
|
expect_img_msg(cel.image, v.expected, '\nTest \'' .. v.id .. '\' failed')
|
||||||
|
cel.image:clear(0)
|
||||||
|
end
|
||||||
|
end
|
75
tests/scripts/point.lua
Normal file
75
tests/scripts/point.lua
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local pt = Point()
|
||||||
|
assert(pt.x == 0)
|
||||||
|
assert(pt.y == 0)
|
||||||
|
|
||||||
|
pt = Point(1, 2)
|
||||||
|
assert(pt.x == 1)
|
||||||
|
assert(pt.y == 2)
|
||||||
|
assert("Point{ x=1, y=2 }" == tostring(pt))
|
||||||
|
|
||||||
|
local pt2 = Point(pt)
|
||||||
|
assert(pt2.x == 1)
|
||||||
|
assert(pt2.y == 2)
|
||||||
|
|
||||||
|
pt.x = 5
|
||||||
|
pt.y = 6
|
||||||
|
assert(pt.x == 5)
|
||||||
|
assert(pt.y == 6)
|
||||||
|
|
||||||
|
pt = Point{x=10, y=20}
|
||||||
|
assert(pt.x == 10)
|
||||||
|
assert(pt.y == 20)
|
||||||
|
|
||||||
|
pt = Point{45, 25}
|
||||||
|
assert(pt.x == 45)
|
||||||
|
assert(pt.y == 25)
|
||||||
|
|
||||||
|
pt = -pt
|
||||||
|
assert(pt.x == -45)
|
||||||
|
assert(pt.y == -25)
|
||||||
|
|
||||||
|
-- add/sub/mul/div/mod/pow/idiv
|
||||||
|
|
||||||
|
pt = Point(1, 2) + 4
|
||||||
|
pt2 = 4 + Point(1, 2)
|
||||||
|
assert(pt.x == 5)
|
||||||
|
assert(pt.y == 6)
|
||||||
|
assert(pt == pt2)
|
||||||
|
|
||||||
|
pt = Point(1, 2) + Point(3, 4)
|
||||||
|
assert(pt.x == 4)
|
||||||
|
assert(pt.y == 6)
|
||||||
|
|
||||||
|
pt = Point(3, 4) - 1
|
||||||
|
assert(pt.x == 2)
|
||||||
|
assert(pt.y == 3)
|
||||||
|
|
||||||
|
pt = Point(1, 5) - Point(3, 2)
|
||||||
|
assert(pt.x == -2)
|
||||||
|
assert(pt.y == 3)
|
||||||
|
|
||||||
|
pt = Point(6, 10) * 2
|
||||||
|
assert(pt.x == 12)
|
||||||
|
assert(pt.y == 20)
|
||||||
|
|
||||||
|
pt = Point(6, 10) / 2
|
||||||
|
assert(pt.x == 3)
|
||||||
|
assert(pt.y == 5)
|
||||||
|
|
||||||
|
pt = Point(10, 5) % 2
|
||||||
|
assert(pt.x == 0)
|
||||||
|
assert(pt.y == 1)
|
||||||
|
|
||||||
|
pt = Point(2, 5) ^ 2
|
||||||
|
assert(pt.x == 4)
|
||||||
|
assert(pt.y == 25)
|
||||||
|
|
||||||
|
pt = Point(31, 10) // 3
|
||||||
|
assert(pt.x == 10)
|
||||||
|
assert(pt.y == 3)
|
10
tests/scripts/print_on_gc.lua
Normal file
10
tests/scripts/print_on_gc.lua
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
-- Create global variable which will be GC'd on lua_close()
|
||||||
|
a = { }
|
||||||
|
|
||||||
|
-- Call print() on __gc, in previous version this produced a crash at exit
|
||||||
|
setmetatable(a, { __gc=function() print('gc') end })
|
118
tests/scripts/range.lua
Normal file
118
tests/scripts/range.lua
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
-- Copyright (C) 2019-2020 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
-- Three layers
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(#s.layers == 1)
|
||||||
|
|
||||||
|
app.activeCel = s.cels[1]
|
||||||
|
|
||||||
|
local r = app.range
|
||||||
|
assert(#r.layers == 1)
|
||||||
|
assert(#r.frames == 1)
|
||||||
|
assert(#r.cels == 1)
|
||||||
|
assert(r.layers[1] == s.layers[1])
|
||||||
|
assert(r.frames[1] == s.frames[1])
|
||||||
|
assert(r.cels[1] == s.cels[1])
|
||||||
|
|
||||||
|
s:newLayer()
|
||||||
|
assert(#s.layers == 2)
|
||||||
|
|
||||||
|
local r = app.range
|
||||||
|
assert(#r.layers == 1)
|
||||||
|
assert(#r.frames == 1)
|
||||||
|
assert(#r.cels == 0)
|
||||||
|
assert(r.layers[1] == s.layers[2])
|
||||||
|
assert(r.frames[1] == s.frames[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test app.range.colors
|
||||||
|
do
|
||||||
|
assert(#app.range.colors == 0)
|
||||||
|
app.range.colors = { 2 }
|
||||||
|
assert(#app.range.colors == 1)
|
||||||
|
assert(app.range.colors[1] == 2)
|
||||||
|
app.range.colors = { 1, 4 }
|
||||||
|
assert(#app.range.colors == 2)
|
||||||
|
assert(app.range.colors[1] == 1)
|
||||||
|
assert(app.range.colors[2] == 4)
|
||||||
|
app.range.colors = { 5, 2, 10, 8, 0 }
|
||||||
|
assert(#app.range.colors == 5)
|
||||||
|
-- app.range.colors are always sorted by color index
|
||||||
|
assert(app.range.colors[1] == 0)
|
||||||
|
assert(app.range.colors[2] == 2)
|
||||||
|
assert(app.range.colors[3] == 5)
|
||||||
|
assert(app.range.colors[4] == 8)
|
||||||
|
assert(app.range.colors[5] == 10)
|
||||||
|
assert(app.range:containsColor(0))
|
||||||
|
assert(not app.range:containsColor(1))
|
||||||
|
assert(app.range:containsColor(2))
|
||||||
|
assert(app.range:containsColor(5))
|
||||||
|
assert(app.range:containsColor(8))
|
||||||
|
assert(app.range:containsColor(10))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test setters
|
||||||
|
do
|
||||||
|
local spr = Sprite(32, 32)
|
||||||
|
local lay1 = spr.layers[1]
|
||||||
|
local r = app.range
|
||||||
|
assert(r.type == RangeType.EMPTY)
|
||||||
|
assert(#r.layers == 1)
|
||||||
|
assert(#r.frames == 1)
|
||||||
|
assert(r.layers[1] == lay1)
|
||||||
|
assert(r.frames[1].frameNumber == 1)
|
||||||
|
|
||||||
|
local lay2 = spr:newLayer()
|
||||||
|
r = app.range
|
||||||
|
assert(r.type == RangeType.EMPTY)
|
||||||
|
assert(#r.layers == 1)
|
||||||
|
assert(#r.frames == 1)
|
||||||
|
assert(r.layers[1] == lay2)
|
||||||
|
assert(r.frames[1].frameNumber == 1)
|
||||||
|
|
||||||
|
r.layers = { lay1, lay2 }
|
||||||
|
assert(r.type == RangeType.LAYERS)
|
||||||
|
assert(#r.layers == 2)
|
||||||
|
assert(#r.frames == 1)
|
||||||
|
assert(r.layers[1] == lay1)
|
||||||
|
assert(r.layers[2] == lay2)
|
||||||
|
assert(r.frames[1].frameNumber == 1)
|
||||||
|
|
||||||
|
spr:newFrame()
|
||||||
|
spr:newFrame()
|
||||||
|
r.frames = { 1, 3 }
|
||||||
|
assert(r.type == RangeType.FRAMES)
|
||||||
|
assert(#r.layers == 2)
|
||||||
|
assert(#r.frames == 2)
|
||||||
|
assert(r.layers[1] == lay1)
|
||||||
|
assert(r.layers[2] == lay2)
|
||||||
|
assert(r.frames[1].frameNumber == 1)
|
||||||
|
assert(r.frames[2].frameNumber == 3)
|
||||||
|
|
||||||
|
r.layers = { lay2 }
|
||||||
|
assert(r.type == RangeType.LAYERS)
|
||||||
|
assert(#r.layers == 1)
|
||||||
|
assert(#r.frames == 2)
|
||||||
|
assert(r.layers[1] == lay2)
|
||||||
|
assert(r.frames[1].frameNumber == 1)
|
||||||
|
assert(r.frames[2].frameNumber == 3)
|
||||||
|
|
||||||
|
-- Clear range
|
||||||
|
r:clear()
|
||||||
|
assert(r.type == RangeType.EMPTY)
|
||||||
|
assert(#r.layers == 1)
|
||||||
|
assert(#r.frames == 1)
|
||||||
|
assert(r.layers[1] == app.activeLayer)
|
||||||
|
assert(r.frames[1] == app.activeFrame)
|
||||||
|
|
||||||
|
-- Check that Range:clear() reset the selected colors
|
||||||
|
r.colors = { 2 }
|
||||||
|
assert(#r.colors == 1)
|
||||||
|
assert(r.colors[1] == 2)
|
||||||
|
r:clear()
|
||||||
|
assert(#r.colors == 0)
|
||||||
|
end
|
72
tests/scripts/rectangle.lua
Normal file
72
tests/scripts/rectangle.lua
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local rc = Rectangle()
|
||||||
|
assert(rc.x == 0)
|
||||||
|
assert(rc.y == 0)
|
||||||
|
assert(rc.width == 0)
|
||||||
|
assert(rc.height == 0)
|
||||||
|
assert(rc.isEmpty)
|
||||||
|
|
||||||
|
rc = Rectangle(1, 2, 3, 4)
|
||||||
|
assert(rc.x == 1)
|
||||||
|
assert(rc.y == 2)
|
||||||
|
assert(rc.width == 3)
|
||||||
|
assert(rc.height == 4)
|
||||||
|
assert(not rc.isEmpty)
|
||||||
|
assert("Rectangle{ x=1, y=2, width=3, height=4 }" == tostring(rc))
|
||||||
|
|
||||||
|
local rc2 = Rectangle(rc)
|
||||||
|
assert(rc2.x == 1)
|
||||||
|
assert(rc2.y == 2)
|
||||||
|
assert(rc2.width == 3)
|
||||||
|
assert(rc2.height == 4)
|
||||||
|
|
||||||
|
rc.x = 5;
|
||||||
|
rc.y = 6;
|
||||||
|
rc.width = 7;
|
||||||
|
rc.height = 8;
|
||||||
|
assert(rc.x == 5)
|
||||||
|
assert(rc.y == 6)
|
||||||
|
assert(rc.width == 7)
|
||||||
|
assert(rc.height == 8)
|
||||||
|
|
||||||
|
rc = Rectangle{x=2, y=3, width=4, height=5}
|
||||||
|
assert(rc.x == 2)
|
||||||
|
assert(rc.y == 3)
|
||||||
|
assert(rc.width == 4)
|
||||||
|
assert(rc.height == 5)
|
||||||
|
|
||||||
|
rc = Rectangle{6, 7, 8, 9}
|
||||||
|
assert(rc.x == 6)
|
||||||
|
assert(rc.y == 7)
|
||||||
|
assert(rc.width == 8)
|
||||||
|
assert(rc.height == 9)
|
||||||
|
|
||||||
|
-- Rectangle:contains
|
||||||
|
|
||||||
|
local a = Rectangle{x=2, y=3, width=4, height=5}
|
||||||
|
local b = Rectangle{x=3, y=4, width=1, height=1}
|
||||||
|
assert(a:contains(b))
|
||||||
|
assert(not b:contains(a))
|
||||||
|
|
||||||
|
-- Rectangle:intersect
|
||||||
|
|
||||||
|
assert(a:intersects(b))
|
||||||
|
assert(b == a:intersect(b))
|
||||||
|
|
||||||
|
a = Rectangle{x=2, y=3, width=4, height=5}
|
||||||
|
b = Rectangle{x=3, y=4, width=4, height=5}
|
||||||
|
c = Rectangle{x=3, y=4, width=3, height=4}
|
||||||
|
assert(c == a:intersect(b))
|
||||||
|
assert(c == b:intersect(a))
|
||||||
|
assert((a & b) == c)
|
||||||
|
|
||||||
|
-- Rectangle:union
|
||||||
|
|
||||||
|
c = Rectangle{x=2, y=3, width=5, height=6}
|
||||||
|
assert(c == a:union(b))
|
||||||
|
assert(c == (a | b))
|
142
tests/scripts/save_file_command.lua
Normal file
142
tests/scripts/save_file_command.lua
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
-- Copyright (C) 2022 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
function fix_test_img(testImg, scale, fileExt, cm, c1)
|
||||||
|
-- With file formats that don't support alpha channel, we
|
||||||
|
-- compare totally transparent pixels (alpha=0) with black.
|
||||||
|
if fileExt == "tga" and cm == ColorMode.GRAYSCALE then
|
||||||
|
local pixel
|
||||||
|
if cm == ColorMode.RGB then
|
||||||
|
pixel = c1.rgbaPixel
|
||||||
|
elseif cm == ColorMode.GRAYSCALE then
|
||||||
|
pixel = c1.grayPixel
|
||||||
|
else
|
||||||
|
pixel = 0 -- Do nothing in indexed
|
||||||
|
end
|
||||||
|
for p in testImg:pixels() do
|
||||||
|
if p() == 0 then p(pixel) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
testImg:resize(testImg.width*scale, testImg.height*scale)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _,cm in ipairs{ ColorMode.RGB,
|
||||||
|
ColorMode.GRAYSCALE,
|
||||||
|
ColorMode.INDEXED } do
|
||||||
|
local spr = Sprite(32, 32, cm)
|
||||||
|
spr.palettes[1]:resize(3)
|
||||||
|
spr.palettes[1]:setColor(0, Color(0, 0, 0, 0))
|
||||||
|
spr.palettes[1]:setColor(1, Color(0, 0, 0, 255))
|
||||||
|
spr.palettes[1]:setColor(2, Color(255, 0, 0, 255))
|
||||||
|
|
||||||
|
local c1, c2
|
||||||
|
if cm == ColorMode.RGB then
|
||||||
|
c1 = Color(0, 0, 0)
|
||||||
|
c2 = Color(255, 0, 0)
|
||||||
|
elseif cm == ColorMode.GRAYSCALE then
|
||||||
|
c1 = Color{ gray=0 }
|
||||||
|
c2 = Color{ gray=255 }
|
||||||
|
elseif cm == ColorMode.INDEXED then
|
||||||
|
c1 = 1
|
||||||
|
c2 = 2
|
||||||
|
end
|
||||||
|
|
||||||
|
app.useTool{ color=c1, brush=Brush(1),
|
||||||
|
tool="filled_ellipse", points={{0,0},{31,31}} }
|
||||||
|
app.useTool{ color=c2, brush=Brush(1),
|
||||||
|
tool="filled_ellipse", points={{4,4},{27,27}} }
|
||||||
|
spr.filename = "_test_a.aseprite"
|
||||||
|
|
||||||
|
app.command.SaveFile()
|
||||||
|
assert(spr.filename == "_test_a.aseprite")
|
||||||
|
|
||||||
|
app.command.SaveFileAs{ filename="_test_b.png" }
|
||||||
|
assert(spr.filename == "_test_b.png")
|
||||||
|
|
||||||
|
app.command.SaveFileCopyAs{ filename="_test_c.png" }
|
||||||
|
assert(spr.filename == "_test_b.png")
|
||||||
|
|
||||||
|
-- Scale
|
||||||
|
for _,fn in ipairs{ "_test_c_scaled.png",
|
||||||
|
"_test_c_scaled.gif",
|
||||||
|
"_test_c_scaled.fli",
|
||||||
|
"_test_c_scaled.tga",
|
||||||
|
"_test_c_scaled.bmp" } do
|
||||||
|
local fileExt = app.fs.fileExtension(fn)
|
||||||
|
|
||||||
|
-- TODO support saving any color mode to FLI files on the fly
|
||||||
|
if (fileExt ~= "fli" or cm == ColorMode.INDEXED) and
|
||||||
|
-- TODO Review grayscale support in bmp files
|
||||||
|
(fileExt ~= "bmp" or cm ~= ColorMode.GRAYSCALE) then
|
||||||
|
for _,scale in ipairs({ 1, 2, 3, 4 }) do
|
||||||
|
print(fn, scale, cm)
|
||||||
|
|
||||||
|
app.activeSprite = spr
|
||||||
|
app.command.SaveFileCopyAs{ filename=fn, scale=scale }
|
||||||
|
local c = app.open(fn)
|
||||||
|
assert(c.width == spr.width*scale)
|
||||||
|
assert(c.height == spr.height*scale)
|
||||||
|
|
||||||
|
-- GIF file is loaded as indexed, so we have to convert from
|
||||||
|
-- indexed to the ColorMode
|
||||||
|
if c.colorMode ~= cm then
|
||||||
|
assert(fileExt == "gif" or fileExt == "bmp")
|
||||||
|
|
||||||
|
if cm == ColorMode.RGB then
|
||||||
|
app.activeSprite = c
|
||||||
|
app.command.ChangePixelFormat{ format="rgb" }
|
||||||
|
elseif cm == ColorMode.GRAYSCALE then
|
||||||
|
app.activeSprite = c
|
||||||
|
app.command.ChangePixelFormat{ format="grayscale" }
|
||||||
|
else
|
||||||
|
assert(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local testImg = Image(spr.cels[1].image)
|
||||||
|
fix_test_img(testImg, scale, fileExt, cm, c1)
|
||||||
|
if not c.cels[1].image:isEqual(testImg) then
|
||||||
|
c.cels[1].image:saveAs("_testA.png")
|
||||||
|
testImg:saveAs("_testB.png")
|
||||||
|
end
|
||||||
|
assert(c.cels[1].image.colorMode == testImg.colorMode)
|
||||||
|
assert(c.cels[1].image:isEqual(testImg))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Scale + Slices
|
||||||
|
local slice = spr:newSlice(Rectangle(1, 2, 8, 15))
|
||||||
|
slice.name = "small_slice"
|
||||||
|
for _,fn in ipairs({ "_test_c_small_slice.png",
|
||||||
|
-- TODO slices aren't supported in gif/fli yet
|
||||||
|
--"_test_c_small_slice.gif",
|
||||||
|
--"_test_c_small_slice.fli",
|
||||||
|
"_test_c_small_slice.tga",
|
||||||
|
"_test_c_small_slice.bmp" }) do
|
||||||
|
local fileExt = app.fs.fileExtension(fn)
|
||||||
|
|
||||||
|
if (fileExt ~= "bmp" or cm ~= ColorMode.GRAYSCALE) then
|
||||||
|
for _,scale in ipairs({ 1, 2, 3, 4 }) do
|
||||||
|
print(fn, scale, cm)
|
||||||
|
|
||||||
|
app.activeSprite = spr
|
||||||
|
app.command.SaveFileCopyAs{ filename=fn, slice="small_slice", scale=scale }
|
||||||
|
local c = app.open(fn)
|
||||||
|
assert(c.width == slice.bounds.width*scale)
|
||||||
|
assert(c.height == slice.bounds.height*scale)
|
||||||
|
|
||||||
|
local testImg = Image(spr.cels[1].image, spr.slices[1].bounds)
|
||||||
|
fix_test_img(testImg, scale, fileExt, cm, c1)
|
||||||
|
if not c.cels[1].image:isEqual(testImg) then
|
||||||
|
c.cels[1].image:saveAs("_testA.png")
|
||||||
|
testImg:saveAs("_testB.png")
|
||||||
|
end
|
||||||
|
assert(c.cels[1].image:isEqual(testImg))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
121
tests/scripts/selection.lua
Normal file
121
tests/scripts/selection.lua
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
-- Isolated selection
|
||||||
|
do
|
||||||
|
local a = Selection()
|
||||||
|
assert(a.bounds.x == 0)
|
||||||
|
assert(a.bounds.y == 0)
|
||||||
|
assert(a.bounds.width == 0)
|
||||||
|
assert(a.bounds.height == 0)
|
||||||
|
assert(a.isEmpty)
|
||||||
|
|
||||||
|
a:select(1, 2, 3, 4)
|
||||||
|
assert(a.bounds.x == 1)
|
||||||
|
assert(a.bounds.y == 2)
|
||||||
|
assert(a.bounds.width == 3)
|
||||||
|
assert(a.bounds.height == 4)
|
||||||
|
assert(not a.isEmpty)
|
||||||
|
assert(a:contains(1, 2))
|
||||||
|
assert(a:contains(1+3-1, 2+4-1))
|
||||||
|
assert(not a:contains(0, 1))
|
||||||
|
assert(not a:contains(1+3, 2+4))
|
||||||
|
|
||||||
|
a:select{x=5, y=6, width=7, height=8}
|
||||||
|
assert(a.bounds.x == 5)
|
||||||
|
assert(a.bounds.y == 6)
|
||||||
|
assert(a.bounds.width == 7)
|
||||||
|
assert(a.bounds.height == 8)
|
||||||
|
|
||||||
|
a:deselect()
|
||||||
|
assert(a.bounds.x == 0)
|
||||||
|
assert(a.bounds.y == 0)
|
||||||
|
assert(a.bounds.width == 0)
|
||||||
|
assert(a.bounds.height == 0)
|
||||||
|
assert(a.isEmpty)
|
||||||
|
assert(not a:contains(0, 0))
|
||||||
|
|
||||||
|
-- Constructor with rectangles
|
||||||
|
local b = Selection(1, 2, 3, 4)
|
||||||
|
assert(b.bounds == Rectangle(1, 2, 3, 4))
|
||||||
|
assert(b.origin == Point(1, 2))
|
||||||
|
|
||||||
|
-- Move
|
||||||
|
b.origin = Point(5, 6)
|
||||||
|
assert(b.bounds == Rectangle(5, 6, 3, 4))
|
||||||
|
assert(b.origin == Point(5, 6))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sprite Selection
|
||||||
|
do
|
||||||
|
local spr = Sprite(32, 32)
|
||||||
|
local sel = spr.selection
|
||||||
|
assert(sel.bounds.x == 0)
|
||||||
|
assert(sel.bounds.y == 0)
|
||||||
|
assert(sel.bounds.width == 0)
|
||||||
|
assert(sel.bounds.height == 0)
|
||||||
|
|
||||||
|
sel:selectAll()
|
||||||
|
assert(sel.bounds.x == 0)
|
||||||
|
assert(sel.bounds.y == 0)
|
||||||
|
assert(sel.bounds.width == spr.width)
|
||||||
|
assert(sel.bounds.height == spr.height)
|
||||||
|
|
||||||
|
sel:select(2, 3, 4, 5)
|
||||||
|
assert(sel.bounds.x == 2)
|
||||||
|
assert(sel.bounds.y == 3)
|
||||||
|
assert(sel.bounds.width == 4)
|
||||||
|
assert(sel.bounds.height == 5)
|
||||||
|
|
||||||
|
sel.origin = Point(5, 6)
|
||||||
|
assert(sel.bounds == Rectangle(5, 6, 4, 5))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Comparison
|
||||||
|
do
|
||||||
|
local a = Selection()
|
||||||
|
local b = Selection()
|
||||||
|
assert(a == b)
|
||||||
|
|
||||||
|
a:select(0, 0, 1, 1)
|
||||||
|
assert(a ~= b)
|
||||||
|
|
||||||
|
b:add(a)
|
||||||
|
assert(a == b)
|
||||||
|
|
||||||
|
a:subtract(b)
|
||||||
|
assert(a ~= b)
|
||||||
|
|
||||||
|
b:subtract(b)
|
||||||
|
assert(a == b)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Operations
|
||||||
|
do
|
||||||
|
local a = Selection()
|
||||||
|
a:select(2, 3, 4, 5)
|
||||||
|
assert(a.bounds == Rectangle(2, 3, 4, 5))
|
||||||
|
|
||||||
|
a:subtract(2, 3, 4, 1)
|
||||||
|
assert(a.bounds == Rectangle(2, 4, 4, 4))
|
||||||
|
|
||||||
|
assert(a:contains(3, 5))
|
||||||
|
a:subtract(3, 5, 1, 1)
|
||||||
|
assert(not a:contains(3, 5))
|
||||||
|
assert(a.bounds == Rectangle(2, 4, 4, 4))
|
||||||
|
|
||||||
|
local b = Selection()
|
||||||
|
assert(a.bounds == Rectangle(2, 4, 4, 4))
|
||||||
|
assert(b.isEmpty)
|
||||||
|
a:subtract(b) -- This should be a no-op because b is empty
|
||||||
|
assert(a.bounds == Rectangle(2, 4, 4, 4))
|
||||||
|
|
||||||
|
b:select(0, 0, 32, 32)
|
||||||
|
assert(a ~= b)
|
||||||
|
b:intersect(a)
|
||||||
|
assert(a == b)
|
||||||
|
assert(b.bounds == Rectangle(2, 4, 4, 4))
|
||||||
|
assert(b.bounds == Rectangle(2, 4, 4, 4))
|
||||||
|
end
|
28
tests/scripts/selection_tools.lua
Normal file
28
tests/scripts/selection_tools.lua
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-- Copyright (C) 2021 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')
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- Test magic wand in transparent layer
|
||||||
|
-- Note: A regression in the beta was found in this case.
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(4, 4, ColorMode.INDEXED)
|
||||||
|
app.command.LayerFromBackground()
|
||||||
|
|
||||||
|
local i = s.cels[1].image
|
||||||
|
i:clear(0)
|
||||||
|
i:putPixel(0, 0, 1)
|
||||||
|
expect_eq(4, i.width)
|
||||||
|
expect_eq(4, i.height)
|
||||||
|
|
||||||
|
app.useTool{ tool='magic_wand', points={Point(0, 0)} }
|
||||||
|
expect_eq(Rectangle(0, 0, 1, 1), s.selection.bounds)
|
||||||
|
|
||||||
|
app.useTool{ tool='magic_wand', points={Point(1, 0)} }
|
||||||
|
expect_eq(Rectangle(0, 0, 4, 4), s.selection.bounds)
|
||||||
|
assert(not s.selection:contains(0, 0))
|
||||||
|
end
|
75
tests/scripts/size.lua
Normal file
75
tests/scripts/size.lua
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
-- Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
local sz = Size()
|
||||||
|
assert(sz.width == 0)
|
||||||
|
assert(sz.height == 0)
|
||||||
|
|
||||||
|
sz = Size(3, 4)
|
||||||
|
assert(sz.width == 3)
|
||||||
|
assert(sz.height == 4)
|
||||||
|
assert("Size{ width=3, height=4 }" == tostring(sz))
|
||||||
|
|
||||||
|
local sz2 = Size(sz)
|
||||||
|
assert(sz2.width == 3)
|
||||||
|
assert(sz2.height == 4)
|
||||||
|
|
||||||
|
sz.width = 7
|
||||||
|
sz.height = 8
|
||||||
|
assert(sz.width == 7)
|
||||||
|
assert(sz.height == 8)
|
||||||
|
|
||||||
|
sz = Size{width=10, height=20}
|
||||||
|
assert(sz.width == 10)
|
||||||
|
assert(sz.height == 20)
|
||||||
|
|
||||||
|
sz = Size{45, 25}
|
||||||
|
assert(sz.width == 45)
|
||||||
|
assert(sz.height == 25)
|
||||||
|
|
||||||
|
sz = -sz
|
||||||
|
assert(sz.width == -45)
|
||||||
|
assert(sz.height == -25)
|
||||||
|
|
||||||
|
-- add/sub/mul/div/mod/pow/idiv
|
||||||
|
|
||||||
|
sz = Size(1, 2) + 4
|
||||||
|
sz2 = 4 + Size(1, 2)
|
||||||
|
assert(sz.width == 5)
|
||||||
|
assert(sz.height == 6)
|
||||||
|
assert(sz == sz2)
|
||||||
|
|
||||||
|
sz = Size(1, 2) + Size(3, 4)
|
||||||
|
assert(sz.width == 4)
|
||||||
|
assert(sz.height == 6)
|
||||||
|
|
||||||
|
sz = Size(3, 4) - 1
|
||||||
|
assert(sz.width == 2)
|
||||||
|
assert(sz.height == 3)
|
||||||
|
|
||||||
|
sz = Size(8, 5) - Size(3, 2)
|
||||||
|
assert(sz.width == 5)
|
||||||
|
assert(sz.height == 3)
|
||||||
|
|
||||||
|
sz = Size(6, 10) * 2
|
||||||
|
assert(sz.width == 12)
|
||||||
|
assert(sz.height == 20)
|
||||||
|
|
||||||
|
sz = Size(6, 10) / 2
|
||||||
|
assert(sz.width == 3)
|
||||||
|
assert(sz.height == 5)
|
||||||
|
|
||||||
|
sz = Size(10, 5) % 2
|
||||||
|
assert(sz.width == 0)
|
||||||
|
assert(sz.height == 1)
|
||||||
|
|
||||||
|
sz = Size(2, 5) ^ 2
|
||||||
|
assert(sz.width == 4)
|
||||||
|
assert(sz.height == 25)
|
||||||
|
|
||||||
|
sz = Size(31, 10) // 3
|
||||||
|
assert(sz.width == 10)
|
||||||
|
assert(sz.height == 3)
|
27
tests/scripts/slice.lua
Normal file
27
tests/scripts/slice.lua
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
|
||||||
|
local a = s:newSlice(0, 0, 32, 32)
|
||||||
|
assert(a.bounds == Rectangle(0, 0, 32, 32))
|
||||||
|
assert(a.sprite == s)
|
||||||
|
|
||||||
|
assert(a.name == "Slice")
|
||||||
|
a.name = "Slice A"
|
||||||
|
assert(a.name == "Slice A")
|
||||||
|
|
||||||
|
assert(a.center == nil)
|
||||||
|
a.center = Rectangle(2, 3, 28, 20)
|
||||||
|
assert(a.center == Rectangle(2, 3, 28, 20))
|
||||||
|
|
||||||
|
assert(a.pivot == nil)
|
||||||
|
a.pivot = Point(16, 17)
|
||||||
|
assert(a.pivot == Point(16, 17))
|
||||||
|
|
||||||
|
a.data = "Data"
|
||||||
|
assert(a.data == "Data")
|
||||||
|
end
|
40
tests/scripts/slices.lua
Normal file
40
tests/scripts/slices.lua
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
-- Copyright (C) 2022 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
|
||||||
|
local a = s:newSlice()
|
||||||
|
local b = s:newSlice(0, 2, 8, 10)
|
||||||
|
local c = s:newSlice{ x=0, y=0, width=32, height=32 }
|
||||||
|
assert(a.bounds == nil)
|
||||||
|
assert(b.bounds == Rectangle(0, 2, 8, 10))
|
||||||
|
assert(c.bounds == Rectangle(0, 0, 32, 32))
|
||||||
|
|
||||||
|
local bounds = { nil, Rectangle(0, 2, 8, 10), Rectangle(0, 0, 32, 32) }
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
for k,v in ipairs(s.slices) do
|
||||||
|
assert(i == k)
|
||||||
|
assert(v == s.slices[k])
|
||||||
|
assert(bounds[i] == s.slices[k].bounds)
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
|
||||||
|
s:deleteSlice(b)
|
||||||
|
assert(a == s.slices[1])
|
||||||
|
assert(c == s.slices[2])
|
||||||
|
|
||||||
|
assert(2 == #s.slices)
|
||||||
|
app.undo()
|
||||||
|
assert(3 == #s.slices)
|
||||||
|
app.undo()
|
||||||
|
assert(2 == #s.slices)
|
||||||
|
app.undo()
|
||||||
|
assert(1 == #s.slices)
|
||||||
|
app.undo()
|
||||||
|
assert(0 == #s.slices)
|
||||||
|
end
|
208
tests/scripts/sprite.lua
Normal file
208
tests/scripts/sprite.lua
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
-- Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local a = Sprite(32, 64)
|
||||||
|
assert(a.width == 32)
|
||||||
|
assert(a.height == 64)
|
||||||
|
assert(a.colorMode == ColorMode.RGB) -- RGB by default
|
||||||
|
assert(a.bounds == Rectangle{x=0, y=0, width=32, height=64})
|
||||||
|
|
||||||
|
-- Crop and resize
|
||||||
|
a.selection:select(2, 3, 4, 5)
|
||||||
|
a:crop()
|
||||||
|
assert(a.width == 4)
|
||||||
|
assert(a.height == 5)
|
||||||
|
assert(a.cels[1].image.width == 32)
|
||||||
|
assert(a.cels[1].image.height == 64)
|
||||||
|
a:resize(6, 8)
|
||||||
|
assert(a.width == 6)
|
||||||
|
assert(a.height == 8)
|
||||||
|
assert(a.cels[1].image.width == 32 * 6 / 4) -- Check that the image was resized (not only the canvas)
|
||||||
|
assert(a.cels[1].image.height == 64 * 8 / 5)
|
||||||
|
a:crop{x=-1, y=-1, width=20, height=30}
|
||||||
|
assert(a.width == 20)
|
||||||
|
assert(a.height == 30)
|
||||||
|
|
||||||
|
-- Resize sprite setting width/height (just changing canvas size)
|
||||||
|
a.width = 8
|
||||||
|
a.height = 10
|
||||||
|
assert(a.width == 8)
|
||||||
|
assert(a.height == 10)
|
||||||
|
|
||||||
|
-- Test other Sprite() constructors
|
||||||
|
local b = Sprite(4, 8, ColorMode.INDEXED)
|
||||||
|
assert(b.width == 4)
|
||||||
|
assert(b.height == 8)
|
||||||
|
assert(b.colorMode == ColorMode.INDEXED)
|
||||||
|
|
||||||
|
local c = Sprite{ colorMode=ColorMode.INDEXED, width=10, height=20 }
|
||||||
|
assert(c.width == 10)
|
||||||
|
assert(c.height == 20)
|
||||||
|
assert(c.colorMode == ColorMode.INDEXED)
|
||||||
|
|
||||||
|
local d = Sprite{ fromFile="sprites/abcd.aseprite" }
|
||||||
|
assert(#d.layers == 4)
|
||||||
|
assert(d.width == 32)
|
||||||
|
assert(d.height == 32)
|
||||||
|
assert(d.colorMode == ColorMode.INDEXED)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Transparent color
|
||||||
|
|
||||||
|
do
|
||||||
|
local a = Sprite(32, 32, ColorMode.INDEXED)
|
||||||
|
assert(a.transparentColor == 0)
|
||||||
|
a.transparentColor = 8
|
||||||
|
assert(a.transparentColor == 8)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Palette
|
||||||
|
|
||||||
|
do
|
||||||
|
local a = Sprite(32, 32, ColorMode.INDEXED)
|
||||||
|
assert(#a.palettes == 1)
|
||||||
|
assert(#a.palettes[1] == 256)
|
||||||
|
|
||||||
|
local p = Palette(3)
|
||||||
|
p:setColor(0, Color(255, 0, 0))
|
||||||
|
p:setColor(1, Color(0, 255, 0))
|
||||||
|
p:setColor(2, Color(0, 0, 255))
|
||||||
|
a:setPalette(p)
|
||||||
|
|
||||||
|
assert(#a.palettes == 1)
|
||||||
|
assert(#a.palettes[1] == 3)
|
||||||
|
assert(a.palettes[1]:getColor(0) == Color(255, 0, 0))
|
||||||
|
assert(a.palettes[1]:getColor(1) == Color(0, 255, 0))
|
||||||
|
assert(a.palettes[1]:getColor(2) == Color(0, 0, 255))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Duplicate & Flatten
|
||||||
|
|
||||||
|
do
|
||||||
|
local a = Sprite(32, 32)
|
||||||
|
a:newLayer()
|
||||||
|
a:newLayer()
|
||||||
|
assert(#a.layers == 3)
|
||||||
|
|
||||||
|
local b = Sprite(a) -- Clone a
|
||||||
|
a:flatten() -- Flatten a
|
||||||
|
assert(#a.layers == 1)
|
||||||
|
assert(#b.layers == 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resize non-active sprite
|
||||||
|
do
|
||||||
|
local a = Sprite(32, 32)
|
||||||
|
local b = Sprite(64, 64)
|
||||||
|
app.activeSprite = a
|
||||||
|
a:resize(10, 10)
|
||||||
|
b:resize(20, 20)
|
||||||
|
assert(a.width == 10)
|
||||||
|
assert(a.height == 10)
|
||||||
|
assert(b.width == 20)
|
||||||
|
assert(b.height == 20)
|
||||||
|
app.undo()
|
||||||
|
assert(a.width == 32)
|
||||||
|
assert(a.height == 32)
|
||||||
|
app.activeSprite = b
|
||||||
|
app.undo()
|
||||||
|
assert(b.width == 64)
|
||||||
|
assert(b.height == 64)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Grid bounds
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(s.gridBounds == Rectangle{0, 0, 16, 16})
|
||||||
|
s.gridBounds = Rectangle{2, 3, 8, 4}
|
||||||
|
assert(s.gridBounds == Rectangle{2, 3, 8, 4})
|
||||||
|
s:saveAs("_test_sprite_gridbounds.aseprite")
|
||||||
|
|
||||||
|
local s2 = Sprite{ fromFile="_test_sprite_gridbounds.aseprite" }
|
||||||
|
assert(s2.gridBounds == Rectangle{2, 3, 8, 4})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pixel ratio
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
assert(s.pixelRatio == Size{1, 1})
|
||||||
|
s.pixelRatio = Size{3, 2}
|
||||||
|
assert(s.pixelRatio == Size{3, 2})
|
||||||
|
s:saveAs("_test_sprite_pixelratio.aseprite")
|
||||||
|
|
||||||
|
local s2 = Sprite{ fromFile="_test_sprite_pixelratio.aseprite" }
|
||||||
|
assert(s2.pixelRatio == Size{3, 2})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sprite{ fromFile, oneFrame }
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
s:newFrame()
|
||||||
|
s:saveAs("_test1.png")
|
||||||
|
assert(#s.frames == 2)
|
||||||
|
|
||||||
|
s = Sprite{ fromFile="_test1.png" }
|
||||||
|
assert(#s.frames == 2)
|
||||||
|
|
||||||
|
s = Sprite{ fromFile="_test1.png", oneFrame=true }
|
||||||
|
assert(#s.frames == 1)
|
||||||
|
|
||||||
|
s = Sprite{ fromFile="_test1.png", oneFrame=false }
|
||||||
|
assert(#s.frames == 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Issues with sprites having pixel with indexes out of palette bounds:
|
||||||
|
-- Saving png failed (https://github.com/aseprite/aseprite/issues/2842)
|
||||||
|
do
|
||||||
|
local s = Sprite(2, 2, ColorMode.INDEXED)
|
||||||
|
assert(#s.palettes == 1)
|
||||||
|
|
||||||
|
s.transparentColor = 1
|
||||||
|
s.palettes[1]:resize(8)
|
||||||
|
assert(#s.palettes[1] == 8)
|
||||||
|
s.cels[1].image:clear(2)
|
||||||
|
s.cels[1].image:putPixel(0, 0, 7)
|
||||||
|
s:saveAs("_test1_.png") -- OK
|
||||||
|
|
||||||
|
s.palettes[1]:resize(4)
|
||||||
|
assert(#s.palettes[1] == 4)
|
||||||
|
local result = s:saveAs("_test2_palerr_.png") -- Used to fail
|
||||||
|
|
||||||
|
-- If result=false we got a "libpng: Wrote palette index exceeding num_palette"
|
||||||
|
assert(result)
|
||||||
|
|
||||||
|
local s2 = app.open("_test2_palerr_.png")
|
||||||
|
assert(s2 ~= nil)
|
||||||
|
print(s2.cels[1].image:getPixel(0, 0))
|
||||||
|
assert(s2.cels[1].image:getPixel(0, 0) == 1)
|
||||||
|
end
|
||||||
|
-- Flatten visible layers uses indices outside the palette range as opaque colors instead of transparent color (https://github.com/aseprite/aseprite/issues/2912)
|
||||||
|
do
|
||||||
|
local s = Sprite(2, 2, ColorMode.INDEXED)
|
||||||
|
|
||||||
|
s.transparentColor = 0
|
||||||
|
s.palettes[1]:resize(4)
|
||||||
|
|
||||||
|
s.cels[1].image:clear(1)
|
||||||
|
local l = s:newLayer()
|
||||||
|
s:newCel(l)
|
||||||
|
s.cels[2].image:putPixel(0, 0, 2)
|
||||||
|
s.cels[2].image:putPixel(1, 0, 7)
|
||||||
|
s:flatten()
|
||||||
|
|
||||||
|
assert(s.cels[1].image:getPixel(0, 0) == 2)
|
||||||
|
assert(s.cels[1].image:getPixel(1, 0) == 1) -- Get the color of the first layer
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Compare sprite IDs
|
||||||
|
|
||||||
|
do
|
||||||
|
local a = Sprite(1, 1)
|
||||||
|
local b = Sprite(1, 1)
|
||||||
|
assert(a == a)
|
||||||
|
assert(a ~= b) -- Compares IDs, not sprite size
|
||||||
|
end
|
23
tests/scripts/string.lua
Normal file
23
tests/scripts/string.lua
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
assert(72 == string.byte("Hello", 1))
|
||||||
|
assert(101 == string.byte("Hello", 2))
|
||||||
|
assert(111 == string.byte("Hello", 5))
|
||||||
|
assert("Hello" == string.char(72, 101, 108, 108, 111))
|
||||||
|
|
||||||
|
local s = "Hello"
|
||||||
|
assert(111 == s:byte(5))
|
||||||
|
assert(5 == string.len(s))
|
||||||
|
assert("olleH" == string.reverse(s))
|
||||||
|
assert("hello" == string.lower(s))
|
||||||
|
assert("HELLO" == string.upper(s))
|
||||||
|
|
||||||
|
assert("Simple int 32" == string.format("Simple int %d", 32))
|
||||||
|
assert("Simple int 0032" == string.format("Simple int %04d", 32))
|
||||||
|
|
||||||
|
assert(7 == string.find("Hello World!", "W"))
|
||||||
|
|
||||||
|
assert("-- hi 1000 --" == string.format("-- %s %d --", "hi", 1000))
|
45
tests/scripts/tag.lua
Normal file
45
tests/scripts/tag.lua
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
-- Copyright (C) 2020 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
for i = 1,7 do s:newFrame() end
|
||||||
|
assert(#s.frames == 8)
|
||||||
|
|
||||||
|
a = s:newTag(1, 8)
|
||||||
|
assert(a.sprite == s)
|
||||||
|
assert(a.fromFrame.frameNumber == 1)
|
||||||
|
assert(a.toFrame.frameNumber == 8)
|
||||||
|
assert(a.frames == 8)
|
||||||
|
|
||||||
|
a.fromFrame = 2
|
||||||
|
a.toFrame = 5
|
||||||
|
assert(a.fromFrame.frameNumber == 2)
|
||||||
|
assert(a.toFrame.frameNumber == 5)
|
||||||
|
|
||||||
|
assert(a.name == "Tag")
|
||||||
|
a.name = "Tag A"
|
||||||
|
assert(a.name == "Tag A")
|
||||||
|
|
||||||
|
assert(a.aniDir == AniDir.FORWARD) -- Default AniDir is FORWARD
|
||||||
|
a.aniDir = AniDir.REVERSE
|
||||||
|
assert(a.aniDir == AniDir.REVERSE)
|
||||||
|
a.aniDir = AniDir.PING_PONG
|
||||||
|
assert(a.aniDir == AniDir.PING_PONG)
|
||||||
|
a.aniDir = AniDir.FORWARD
|
||||||
|
assert(a.aniDir == AniDir.FORWARD)
|
||||||
|
|
||||||
|
assert(a.color == Color(0, 0, 0))
|
||||||
|
a.color = Color(255, 0, 0)
|
||||||
|
assert(a.color == Color(255, 0, 0))
|
||||||
|
|
||||||
|
assert(a.repeats == 0)
|
||||||
|
a.repeats = 1
|
||||||
|
assert(a.repeats == 1)
|
||||||
|
|
||||||
|
a.data = "Data"
|
||||||
|
assert(a.data == "Data")
|
||||||
|
end
|
36
tests/scripts/tags.lua
Normal file
36
tests/scripts/tags.lua
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(32, 32)
|
||||||
|
for i = 1,7 do s:newFrame() end
|
||||||
|
assert(#s.frames == 8)
|
||||||
|
|
||||||
|
a = s:newTag(1, 2)
|
||||||
|
b = s:newTag(3, 4)
|
||||||
|
c = s:newTag(5, 8)
|
||||||
|
|
||||||
|
assert(a.frames == 2)
|
||||||
|
assert(b.frames == 2)
|
||||||
|
assert(c.frames == 4)
|
||||||
|
|
||||||
|
assert(a == s.tags[1])
|
||||||
|
assert(b == s.tags[2])
|
||||||
|
assert(c == s.tags[3])
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
for k,v in ipairs(s.tags) do
|
||||||
|
assert(i == k)
|
||||||
|
assert(v == s.tags[k])
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
|
||||||
|
s:deleteTag(b)
|
||||||
|
assert(a == s.tags[1])
|
||||||
|
assert(c == s.tags[2])
|
||||||
|
|
||||||
|
assert(c.fromFrame.frameNumber == 5)
|
||||||
|
assert(c.toFrame.frameNumber == 8)
|
||||||
|
end
|
134
tests/scripts/test_utils.lua
Normal file
134
tests/scripts/test_utils.lua
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
-- Copyright (C) 2019-2020 Igara Studio S.A.
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
function expect_eq(a, b)
|
||||||
|
if a ~= b then
|
||||||
|
print(debug.traceback())
|
||||||
|
print('Expected A == B but:')
|
||||||
|
print(' - Value A = ' .. tostring(a))
|
||||||
|
print(' - Value B = ' .. tostring(b))
|
||||||
|
assert(a == b)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function dump_img(image)
|
||||||
|
local w = image.width
|
||||||
|
local h = image.height
|
||||||
|
print('Image(' .. tostring(w) .. 'x' .. tostring(h) .. ') = {')
|
||||||
|
for v=0,h-1 do
|
||||||
|
local lineStr = ' '
|
||||||
|
for u=0,w-1 do
|
||||||
|
lineStr = lineStr .. image:getPixel(u, v) .. ','
|
||||||
|
end
|
||||||
|
print(lineStr)
|
||||||
|
end
|
||||||
|
print('}')
|
||||||
|
end
|
||||||
|
|
||||||
|
function expect_img(image, expectedPixels)
|
||||||
|
local w = image.width
|
||||||
|
local h = image.height
|
||||||
|
if w*h ~= #expectedPixels then
|
||||||
|
print(debug.traceback())
|
||||||
|
print('Expected pixels: #=' .. #expectedPixels)
|
||||||
|
print('Image size: w=' .. w .. ' h=' .. h .. ' #=' .. w*h)
|
||||||
|
dump_img(image)
|
||||||
|
assert(w*h == #expectedPixels)
|
||||||
|
end
|
||||||
|
for y=0,h-1 do
|
||||||
|
for x=0,w-1 do
|
||||||
|
local value = image:getPixel(x, y)
|
||||||
|
local expected = expectedPixels[1+y*w+x]
|
||||||
|
if value ~= expected then
|
||||||
|
dump_img(image)
|
||||||
|
print('In pixel (' .. x .. ', ' .. y .. '):')
|
||||||
|
|
||||||
|
local a = value
|
||||||
|
local b = expected
|
||||||
|
print(debug.traceback())
|
||||||
|
print('Expected A == B but:')
|
||||||
|
if image.colorMode == ColorMode.RGB then
|
||||||
|
print(string.format(' - Value A = rgba(%d,%d,%d,%d)',
|
||||||
|
app.pixelColor.rgbaR(a),
|
||||||
|
app.pixelColor.rgbaG(a),
|
||||||
|
app.pixelColor.rgbaB(a),
|
||||||
|
app.pixelColor.rgbaA(a)))
|
||||||
|
print(string.format(' - Value B = rgba(%d,%d,%d,%d)',
|
||||||
|
app.pixelColor.rgbaR(b),
|
||||||
|
app.pixelColor.rgbaG(b),
|
||||||
|
app.pixelColor.rgbaB(b),
|
||||||
|
app.pixelColor.rgbaA(b)))
|
||||||
|
elseif image.colorMode == ColorMode.GRAY then
|
||||||
|
print(string.format(' - Value A = gray(%d,%d)',
|
||||||
|
app.pixelColor.grayaV(a),
|
||||||
|
app.pixelColor.grayaA(a)))
|
||||||
|
print(string.format(' - Value B = gray(%d,%d)',
|
||||||
|
app.pixelColor.grayaV(b),
|
||||||
|
app.pixelColor.grayaA(b)))
|
||||||
|
else
|
||||||
|
print(' - Value A = ' .. tostring(a))
|
||||||
|
print(' - Value B = ' .. tostring(b))
|
||||||
|
end
|
||||||
|
assert(a == b)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function expect_img_msg(image, expectedPixels, msg)
|
||||||
|
local status, err = pcall(expect_img, image, expectedPixels)
|
||||||
|
if not status then
|
||||||
|
print(msg)
|
||||||
|
error(err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function array_to_pixels(array, image)
|
||||||
|
local w = image.width
|
||||||
|
local h = image.height
|
||||||
|
assert(w*h == #array)
|
||||||
|
local i = 1
|
||||||
|
for y=0,h-1 do
|
||||||
|
for x=0,w-1 do
|
||||||
|
image:drawPixel(x, y, array[i])
|
||||||
|
i = i+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns true if the given array (layers) of layers
|
||||||
|
function expect_rendered_layers(expectedImage, sprite, layerNames, frame)
|
||||||
|
function contains_layer(name)
|
||||||
|
for _,n in ipairs(layerNames) do
|
||||||
|
if name == n then return true end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if frame == nil then frame = 1 end
|
||||||
|
local render = Image(sprite.spec)
|
||||||
|
function render_layers(prefix, layers)
|
||||||
|
for _,layer in ipairs(layers) do
|
||||||
|
if layer.isGroup then
|
||||||
|
render_layers(layer.name.."/", layer.layers)
|
||||||
|
end
|
||||||
|
if contains_layer(prefix..layer.name) then
|
||||||
|
local cel = layer:cel(frame)
|
||||||
|
if cel then
|
||||||
|
render:drawImage(cel.image, cel.position)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
render_layers("", sprite.layers)
|
||||||
|
if not expectedImage:isEqual(render) then
|
||||||
|
print("Rendering:")
|
||||||
|
for _,n in ipairs(layerNames) do
|
||||||
|
print(" - " .. n)
|
||||||
|
end
|
||||||
|
error("render doesn't match to the expected image")
|
||||||
|
end
|
||||||
|
end
|
1119
tests/scripts/tilemap.lua
Normal file
1119
tests/scripts/tilemap.lua
Normal file
File diff suppressed because it is too large
Load Diff
684
tests/scripts/tools.lua
Normal file
684
tests/scripts/tools.lua
Normal file
@ -0,0 +1,684 @@
|
|||||||
|
-- Copyright (C) 2019-2020 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')
|
||||||
|
|
||||||
|
local rgba = app.pixelColor.rgba
|
||||||
|
local gray = app.pixelColor.graya
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- activeTool
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local pencil = app.activeTool -- pencil is the default tool
|
||||||
|
assert(pencil ~= nil)
|
||||||
|
assert(pencil.id == 'pencil')
|
||||||
|
app.activeTool = 'line'
|
||||||
|
assert(app.activeTool.id == 'line')
|
||||||
|
app.activeTool = pencil
|
||||||
|
assert(app.activeTool.id == 'pencil')
|
||||||
|
|
||||||
|
-- default brush is a circle of 1x1 when there is no UI
|
||||||
|
assert(app.activeBrush.type == BrushType.CIRCLE)
|
||||||
|
assert(app.activeBrush.size == 1)
|
||||||
|
assert(app.activeBrush.angle == 0)
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- create sprite for testing
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local spr = Sprite(4, 4)
|
||||||
|
local cel = spr.cels[1]
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- pencil and eraser
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
app.useTool{
|
||||||
|
tool='pencil',
|
||||||
|
color=Color{ r=0, g=0, b=0 },
|
||||||
|
points={ Point(2, 2),
|
||||||
|
Point(3, 2) }}
|
||||||
|
expect_eq(cel.bounds, Rectangle(2, 2, 2, 1))
|
||||||
|
|
||||||
|
app.useTool{
|
||||||
|
tool='eraser',
|
||||||
|
points={ Point(2, 2) }}
|
||||||
|
expect_eq(cel.bounds, Rectangle(3, 2, 1, 1))
|
||||||
|
|
||||||
|
app.useTool{
|
||||||
|
tool='eraser',
|
||||||
|
points={ Point(3, 2) }}
|
||||||
|
-- This must fail because cel is pointing to an invalid cel now.
|
||||||
|
-- TODO: In a future this could change if this issue:
|
||||||
|
-- https://github.com/aseprite/aseprite/issues/1833
|
||||||
|
-- is implemented.
|
||||||
|
assert(not pcall(function() print(cel.bounds) end))
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- line
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local red = Color{ r=255, g=0, b=0 }
|
||||||
|
app.useTool{
|
||||||
|
tool='line',
|
||||||
|
color=red,
|
||||||
|
points={ Point(0, 0), Point(3, 3) }}
|
||||||
|
local cel = spr.cels[1]
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
do
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local expected = { r, 0, 0, 0,
|
||||||
|
0, r, 0, 0,
|
||||||
|
0, 0, r, 0,
|
||||||
|
0, 0, 0, r }
|
||||||
|
assert(cel.image.width == 4)
|
||||||
|
assert(cel.image.height == 4)
|
||||||
|
for v=0,3 do
|
||||||
|
for u=0,3 do
|
||||||
|
assert(cel.image:getPixel(u, v) == expected[1+v*4+u])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- paint_bucket
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
app.useTool{
|
||||||
|
tool='paint_bucket',
|
||||||
|
color=red,
|
||||||
|
points={ Point(3, 0) }}
|
||||||
|
local cel = spr.cels[1]
|
||||||
|
do
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local expected = { r, r, r, r,
|
||||||
|
0, r, r, r,
|
||||||
|
0, 0, r, r,
|
||||||
|
0, 0, 0, r }
|
||||||
|
assert(cel.image.width == 4)
|
||||||
|
assert(cel.image.height == 4)
|
||||||
|
for v=0,3 do
|
||||||
|
for u=0,3 do
|
||||||
|
assert(cel.image:getPixel(u, v) == expected[1+v*4+u])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- rectangle
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local blue = Color{ r=0, g=0, b=255 }
|
||||||
|
app.useTool{
|
||||||
|
tool='rectangle',
|
||||||
|
color=blue,
|
||||||
|
points={ Point(0, 0), Point(3, 3) }}
|
||||||
|
local cel = spr.cels[1]
|
||||||
|
do
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local b = blue.rgbaPixel
|
||||||
|
local expected = { b, b, b, b,
|
||||||
|
b, r, r, b,
|
||||||
|
b, 0, r, b,
|
||||||
|
b, b, b, b }
|
||||||
|
assert(cel.image.width == 4)
|
||||||
|
assert(cel.image.height == 4)
|
||||||
|
for v=0,3 do
|
||||||
|
for u=0,3 do
|
||||||
|
assert(cel.image:getPixel(u, v) == expected[1+v*4+u])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- ellipse
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
local yellow = Color{ r=255, g=255, b=0 }
|
||||||
|
app.useTool{
|
||||||
|
tool='ellipse',
|
||||||
|
color=yellow,
|
||||||
|
points={ Point(0, 0), Point(3, 3) }}
|
||||||
|
local cel = spr.cels[1]
|
||||||
|
do
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local b = blue.rgbaPixel
|
||||||
|
local y = yellow.rgbaPixel
|
||||||
|
local expected = { b, y, y, b,
|
||||||
|
y, r, r, y,
|
||||||
|
y, 0, r, y,
|
||||||
|
b, y, y, b }
|
||||||
|
assert(cel.image.width == 4)
|
||||||
|
assert(cel.image.height == 4)
|
||||||
|
for v=0,3 do
|
||||||
|
for u=0,3 do
|
||||||
|
assert(cel.image:getPixel(u, v) == expected[1+v*4+u])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- draw in several cels
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
do
|
||||||
|
local spr2 = Sprite(4, 4)
|
||||||
|
spr2:newFrame()
|
||||||
|
|
||||||
|
local bgLay = spr2.layers[1]
|
||||||
|
local fgLay = spr2:newLayer()
|
||||||
|
local bgCel1 = spr2:newCel(fgLay, 1, Image(spr2.spec))
|
||||||
|
local fgCel1 = spr2:newCel(bgLay, 1, Image(spr2.spec))
|
||||||
|
local bgCel2 = spr2:newCel(fgLay, 2, Image(spr2.spec))
|
||||||
|
local fgCel2 = spr2:newCel(bgLay, 2, Image(spr2.spec))
|
||||||
|
expect_eq(fgCel1.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_eq(bgCel1.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_eq(fgCel2.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_eq(bgCel2.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
|
||||||
|
-- After each useTool(), the cels will be shrunken to the minimum
|
||||||
|
-- required size.
|
||||||
|
app.activeTool = 'pencil'
|
||||||
|
app.useTool{ color=red, cel=bgCel1, points={ Point(0, 0) }}
|
||||||
|
app.useTool{ color=red, layer=bgCel2.layer, frame=bgCel2.frame, points={ Point(1, 0) }}
|
||||||
|
|
||||||
|
-- After using the tool in bgCel2, the activeFrame is the frame
|
||||||
|
-- number 2.
|
||||||
|
assert(bgCel2.frame == app.activeFrame)
|
||||||
|
assert(bgCel2.frame == fgCel2.frame)
|
||||||
|
|
||||||
|
app.activeFrame = fgCel1.frame
|
||||||
|
app.useTool{ color=yellow, layer=fgCel1.layer, points={ Point(1, 1) }}
|
||||||
|
app.useTool{ color=yellow, cel=fgCel2, points={ Point(2, 1) }}
|
||||||
|
|
||||||
|
expect_eq(bgCel1.bounds, Rectangle(0, 0, 1, 1))
|
||||||
|
expect_eq(bgCel2.bounds, Rectangle(1, 0, 1, 1))
|
||||||
|
expect_eq(fgCel1.bounds, Rectangle(1, 1, 1, 1))
|
||||||
|
expect_eq(fgCel2.bounds, Rectangle(2, 1, 1, 1))
|
||||||
|
|
||||||
|
assert(bgCel1.image:getPixel(0, 0) == red.rgbaPixel)
|
||||||
|
assert(bgCel2.image:getPixel(0, 0) == red.rgbaPixel)
|
||||||
|
assert(fgCel1.image:getPixel(0, 0) == yellow.rgbaPixel)
|
||||||
|
assert(fgCel2.image:getPixel(0, 0) == yellow.rgbaPixel)
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- draw with brushes
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
function drawing_with_simple_brushes(colorMode, a, b, c)
|
||||||
|
print("drawing_with_simple_brushes", colorMode)
|
||||||
|
|
||||||
|
local expectedImages = {
|
||||||
|
{ 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0 },
|
||||||
|
{ 0, 0, 0, 0,
|
||||||
|
0, a, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0 },
|
||||||
|
{ 0, 0, 0, 0,
|
||||||
|
0, b, b, 0,
|
||||||
|
0, b, b, 0,
|
||||||
|
0, 0, 0, 0 },
|
||||||
|
{ c, c, c, 0,
|
||||||
|
c, c, c, c,
|
||||||
|
c, c, c, c,
|
||||||
|
0, c, c, c }
|
||||||
|
}
|
||||||
|
|
||||||
|
local s = Sprite(4, 4, colorMode)
|
||||||
|
assert(s == app.activeSprite)
|
||||||
|
assert(s.cels[1] == app.activeCel)
|
||||||
|
|
||||||
|
function expect_cel_is_image(imageIndex)
|
||||||
|
local a = Image(s.spec)
|
||||||
|
a:drawSprite(s, 1, Point(0, 0))
|
||||||
|
local b = expectedImages[imageIndex]
|
||||||
|
expect_img(a, b)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect_cel_is_image(1)
|
||||||
|
app.useTool{ tool='pencil', color=a, points={ Point(1, 1) } }
|
||||||
|
assert(#s.cels == 1)
|
||||||
|
expect_cel_is_image(2)
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
expect_cel_is_image(1)
|
||||||
|
app.useTool{ tool='pencil',
|
||||||
|
brush=Brush{ size=2, type=BrushType.SQUARE },
|
||||||
|
color=b, points={ Point(2, 2) } }
|
||||||
|
expect_cel_is_image(3)
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
expect_cel_is_image(1)
|
||||||
|
app.useTool{ tool='pencil',
|
||||||
|
brush=Brush{ size=2, type=BrushType.SQUARE, center=Point(0, 0) },
|
||||||
|
color=b, points={ Point(1, 1) } }
|
||||||
|
expect_cel_is_image(3)
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
expect_cel_is_image(1)
|
||||||
|
app.useTool{ tool='line',
|
||||||
|
brush={ size=3, type=BrushType.SQUARE },
|
||||||
|
color=c, points={ Point(1, 1), Point(2, 2) } }
|
||||||
|
expect_cel_is_image(4)
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
drawing_with_simple_brushes(ColorMode.RGB, red.rgbaPixel, blue.rgbaPixel, yellow.rgbaPixel)
|
||||||
|
drawing_with_simple_brushes(ColorMode.GRAY, gray(255), gray(128), gray(32))
|
||||||
|
drawing_with_simple_brushes(ColorMode.INDEXED, 1, 2, 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- draw with special image brushes + patterns
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
function drawing_with_image_brushes(imageColorMode, colorInImage,
|
||||||
|
brushColorMode, colorInBrush, palette)
|
||||||
|
print("drawing_with_image_brushes", imageColorMode, brushColorMode)
|
||||||
|
local s = Sprite(4, 4, imageColorMode)
|
||||||
|
local c = colorInImage
|
||||||
|
cel = s.cels[1]
|
||||||
|
|
||||||
|
if palette then
|
||||||
|
s:setPalette(palette)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Brush image with BrushPattern.ORIGIN
|
||||||
|
local bi = Image(2, 2, brushColorMode)
|
||||||
|
bi:clear(0)
|
||||||
|
bi:putPixel(0, 0, colorInBrush)
|
||||||
|
bi:putPixel(1, 1, colorInBrush)
|
||||||
|
local b = Brush { image=bi,
|
||||||
|
center=Point(0, 0),
|
||||||
|
pattern=BrushPattern.ORIGIN,
|
||||||
|
patternOrigin=Point(0, 0) }
|
||||||
|
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0 })
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(0, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 2, 2))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ c, 0,
|
||||||
|
0, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(0, 0), Point(1, 1) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 3, 3))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ c, 0, 0,
|
||||||
|
0, c, 0,
|
||||||
|
0, 0, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(0, 1) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 1, 2, 2))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 0, c,
|
||||||
|
c, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(0, 0), Point(2, 0),
|
||||||
|
Point(0, 0), Point(0, 1) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 3))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ c, 0, c, 0,
|
||||||
|
0, c, 0, c,
|
||||||
|
c, 0, 0, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.useTool{ tool='paint_bucket', brush=b, points={ Point(0, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 4, 4))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ c, 0, c, 0,
|
||||||
|
0, c, 0, c,
|
||||||
|
c, 0, c, 0,
|
||||||
|
0, c, 0, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(1, 0) } }
|
||||||
|
assert(app.activeImage ~= nil)
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 0, 2, 2))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 0, c,
|
||||||
|
c, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(1, 0),
|
||||||
|
Point(1, 0)} }
|
||||||
|
assert(app.activeImage ~= nil)
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 0, 2, 2))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 0, c,
|
||||||
|
c, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Change brush pattern to BrushPattern.TARGET
|
||||||
|
|
||||||
|
b = Brush { image=bi,
|
||||||
|
center=Point(0, 0),
|
||||||
|
pattern=BrushPattern.TARGET,
|
||||||
|
patternOrigin=Point(0, 0) }
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(1, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 0, 2, 2))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ c, 0,
|
||||||
|
0, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
drawing_with_image_brushes(ColorMode.RGB, rgba(255, 0, 0),
|
||||||
|
ColorMode.RGB, rgba(255, 0, 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- draw with symmetry
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
function drawing_with_symmetry(imageColorMode, colorInImage,
|
||||||
|
brushColorMode, colorInBrush, palette)
|
||||||
|
print("drawing_with_symmetry", imageColorMode, brushColorMode)
|
||||||
|
local s = Sprite(8, 3, imageColorMode)
|
||||||
|
local c = colorInImage
|
||||||
|
cel = s.cels[1]
|
||||||
|
|
||||||
|
if palette then
|
||||||
|
s:setPalette(palette)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Enable symmetry
|
||||||
|
local pref = app.preferences
|
||||||
|
local docPref = pref.document(s)
|
||||||
|
pref.symmetry_mode.enabled = true
|
||||||
|
docPref.symmetry.mode = 1 -- TODO use SymmetryMode.HORIZONTAL when it's available
|
||||||
|
docPref.symmetry.x_axis = 4
|
||||||
|
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 8, 3))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0 })
|
||||||
|
|
||||||
|
local b = Brush { size=1 }
|
||||||
|
app.fgColor = c
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(0, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 8, 1))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c, 0, 0, 0, 0, 0, 0, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(2, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(2, 0, 4, 1))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c, 0, 0, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Brush size 2x2 center=(1,1)
|
||||||
|
b = Brush { size=2 }
|
||||||
|
assert(b.center.x == 1)
|
||||||
|
assert(b.center.y == 1)
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(1, 1) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 8, 2))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c, c, 0, 0, 0, 0, c, c,
|
||||||
|
c, c, 0, 0, 0, 0, c, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Brush size 2x2 center=(0,0)
|
||||||
|
b = Brush { size=2, center=Point(0, 0) }
|
||||||
|
assert(b.center.x == 0)
|
||||||
|
assert(b.center.y == 0)
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(1, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 0, 6, 2))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c, c, 0, 0, c, c,
|
||||||
|
c, c, 0, 0, c, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Brush size 3x3
|
||||||
|
b = Brush { size=3 }
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(1, 1) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 8, 3))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 0, c, 0, 0, 0, 0, c, 0,
|
||||||
|
c, c, c, 0, 0, c, c, c,
|
||||||
|
0, c, 0, 0, 0, 0, c, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Brush size 3x3
|
||||||
|
b = Brush { size=3, center=Point(1, 1) }
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(2, 1) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 0, 6, 3))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 0, c, 0, 0, c, 0,
|
||||||
|
c, c, c, c, c, c,
|
||||||
|
0, c, 0, 0, c, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Brush size 4x4 center=(2,2)
|
||||||
|
b = Brush { size=4 }
|
||||||
|
assert(b.center.x == 2)
|
||||||
|
assert(b.center.y == 2)
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(1, 1) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 8, 3))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c, c, c, 0, 0, c, c, c,
|
||||||
|
c, c, c, 0, 0, c, c, c,
|
||||||
|
c, c, 0, 0, 0, 0, c, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Brush size 4x4 center=(1,1)
|
||||||
|
b = Brush { size=4, center=Point(1, 1) }
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(1, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(0, 0, 8, 3))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c, c, c, c, c, c, c, c,
|
||||||
|
c, c, c, c, c, c, c, c,
|
||||||
|
0, c, c, 0, 0, c, c, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Odd symmetry
|
||||||
|
docPref.symmetry.x_axis = 4.5
|
||||||
|
|
||||||
|
b = Brush { size=1 }
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(4, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(4, 0, 1, 1))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
b = Brush { size=1 }
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(3, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(3, 0, 3, 1))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c, 0, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
b = Brush { size=2 }
|
||||||
|
app.useTool{ tool=pencil, brush=b, points={ Point(2, 0) } }
|
||||||
|
expect_eq(cel.bounds, Rectangle(1, 0, 7, 1))
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ c, c, 0, 0, 0, c, c })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
drawing_with_symmetry(ColorMode.RGB, rgba(255, 0, 0),
|
||||||
|
ColorMode.RGB, rgba(255, 0, 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- useTool in a transaction
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(2, 2)
|
||||||
|
local r = red.rgbaPixel
|
||||||
|
local y = yellow.rgbaPixel
|
||||||
|
app.fgColor = r
|
||||||
|
|
||||||
|
local cel = s.cels[1]
|
||||||
|
expect_img(cel.image, { 0, 0,
|
||||||
|
0, 0 })
|
||||||
|
app.transaction(
|
||||||
|
function()
|
||||||
|
app.useTool{ tool=pencil,
|
||||||
|
color=r, brush=Brush{ size=1 },
|
||||||
|
points={ Point(0, 0) } }
|
||||||
|
app.useTool{ tool=pencil,
|
||||||
|
color=y, brush=Brush{ size=1 },
|
||||||
|
points={ Point(1, 1) } }
|
||||||
|
end)
|
||||||
|
expect_img(cel.image, { r, 0,
|
||||||
|
0, y })
|
||||||
|
app.undo() -- Undo the whole transaction (two useTool grouped in one transaction)
|
||||||
|
expect_img(cel.image, { 0, 0,
|
||||||
|
0, 0 })
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- draw with tiled mode + image brush
|
||||||
|
-- test for: https://community.aseprite.org/t/tile-mode-glitch/1183
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
function drawing_with_tiled_mode_and_image_brush()
|
||||||
|
print("drawing_with_tiled_mode_and_image_brush")
|
||||||
|
local spr = Sprite(8, 3, ColorMode.INDEXED)
|
||||||
|
local cel = spr.cels[1]
|
||||||
|
|
||||||
|
-- enable tiled mode
|
||||||
|
local pref = app.preferences
|
||||||
|
local docPref = pref.document(spr)
|
||||||
|
docPref.tiled.mode = 3 -- both
|
||||||
|
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0 })
|
||||||
|
|
||||||
|
-- Create brush
|
||||||
|
local brushImg = Image(5, 2, ColorMode.INDEXED)
|
||||||
|
array_to_pixels({ 1, 2, 3, 2, 1,
|
||||||
|
0, 1, 2, 1, 0 }, brushImg)
|
||||||
|
local bru = Brush { image=brushImg }
|
||||||
|
|
||||||
|
-- Without overflow
|
||||||
|
app.useTool{ tool=pencil, brush=bru, points={ Point(2, 1) } }
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 1, 2, 3, 2, 1,
|
||||||
|
0, 1, 2, 1, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Overflow at the left-side
|
||||||
|
app.useTool{ tool=pencil, brush=bru, points={ Point(1, 1) } }
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 2, 3, 2, 1, 0, 0, 0, 1,
|
||||||
|
1, 2, 1, 0, 0, 0, 0, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Overflow at the right-side
|
||||||
|
app.useTool{ tool=pencil, brush=bru, points={ Point(9, 1) } }
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 2, 3, 2, 1, 0, 0, 0, 1,
|
||||||
|
1, 2, 1, 0, 0, 0, 0, 0 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Overflow at the top
|
||||||
|
app.useTool{ tool=pencil, brush=bru, points={ Point(0, 0) } }
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 2, 1, 0, 0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
3, 2, 1, 0, 0, 0, 1, 2 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Overflow at the bottom
|
||||||
|
app.useTool{ tool=pencil, brush=bru, points={ Point(1, 3) } }
|
||||||
|
expect_img(cel.image,
|
||||||
|
{ 1, 2, 1, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
2, 3, 2, 1, 0, 0, 0, 1 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
docPref.tiled.mode = 0 -- none (disable tiled mode)
|
||||||
|
end
|
||||||
|
drawing_with_tiled_mode_and_image_brush()
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- countour with pixel perfect
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
do
|
||||||
|
local s = Sprite(3, 3, ColorMode.INDEXED)
|
||||||
|
local i = app.activeImage
|
||||||
|
i:clear(1)
|
||||||
|
expect_img(i,
|
||||||
|
{ 1, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, 1, 1 })
|
||||||
|
app.useTool{
|
||||||
|
tool='contour',
|
||||||
|
brush=Brush(1),
|
||||||
|
color=2,
|
||||||
|
freehandAlgorithm=1, -- 1=FreehandAlgorithm.PIXEL_PERFECT
|
||||||
|
points={ { 1, 1 }, { 2, 1 }, { 2, 2 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 1, 1, 1,
|
||||||
|
1, 2, 1,
|
||||||
|
1, 1, 2 })
|
||||||
|
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Test one pixel when using one point
|
||||||
|
app.useTool{
|
||||||
|
tool='contour',
|
||||||
|
brush=Brush(1),
|
||||||
|
color=2,
|
||||||
|
freehandAlgorithm=1, -- 1=FreehandAlgorithm.PIXEL_PERFECT
|
||||||
|
points={ { 1, 1 } }
|
||||||
|
}
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 1, 1, 1,
|
||||||
|
1, 2, 1,
|
||||||
|
1, 1, 1 })
|
||||||
|
app.undo()
|
||||||
|
|
||||||
|
-- Test bug where one click doesn't draw with the contour tool with
|
||||||
|
-- pixel perfect algorith.
|
||||||
|
-- Report: https://community.aseprite.org/t/13149
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 1, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, 1, 1 })
|
||||||
|
app.useTool{
|
||||||
|
tool='contour',
|
||||||
|
brush=Brush(1),
|
||||||
|
color=2,
|
||||||
|
freehandAlgorithm=1, -- 1=FreehandAlgorithm.PIXEL_PERFECT
|
||||||
|
-- Two points in the same spot, this happens in the UI, one
|
||||||
|
-- created in mouse down, other in mouse up.
|
||||||
|
points={ { 1, 1 }, { 1, 1 } }
|
||||||
|
}
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 1, 1, 1,
|
||||||
|
1, 2, 1,
|
||||||
|
1, 1, 1 })
|
||||||
|
end
|
41
tests/scripts/version.lua
Normal file
41
tests/scripts/version.lua
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
-- Copyright (C) 2019-2021 Igara Studio S.A.
|
||||||
|
-- Copyright (C) 2018 David Capello
|
||||||
|
--
|
||||||
|
-- This file is released under the terms of the MIT license.
|
||||||
|
-- Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
assert(string.sub(tostring(app.version), 1, 1) == "1")
|
||||||
|
assert(string.sub(tostring(app.version), 2, 2) == ".")
|
||||||
|
assert(app.version.major == 1)
|
||||||
|
|
||||||
|
-- We cannot test the specific app.version from the "main" branch
|
||||||
|
-- because it's "1.x-dev" (which is converted to "1.0-dev" as Version object)
|
||||||
|
--assert(app.version > Version("1.2.10-beta4"))
|
||||||
|
|
||||||
|
assert(Version("1") == Version("1"))
|
||||||
|
assert(Version("1.1") > Version("1"))
|
||||||
|
assert(Version("0.1") < Version("0.2"))
|
||||||
|
assert(Version("1.0.1") > Version("1"))
|
||||||
|
assert(Version("1.0.1") < Version("1.1"))
|
||||||
|
assert(Version("1.0.1") == Version("1.0.1"))
|
||||||
|
assert(Version("1.0.1") ~= Version("1.0.2"))
|
||||||
|
assert(Version("1.0.1") > Version("1.0.1-beta"))
|
||||||
|
assert(Version("1.0.1") > Version("1.0.1-dev"))
|
||||||
|
assert(Version("1.0.1-beta") > Version("1.0.1-alpha"))
|
||||||
|
assert(Version("1.0.1-beta50") < Version("1.0.1-beta100"))
|
||||||
|
assert(Version("1.0.1-beta50") <= Version("1.0.1-beta100"))
|
||||||
|
assert(Version("1.0.1-beta100") <= Version("1.0.1-beta100"))
|
||||||
|
|
||||||
|
local v = Version()
|
||||||
|
assert(v.major == 0)
|
||||||
|
assert(v.minor == 0)
|
||||||
|
assert(v.patch == 0)
|
||||||
|
assert(v.prereleaseLabel == "")
|
||||||
|
assert(v.prereleaseNumber == 0)
|
||||||
|
|
||||||
|
v = Version("1.2.10-beta4")
|
||||||
|
assert(v.major == 1)
|
||||||
|
assert(v.minor == 2)
|
||||||
|
assert(v.patch == 10)
|
||||||
|
assert(v.prereleaseLabel == "beta")
|
||||||
|
assert(v.prereleaseNumber == 4)
|
BIN
tests/sprites/1empty3.aseprite
Normal file
BIN
tests/sprites/1empty3.aseprite
Normal file
Binary file not shown.
BIN
tests/sprites/2f-index-3x3.aseprite
Normal file
BIN
tests/sprites/2f-index-3x3.aseprite
Normal file
Binary file not shown.
27
tests/sprites/README.md
Normal file
27
tests/sprites/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Files
|
||||||
|
|
||||||
|
* `abcd.aseprite`: Indexed, 32x32, four layers ("a", "b", "c", "d")
|
||||||
|
* `1empty3.aseprite`: RGB, 32x32, two layers ("fg", "bg"), 2nd frame
|
||||||
|
completelly empty, two tags ("a", "b")
|
||||||
|
* `groups2.aseprite`: Indexed, 8x8, two groups ("items", "player"),
|
||||||
|
two layers per group ("items/gun", "items/sword", "player/head",
|
||||||
|
"player/body"), with one layer hidden ("items/gun").
|
||||||
|
* `groups3abc.aseprite`: RGB, 9x11, three groups ("a", "b", "c"), with
|
||||||
|
three layers each one (called "a", "b", "c" too). There is a
|
||||||
|
combination of visibilities ("b/b", "c", "c/a", and "c/b" are
|
||||||
|
hidden).
|
||||||
|
* `bg-index-3.aseprite`: Indexed, 4x4, two layers ("fg" and "bg")
|
||||||
|
with a special transparent index color (= palette index 3).
|
||||||
|
* `tags3.aseprite`: 3 tags ("forward", "reverse", "pingpong") and 3
|
||||||
|
layers ("a", "b", "c"), 4x4, several linked cels + layer "c" with
|
||||||
|
empty cels.
|
||||||
|
* `point4frames.aseprite`: Indexed, 4 frames, 2 layers, same cel
|
||||||
|
content but different positions, can be used to test
|
||||||
|
`-merge-duplicates` to check if all cels go to the same sprite sheet
|
||||||
|
position.
|
||||||
|
* `point2frames.aseprite`: Indexed, 2 frames, 1 layer, same cel
|
||||||
|
content as in `point4frames.aseprite`. Useful to test if
|
||||||
|
`"sourceSize"` is different when two cels from different sprites are
|
||||||
|
merged in the same texture atlas.
|
||||||
|
* `2f-index-3x3.aseprite`: Indexed, 2 frames, 1 layer, mask color set
|
||||||
|
to index 21.
|
BIN
tests/sprites/abcd.aseprite
Normal file
BIN
tests/sprites/abcd.aseprite
Normal file
Binary file not shown.
BIN
tests/sprites/bg-index-3.aseprite
Normal file
BIN
tests/sprites/bg-index-3.aseprite
Normal file
Binary file not shown.
BIN
tests/sprites/groups2.aseprite
Normal file
BIN
tests/sprites/groups2.aseprite
Normal file
Binary file not shown.
BIN
tests/sprites/groups3abc.aseprite
Normal file
BIN
tests/sprites/groups3abc.aseprite
Normal file
Binary file not shown.
BIN
tests/sprites/link.aseprite
Normal file
BIN
tests/sprites/link.aseprite
Normal file
Binary file not shown.
BIN
tests/sprites/point2frames.aseprite
Normal file
BIN
tests/sprites/point2frames.aseprite
Normal file
Binary file not shown.
BIN
tests/sprites/point4frames.aseprite
Normal file
BIN
tests/sprites/point4frames.aseprite
Normal file
Binary file not shown.
BIN
tests/sprites/tags3.aseprite
Normal file
BIN
tests/sprites/tags3.aseprite
Normal file
Binary file not shown.
1
tests/third_party/json
vendored
Submodule
1
tests/third_party/json
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit dbf4b2dd2eb7c23be2773c89eb059dadd6436f94
|
Loading…
Reference in New Issue
Block a user