1
0
mirror of synced 2024-11-27 23:50:47 +01:00

Hook up TXP2 container to renderer, provide a "list" option to list out possible rendering paths in a container.

This commit is contained in:
Jennifer Taylor 2021-04-16 21:08:41 +00:00
parent d4faa9f7d8
commit de5dfd2421
2 changed files with 96 additions and 14 deletions

View File

@ -75,6 +75,17 @@ class AFPRenderer(VerboseOutput):
raise Exception(f'{path} not found in registered SWFs!')
def list_paths(self, verbose: bool = False) -> List[str]:
paths: List[str] = []
for name, swf in self.swfs.items():
paths.append(swf.exported_name)
for export_tag in swf.exported_tags:
paths.append(f"{swf.exported_name}.{export_tag}")
return paths
def __place(self, tag: Tag, parent_sprite: Optional[int], prefix: str = "") -> List[Clip]:
if isinstance(tag, AP2ShapeTag):
self.vprint(f"{prefix} Loading {tag.reference} into shape slot {tag.id}")
@ -185,7 +196,8 @@ class AFPRenderer(VerboseOutput):
return img
if params.flags & 0x4 or params.flags & 0x8:
raise Exception("Don't support shape blend or uv coordinate color yet!")
# TODO: Need to support blending and UV coordinate colors here.
print("WARNING: Unhandled shape blend or UV coordinate color!")
texture = None
if params.flags & 0x2:
@ -194,17 +206,18 @@ class AFPRenderer(VerboseOutput):
raise Exception(f"Cannot find texture reference {params.region}!")
texture = self.textures[params.region]
# Now, render out the texture.
cutin = Point(offset.x, offset.y)
cutoff = Point.identity()
if cutin.x < 0:
cutoff.x = -cutin.x
cutin.x = 0
if cutin.y < 0:
cutoff.y = -cutin.y
cutin.y = 0
if texture is not None:
# Now, render out the texture.
cutin = Point(offset.x, offset.y)
cutoff = Point.identity()
if cutin.x < 0:
cutoff.x = -cutin.x
cutin.x = 0
if cutin.y < 0:
cutoff.y = -cutin.y
cutin.y = 0
img.alpha_composite(texture, cutin.as_tuple(), cutoff.as_tuple())
img.alpha_composite(texture, cutin.as_tuple(), cutoff.as_tuple())
return img
def __render(self, swf: SWF, export_tag: Optional[str]) -> Tuple[int, List[Any]]:

View File

@ -168,6 +168,21 @@ def main() -> int:
help="Display verbuse debugging output",
)
list_parser = subparsers.add_parser('list', help='List out the possible paths to render from a series of SWFs')
list_parser.add_argument(
"container",
metavar="CONTAINER",
type=str,
nargs='+',
help="A container file to use for loading SWF data. Can be either a TXP2 or IFS container.",
)
list_parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Display verbuse debugging output",
)
args = parser.parse_args()
if args.action == "extract":
@ -429,7 +444,7 @@ def main() -> int:
print(geo, file=sys.stderr)
print(json.dumps(geo.as_dict(), sort_keys=True, indent=4))
if args.action == "render":
if args.action in ["render", "list"]:
# This is a complicated one, as we need to be able to specify multiple
# directories of files as well as support IFS files and TXP2 files.
renderer = AFPRenderer()
@ -446,8 +461,54 @@ def main() -> int:
pass
if afpfile is not None:
# TODO: Load from afp container
pass
if args.verbose:
print(f"Loading files out of TXP2 container {container}...", file=sys.stderr)
# First, load GE2D structures into the renderer.
for i, name in enumerate(afpfile.shapemap.entries):
shape = afpfile.shapes[i]
renderer.add_shape(name, shape)
if args.verbose:
print(f"Added {name} to SWF shape library.", file=sys.stderr)
# Now, split and load textures into the renderer.
sheets: Dict[str, Any] = {}
for i, name in enumerate(afpfile.regionmap.entries):
if i < 0 or i >= len(afpfile.texture_to_region):
raise Exception(f"Out of bounds region {i}")
region = afpfile.texture_to_region[i]
texturename = afpfile.texturemap.entries[region.textureno]
if texturename not in sheets:
for tex in afpfile.textures:
if tex.name == texturename:
sheets[texturename] = tex
break
else:
raise Exception("Could not find texture {texturename} to split!")
if sheets[texturename].img:
sprite = sheets[texturename].img.crop(
(region.left // 2, region.top // 2, region.right // 2, region.bottom // 2),
)
renderer.add_texture(name, sprite)
if args.verbose:
print(f"Added {name} to SWF texture library.", file=sys.stderr)
else:
print(f"Cannot load {name} from {texturename} because it is not a supported format!")
# Finally, load the SWF data itself into the renderer.
for i, name in enumerate(afpfile.swfmap.entries):
swf = afpfile.swfdata[i]
renderer.add_swf(name, swf)
if args.verbose:
print(f"Added {name} to SWF library.", file=sys.stderr)
continue
ifsfile = None
try:
@ -456,6 +517,8 @@ def main() -> int:
pass
if ifsfile is not None:
if args.verbose:
print(f"Loading files out of IFS container {container}...", file=sys.stderr)
for fname in ifsfile.filenames:
if fname.startswith(f"geo{os.sep}"):
# Trim off directory.
@ -492,12 +555,18 @@ def main() -> int:
if args.verbose:
print(f"Added {afpname} to SWF library.", file=sys.stderr)
continue
if args.action == "render":
duration, images = renderer.render_path(args.path, verbose=args.verbose)
if len(images) == 0:
raise Exception("Did not render any frames!")
images[0].save(args.output, save_all=True, append_images=images[1:], loop=0, duration=duration)
print(f"Wrote animation to {args.output}")
elif args.action == "list":
paths = renderer.list_paths(verbose=args.verbose)
for path in paths:
print(path)
return 0