1
0
mirror of synced 2025-01-19 06:27:23 +01:00

Add support for offsetting the background animation loop.

This commit is contained in:
Jennifer Taylor 2021-08-12 15:57:02 +00:00
parent aa04762b41
commit 9c2c7fe3a9
2 changed files with 201 additions and 21 deletions

View File

@ -0,0 +1,150 @@
# vim: set fileencoding=utf-8
import unittest
from bemani.utils.afputils import parse_intlist, adjust_background_loop
class TestAFPUtils(unittest.TestCase):
def test_parse_intlist(self) -> None:
# Simple
self.assertEqual(
parse_intlist("5"),
[5],
)
# Comma separated
self.assertEqual(
parse_intlist("5,7,9"),
[5, 7, 9],
)
# Range
self.assertEqual(
parse_intlist("5-9"),
[5, 6, 7, 8, 9],
)
# Duplicate
self.assertEqual(
parse_intlist("5,7,7,9"),
[5, 7, 9],
)
# Overlapping range
self.assertEqual(
parse_intlist("5-9,8-10"),
[5, 6, 7, 8, 9, 10],
)
# Out of order
self.assertEqual(
parse_intlist("5,3,1"),
[1, 3, 5],
)
# All manner of combos
self.assertEqual(
parse_intlist("5,13-17,23,9,27-29,23,33"),
[5, 9, 13, 14, 15, 16, 17, 23, 27, 28, 29, 33],
)
def test_adjust_background_loop(self) -> None:
# No adjustment
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
background_loop_start=None,
background_loop_end=None,
background_loop_offset=None,
),
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
)
# Specify start
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
background_loop_start=6,
background_loop_end=None,
background_loop_offset=None,
),
[6, 7, 8, 9, 10],
)
# Specify end
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5],
background_loop_start=None,
background_loop_end=5,
background_loop_offset=None,
),
[1, 2, 3, 4, 5],
)
# Specify start and end
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
background_loop_start=5,
background_loop_end=9,
background_loop_offset=None,
),
[5, 6, 7, 8, 9],
)
# Specify loop offset
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
background_loop_start=None,
background_loop_end=None,
background_loop_offset=7,
),
[7, 8, 9, 10, 1, 2, 3, 4, 5, 6],
)
# Specify start and loop offset
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
background_loop_start=6,
background_loop_end=None,
background_loop_offset=8,
),
[8, 9, 10, 6, 7],
)
# Specify end and loop offset
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5],
background_loop_start=None,
background_loop_end=5,
background_loop_offset=3,
),
[3, 4, 5, 1, 2],
)
# Specify start, end and loop offset
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
background_loop_start=5,
background_loop_end=9,
background_loop_offset=6,
),
[6, 7, 8, 9, 5],
)
# Only one frame.
self.assertEqual(
adjust_background_loop(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
background_loop_start=5,
background_loop_end=5,
background_loop_offset=None,
),
[5],
)

View File

@ -8,7 +8,7 @@ import os.path
import sys
import textwrap
from PIL import Image, ImageDraw # type: ignore
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Tuple, TypeVar
from bemani.format.afp import TXP2File, Shape, SWF, Frame, Tag, AP2DoActionTag, AP2PlaceObjectTag, AP2DefineSpriteTag, AFPRenderer, Color, Matrix
from bemani.format import IFS
@ -517,6 +517,45 @@ def list_paths(containers: List[str], *, include_frames: bool=False, include_siz
return 0
BackgroundT = TypeVar("BackgroundT")
def adjust_background_loop(
background: List[BackgroundT],
background_loop_start: Optional[int] = None,
background_loop_end: Optional[int] = None,
background_loop_offset: Optional[int] = None,
) -> List[BackgroundT]:
# Make sure background frames are 1-indexed here as well.
if background_loop_start is None:
background_loop_start = 0
else:
background_loop_start -= 1
if background_loop_offset is None:
background_loop_offset = 0
else:
background_loop_offset -= (background_loop_start + 1)
# Don't one-index the end because we want it to be inclusive.
if background_loop_end is None:
background_loop_end = len(background)
if background_loop_start >= background_loop_end:
raise Exception("Cannot start background loop after the end of the background loop!")
if background_loop_start < 0 or background_loop_end < 0:
raise Exception("Cannot start or end background loop on a negative frame!")
if background_loop_start >= len(background) or background_loop_end > len(background):
raise Exception("Cannot start or end background loop larger than the number of background animation frames!")
background = background[background_loop_start:background_loop_end]
if background_loop_offset < 0 or background_loop_offset >= len(background):
raise Exception("Cannot start first iteration of background loop outside the loop bounds!")
return background[background_loop_offset:] + background[:background_loop_offset]
def render_path(
containers: List[str],
path: str,
@ -528,6 +567,7 @@ def render_path(
background_image: Optional[str] = None,
background_loop_start: Optional[int] = None,
background_loop_end: Optional[int] = None,
background_loop_offset: Optional[int] = None,
force_width: Optional[int] = None,
force_height: Optional[int] = None,
force_aspect_ratio: Optional[str] = None,
@ -634,24 +674,7 @@ def render_path(
else:
raise Exception("Invalid image specified as background!")
# Make sure background frames are 1-indexed here as well.
if background_loop_start is None:
background_loop_start = 0
else:
background_loop_start -= 1
# Don't one-index the end because we want it to be inclusive.
if background_loop_end is None:
background_loop_end = len(background)
if background_loop_start >= background_loop_end:
raise Exception("Cannot start background loop after the end of the background loop!")
if background_loop_start < 0 or background_loop_end < 0:
raise Exception("Cannot start or end background loop on a negative frame!")
if background_loop_start >= len(background) or background_loop_end > len(background):
raise Exception("Cannot start or end background loop larger than the number of background animation frames!")
background = background[background_loop_start:background_loop_end]
background = adjust_background_loop(background, background_loop_start, background_loop_end, background_loop_offset)
else:
background = None
@ -1001,13 +1024,19 @@ def main() -> int:
"--background-loop-start",
type=int,
default=None,
help="The starting frame of the background animation. Specify this to start the background animation on a frame other than the first.",
help="The starting frame of the background animation loop. Specify this to loop to a background animation frame other than the first.",
)
render_parser.add_argument(
"--background-loop-end",
type=int,
default=None,
help="The ending frame of the background animation. Specify this to end the background animation on a frame other than the last.",
help="The ending frame of the background animation loop. Specify this to loop from a background animation frame other than the last.",
)
render_parser.add_argument(
"--background-loop-offset",
type=int,
default=None,
help="The very first frame of the background animation. Specify this to start the first loop anywhere other than the loop start frame.",
)
render_parser.add_argument(
"--only-depths",
@ -1136,6 +1165,7 @@ def main() -> int:
background_image=args.background_image,
background_loop_start=args.background_loop_start,
background_loop_end=args.background_loop_end,
background_loop_offset=args.background_loop_offset,
force_width=args.force_width,
force_height=args.force_height,
force_aspect_ratio=args.force_aspect_ratio,