Hook up TXP2 container to renderer, provide a "list" option to list out possible rendering paths in a container.
This commit is contained in:
parent
d4faa9f7d8
commit
de5dfd2421
@ -75,6 +75,17 @@ class AFPRenderer(VerboseOutput):
|
|||||||
|
|
||||||
raise Exception(f'{path} not found in registered SWFs!')
|
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]:
|
def __place(self, tag: Tag, parent_sprite: Optional[int], prefix: str = "") -> List[Clip]:
|
||||||
if isinstance(tag, AP2ShapeTag):
|
if isinstance(tag, AP2ShapeTag):
|
||||||
self.vprint(f"{prefix} Loading {tag.reference} into shape slot {tag.id}")
|
self.vprint(f"{prefix} Loading {tag.reference} into shape slot {tag.id}")
|
||||||
@ -185,7 +196,8 @@ class AFPRenderer(VerboseOutput):
|
|||||||
return img
|
return img
|
||||||
|
|
||||||
if params.flags & 0x4 or params.flags & 0x8:
|
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
|
texture = None
|
||||||
if params.flags & 0x2:
|
if params.flags & 0x2:
|
||||||
@ -194,6 +206,7 @@ class AFPRenderer(VerboseOutput):
|
|||||||
raise Exception(f"Cannot find texture reference {params.region}!")
|
raise Exception(f"Cannot find texture reference {params.region}!")
|
||||||
texture = self.textures[params.region]
|
texture = self.textures[params.region]
|
||||||
|
|
||||||
|
if texture is not None:
|
||||||
# Now, render out the texture.
|
# Now, render out the texture.
|
||||||
cutin = Point(offset.x, offset.y)
|
cutin = Point(offset.x, offset.y)
|
||||||
cutoff = Point.identity()
|
cutoff = Point.identity()
|
||||||
|
@ -168,6 +168,21 @@ def main() -> int:
|
|||||||
help="Display verbuse debugging output",
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.action == "extract":
|
if args.action == "extract":
|
||||||
@ -429,7 +444,7 @@ def main() -> int:
|
|||||||
print(geo, file=sys.stderr)
|
print(geo, file=sys.stderr)
|
||||||
print(json.dumps(geo.as_dict(), sort_keys=True, indent=4))
|
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
|
# 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.
|
# directories of files as well as support IFS files and TXP2 files.
|
||||||
renderer = AFPRenderer()
|
renderer = AFPRenderer()
|
||||||
@ -446,8 +461,54 @@ def main() -> int:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if afpfile is not None:
|
if afpfile is not None:
|
||||||
# TODO: Load from afp container
|
if args.verbose:
|
||||||
pass
|
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
|
ifsfile = None
|
||||||
try:
|
try:
|
||||||
@ -456,6 +517,8 @@ def main() -> int:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if ifsfile is not None:
|
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:
|
for fname in ifsfile.filenames:
|
||||||
if fname.startswith(f"geo{os.sep}"):
|
if fname.startswith(f"geo{os.sep}"):
|
||||||
# Trim off directory.
|
# Trim off directory.
|
||||||
@ -492,12 +555,18 @@ def main() -> int:
|
|||||||
|
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
print(f"Added {afpname} to SWF library.", file=sys.stderr)
|
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)
|
duration, images = renderer.render_path(args.path, verbose=args.verbose)
|
||||||
if len(images) == 0:
|
if len(images) == 0:
|
||||||
raise Exception("Did not render any frames!")
|
raise Exception("Did not render any frames!")
|
||||||
images[0].save(args.output, save_all=True, append_images=images[1:], loop=0, duration=duration)
|
images[0].save(args.output, save_all=True, append_images=images[1:], loop=0, duration=duration)
|
||||||
print(f"Wrote animation to {args.output}")
|
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
|
return 0
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user