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!')
|
||||
|
||||
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]]:
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user