feat: clothing lane, character sources, and DCC bridges
Bulk import of the working lanes that were living untracked on the PC. Content: - characters/ Lena/male body lanes, bakes, texture work, run logs - clothing/ garment pipeline, configs, gates, contract docs - garments/ MD-authored garment sources (.zprj/.zpac) - UAL-Lib/ Universal Animation Library 2 source (.blend/.fbx/.glb) - tools/ blender_bridge, iclone_bridge, md_bridge, tailor, glm_agent - docs/, plans/, dev/, .agents/plans/ Repo hygiene: - .gitattributes: LFS now covers .blend, .zprj, .zpac, .obj, .npy and the Reallusion .iAvatar/.ccAvatar/.ccRestore containers. Without this the ~3.8 GB in this commit would land as raw blobs. .png/.jpg are left out on purpose — ~250 are already tracked raw and converting them would rewrite every one without shrinking history. - .gitignore: exclude /accurig/ (~1 GB AccuRig program files, redistributable from Reallusion, nothing authored here) and /dev/null/ (git-lfs hook copies dropped by a `>/dev/null` redirect on Windows). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
# MD session recon -- run FIRST thing next bridge session:
|
||||
# python tools/md_bridge.py --file tools/tailor/md_recon.py --timeout 300
|
||||
#
|
||||
# 1. Harvests pybind11 docstrings (all overloads) for every function the
|
||||
# t-shirt build needs -> tools/md_bridge/api_docs.json
|
||||
# 2. Imports the Lena avatar FBX (tools/tailor/avatar/Lena_QuatSkin_Avatar.fbx)
|
||||
# 3. Lists arrangement points, snapshots the scene
|
||||
# Defensive: each step reports independently; nothing dies on the first surprise.
|
||||
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import traceback
|
||||
|
||||
REPO = r"C:\Users\Jeremy\tinqs\animation"
|
||||
AVATAR_FBX = os.path.join(REPO, "tools", "tailor", "avatar", "Lena_QuatSkin_Avatar.fbx")
|
||||
DOCS_OUT = os.path.join(REPO, "tools", "md_bridge", "api_docs.json")
|
||||
|
||||
report = {"steps": []}
|
||||
|
||||
|
||||
def step(name, fn):
|
||||
entry = {"step": name}
|
||||
try:
|
||||
entry["ok"] = True
|
||||
entry["value"] = fn()
|
||||
except Exception:
|
||||
entry["ok"] = False
|
||||
entry["error"] = traceback.format_exc().strip().splitlines()[-1]
|
||||
report["steps"].append(entry)
|
||||
return entry
|
||||
|
||||
|
||||
# ---- 1. docstring harvest -------------------------------------------------
|
||||
WANTED = {
|
||||
"import_api": ["ImportAvatar", "ImportFBX", "ImportOBJ", "ImportFile",
|
||||
"ImportZpac", "ImportPose"],
|
||||
"export_api": ["ExportSnapshot3D", "ExportCustomViewSnapshot", "ExportFBX",
|
||||
"ExportOBJ", "ExportZPac", "ExportTurntableImages",
|
||||
"GetAvatarCount", "GetAvatarNameList"],
|
||||
"pattern_api": ["CreatePatternWithPoints", "CreateInternalShapeWithPoints",
|
||||
"AddSeamlinePairGroup", "GetSeamlinePairGroupCount",
|
||||
"SetArrangement", "SetArrangementPosition",
|
||||
"SetArrangementOrientation", "GetArrangementList",
|
||||
"GetArrangementOfPattern", "SetPatternPiecePos",
|
||||
"SetPatternPieceMove", "MovePatternPoint", "FlipPatternPiece",
|
||||
"GetPatternIndexList", "GetPatternInformation",
|
||||
"SetPatternPieceElastic", "DeletePatternPiece"],
|
||||
"fabric_api": ["GetFabricList", "GetFabricIndexForPattern",
|
||||
"SetFabricForPattern", "AddFabric", "SetFabricColor"],
|
||||
"utility_api": ["Simulate", "NewProject", "OpenProject", "SaveProjectFile",
|
||||
"SetColorwayIndex", "DeleteAvatar",
|
||||
"AlignAvatarsAndGarmentToCenter", "ResetSimulation",
|
||||
"SetSimulationQuality", "GetCurrentProjectFilePath"],
|
||||
"ApiTypes": ["ImportExportOption"],
|
||||
}
|
||||
|
||||
|
||||
def harvest():
|
||||
docs = {}
|
||||
for mod_name, names in WANTED.items():
|
||||
mod = globals().get(mod_name)
|
||||
if mod is None:
|
||||
continue
|
||||
for n in names:
|
||||
f = getattr(mod, n, None)
|
||||
key = "{}.{}".format(mod_name, n)
|
||||
docs[key] = (getattr(f, "__doc__", None) or "<missing>") if f is not None else "<missing>"
|
||||
# ImportExportOption: dump its member names too -- it's the option struct
|
||||
opt = getattr(ApiTypes, "ImportExportOption", None)
|
||||
if opt is not None:
|
||||
docs["ApiTypes.ImportExportOption.members"] = [
|
||||
m for m in dir(opt) if not m.startswith("_")]
|
||||
with open(DOCS_OUT, "w", encoding="utf-8") as f:
|
||||
json.dump(docs, f, indent=1)
|
||||
return {"harvested": len(docs), "out": DOCS_OUT}
|
||||
|
||||
|
||||
step("harvest_docs", harvest)
|
||||
|
||||
# ---- 2. fresh scene + avatar ----------------------------------------------
|
||||
step("NewProject", lambda: utility_api.NewProject())
|
||||
step("avatar_file_exists", lambda: os.path.getsize(AVATAR_FBX))
|
||||
|
||||
|
||||
def import_avatar():
|
||||
# Try the simplest overload first; fall back to option-struct form.
|
||||
try:
|
||||
return {"call": "ImportAvatar(path)", "ret": import_api.ImportAvatar(AVATAR_FBX)}
|
||||
except TypeError:
|
||||
op = ApiTypes.ImportExportOption()
|
||||
return {"call": "ImportAvatar(path, op)",
|
||||
"ret": import_api.ImportAvatar(AVATAR_FBX, op)}
|
||||
|
||||
|
||||
step("ImportAvatar", import_avatar)
|
||||
step("avatars_after", lambda: {"count": export_api.GetAvatarCount(),
|
||||
"names": export_api.GetAvatarNameList()})
|
||||
step("arrangement_points", lambda: pattern_api.GetArrangementList())
|
||||
|
||||
# ---- 3. look at her --------------------------------------------------------
|
||||
SNAP = os.path.join(tempfile.gettempdir(), "tinqs_md_lena_avatar.png")
|
||||
|
||||
|
||||
def snap():
|
||||
export_api.ExportSnapshot3D(SNAP)
|
||||
return {"path": SNAP, "exists": os.path.exists(SNAP),
|
||||
"size": os.path.getsize(SNAP) if os.path.exists(SNAP) else 0}
|
||||
|
||||
|
||||
step("snapshot", snap)
|
||||
|
||||
report["passed"] = sum(1 for s in report["steps"] if s["ok"])
|
||||
report["failed"] = sum(1 for s in report["steps"] if not s["ok"])
|
||||
result = report
|
||||
Reference in New Issue
Block a user