diff --git a/bemani/utils/afputils.py b/bemani/utils/afputils.py
index 0428341..00b6706 100644
--- a/bemani/utils/afputils.py
+++ b/bemani/utils/afputils.py
@@ -1676,6 +1676,12 @@ def main() -> int:
action="store_true",
help="Generate overlay images showing mappings",
)
+ extract_parser.add_argument(
+ "-s",
+ "--split-textures",
+ action="store_true",
+ help="Split textures into individual sprites",
+ )
update_parser = subparsers.add_parser('update', help='Update relevant textures in a file from a directory')
update_parser.add_argument(
@@ -1711,67 +1717,75 @@ def main() -> int:
args = parser.parse_args()
if args.action == "extract":
+ if args.split_textures:
+ if args.write_raw:
+ raise Exception("Cannot write raw textures when splitting sprites!")
+ if args.generate_mapping_overlays:
+ raise Exception("Cannot generate mapping overlays when splitting sprites!")
+
with open(args.file, "rb") as bfp:
afpfile = AFPFile(bfp.read(), verbose=args.verbose)
# Actually place the files down.
os.makedirs(args.dir, exist_ok=True)
- for texture in afpfile.textures:
- filename = os.path.join(args.dir, texture.name)
+ if not args.split_textures:
+ for texture in afpfile.textures:
+ filename = os.path.join(args.dir, texture.name)
- if texture.img:
- if args.pretend:
- print(f"Would write {filename}.png texture...")
- else:
- print(f"Writing {filename}.png texture...")
- with open(f"{filename}.png", "wb") as bfp:
- texture.img.save(bfp, format='PNG')
+ if texture.img:
+ if args.pretend:
+ print(f"Would write {filename}.png texture...")
+ else:
+ print(f"Writing {filename}.png texture...")
+ with open(f"{filename}.png", "wb") as bfp:
+ texture.img.save(bfp, format='PNG')
- if not texture.img or args.write_raw:
- if args.pretend:
- print(f"Would write {filename}.raw texture...")
- else:
- print(f"Writing {filename}.raw texture...")
- with open(f"{filename}.raw", "wb") as bfp:
- bfp.write(texture.raw)
+ if not texture.img or args.write_raw:
+ if args.pretend:
+ print(f"Would write {filename}.raw texture...")
+ else:
+ print(f"Writing {filename}.raw texture...")
+ with open(f"{filename}.raw", "wb") as bfp:
+ bfp.write(texture.raw)
- if args.pretend:
- print(f"Would write {filename}.xml texture info...")
- else:
- print(f"Writing {filename}.xml texture info...")
- with open(f"{filename}.xml", "w") as sfp:
- sfp.write(textwrap.dedent(f"""
-
- {texture.width}
- {texture.height}
- {hex(texture.fmt)}
- {filename}.raw
-
- """).strip())
+ if args.pretend:
+ print(f"Would write {filename}.xml texture info...")
+ else:
+ print(f"Writing {filename}.xml texture info...")
+ with open(f"{filename}.xml", "w") as sfp:
+ sfp.write(textwrap.dedent(f"""
+
+ {texture.width}
+ {texture.height}
+ {hex(texture.fmt)}
+ {filename}.raw
+
+ """).strip())
if args.write_mappings:
- 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]
- filename = os.path.join(args.dir, name)
+ if not args.split_textures:
+ 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]
+ filename = os.path.join(args.dir, name)
- if args.pretend:
- print(f"Would write {filename}.xml region information...")
- else:
- print(f"Writing {filename}.xml region information...")
- with open(f"{filename}.xml", "w") as sfp:
- sfp.write(textwrap.dedent(f"""
-
- {region.left}
- {region.top}
- {region.right}
- {region.bottom}
- {texturename}
-
- """).strip())
+ if args.pretend:
+ print(f"Would write {filename}.xml region information...")
+ else:
+ print(f"Writing {filename}.xml region information...")
+ with open(f"{filename}.xml", "w") as sfp:
+ sfp.write(textwrap.dedent(f"""
+
+ {region.left}
+ {region.top}
+ {region.right}
+ {region.bottom}
+ {texturename}
+
+ """).strip())
if afpfile.fontdata is not None:
filename = os.path.join(args.dir, "fontinfo.xml")
@@ -1826,6 +1840,43 @@ def main() -> int:
with open(filename, "wb") as bfp:
img.save(bfp, format='PNG')
+ if args.split_textures:
+ textures: Dict[str, Any] = {}
+ announced: Dict[str, bool] = {}
+
+ 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 textures:
+ for tex in afpfile.textures:
+ if tex.name == texturename:
+ textures[texturename] = tex
+ break
+ else:
+ raise Exception("Could not find texture {texturename} to split!")
+
+ if textures[texturename].img:
+ # Grab the location in the image, save it out to a new file.
+ filename = f"{texturename}_{name}.png"
+ filename = os.path.join(args.dir, filename)
+
+ if args.pretend:
+ print(f"Would write {filename} sprite...")
+ else:
+ print(f"Writing {filename} sprite...")
+ sprite = textures[texturename].img.crop(
+ (region.left // 2, region.top // 2, region.right // 2, region.bottom // 2),
+ )
+ with open(filename, "wb") as bfp:
+ sprite.save(bfp, format='PNG')
+ else:
+ if not announced.get(texturename, False):
+ print(f"Cannot extract sprites from {texturename} because it is not a supported format!")
+ announced[texturename] = True
+
if args.action == "update":
# First, parse the file out
with open(args.file, "rb") as bfp: