3ba86b2ea8
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>
92 lines
2.8 KiB
Python
92 lines
2.8 KiB
Python
# TinqsMDBridge smoke test -- run via:
|
|
# python tools/md_bridge.py --file tools/md_bridge/smoke_test.py --timeout 120
|
|
#
|
|
# Defensive by design: MD's api docs are incomplete and signatures unverified,
|
|
# so every step is independently try/except'd and the whole thing returns a
|
|
# step-by-step report instead of dying on the first surprise. Nothing here
|
|
# should be treated as the "right" calling convention until this has passed
|
|
# once -- it's a probe, not a recipe.
|
|
|
|
import inspect
|
|
import os
|
|
import tempfile
|
|
import traceback
|
|
|
|
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
|
|
|
|
|
|
def docs_of(mod, names):
|
|
out = {}
|
|
for n in names:
|
|
f = getattr(mod, n, None)
|
|
if f is None:
|
|
out[n] = "<missing>"
|
|
continue
|
|
try:
|
|
out[n] = str(inspect.signature(f))
|
|
except (ValueError, TypeError):
|
|
doc = (getattr(f, "__doc__", "") or "").strip()
|
|
out[n] = doc.splitlines()[0] if doc else "<no signature/doc>"
|
|
return out
|
|
|
|
|
|
# 1. what do the key functions actually look like?
|
|
step("signatures.pattern", lambda: docs_of(pattern_api, [
|
|
"CreatePatternWithPoints", "AddSeamlinePairGroup", "SetArrangementPosition",
|
|
"MovePatternPoint", "DeletePatternPiece"]))
|
|
step("signatures.utility", lambda: docs_of(utility_api, [
|
|
"NewProject", "Simulate", "GetAvatarCount", "GetAvatarNameList"]))
|
|
step("signatures.export", lambda: docs_of(export_api, [
|
|
"ExportSnapshot3D", "ExportCustomViewSnapshot", "ExportGLTF", "ExportFBX"]))
|
|
|
|
# 2. fresh project
|
|
step("NewProject", lambda: utility_api.NewProject())
|
|
|
|
# 3. default avatar present?
|
|
step("avatars", lambda: {
|
|
"count": utility_api.GetAvatarCount(),
|
|
"names": utility_api.GetAvatarNameList(),
|
|
})
|
|
|
|
# 4. create a 50cm square pattern (units unverified -- try mm first, the CLO
|
|
# convention; the snapshot will show which interpretation MD used)
|
|
SQUARE_MM = [(0.0, 0.0), (500.0, 0.0), (500.0, 500.0), (0.0, 500.0)]
|
|
|
|
|
|
def make_square():
|
|
return pattern_api.CreatePatternWithPoints(SQUARE_MM)
|
|
|
|
|
|
step("CreatePatternWithPoints(square)", make_square)
|
|
|
|
# 5. short drape
|
|
step("Simulate(30)", lambda: utility_api.Simulate(30))
|
|
|
|
# 6. snapshot -- the agent's eyes
|
|
SNAP = os.path.join(tempfile.gettempdir(), "tinqs_md_smoke.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("ExportSnapshot3D", 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
|