Files
SkinPress/scripts/relearn/fix_left_maps.py
M1rsem ec62941845 Initial release: SkinPress — Minecraft skin to Bambu 3MF
ModVer full-body and MakerWorld chibi customizers with tests and templates.
2026-07-20 10:02:33 +03:00

86 lines
2.9 KiB
Python

"""Post-process pixel UV maps: rebuild left-limb maps from right-limb maps."""
from __future__ import annotations
import json
from pathlib import Path
from PIL import Image
from skin_figurine.regions import REGIONS
ROOT = Path(__file__).resolve().parents[2]
SKINS = ROOT / "tests" / "fixtures" / "skins"
MAPS = ROOT / "skin_figurine" / "data" / "pixel_uv_maps.json"
def remap_info(info: dict, src_regions: dict, dst_regions: dict) -> dict:
face = info["face"]
i, j = info["i"], info["j"]
if face not in dst_regions:
return dict(info)
x0, y0, w, h = dst_regions[face]
# clamp
i = min(max(i, 0), w - 1)
j = min(max(j, 0), h - 1)
out = dict(info)
out["i"] = i
out["j"] = j
out["u"] = x0 + i
out["v"] = y0 + j
out["remapped_from_right"] = True
return out
def rebuild_left(style: str, data: dict) -> None:
pairs = [("arm_r", "arm_l"), ("leg_r", "leg_l")]
regions = REGIONS[style]
for right_key, left_key in pairs:
right_map = data[style][right_key]
# Index right map by (face,i,j) — primary; also keep list for zip fallback
by_fij = {}
for k, info in right_map.items():
by_fij[(info["face"], info["i"], info["j"])] = info
left_map = data[style][left_key]
# Rebuild: for every left key, if we can find same face/i/j in right, remap UV.
# Left keys that only exist on left: zip-sorted with right keys.
new_left = {}
right_sorted = sorted(right_map.items(), key=lambda kv: int(kv[0]) if kv[0].isdigit() else kv[0])
left_keys = sorted(left_map.keys(), key=lambda k: int(k) if k.isdigit() else k)
# Prefer 1:1 by sorted key order (same Blender stack order on mirrored parts)
for idx, lk in enumerate(left_keys):
if idx < len(right_sorted):
_rk, rinfo = right_sorted[idx]
new_left[lk] = remap_info(rinfo, regions[right_key], regions[left_key])
elif lk in left_map:
# keep old if any
info = left_map[lk]
new_left[lk] = remap_info(info, regions[left_key], regions[left_key])
# Also ensure every right (face,i,j) has a left counterpart via key order already
data[style][left_key] = new_left
print(f"{style}.{left_key}: rebuilt {len(new_left)} entries from {right_key}")
def main():
data = json.loads(MAPS.read_text(encoding="utf-8"))
rebuild_left("classic", data)
rebuild_left("slim", data)
MAPS.write_text(json.dumps(data, indent=2), encoding="utf-8")
print(f"Updated {MAPS}")
# Quick validate against jay left leg opaque count
from PIL import Image
skin = Image.open(SKINS / "jay.png").convert("RGBA")
pred = 0
for info in data["classic"]["leg_l"].values():
if skin.getpixel((info["u"], info["v"]))[3] > 10:
pred += 1
print(f"jay left leg predicted opaque mappings: {pred}")
if __name__ == "__main__":
main()