From 89b1fb6f88ef2ea60f28623e04d46072ef15ba21 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Wed, 28 Oct 2026 12:25:51 +0100 Subject: Skip non-numeric morph channels, summarize other-geometry morphs Genesis 9 Starter Essentials ships file-launcher channels (type "file") in its Morphs folder and morphs whose vertex count belongs to other geometry. The first made loading fatal, the second printed one warning per morph. Co-Authored-By: Claude Opus 5.5 --- generat3d/scene.py | 7 ++++++- tests/test_scene.py | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/generat3d/scene.py b/generat3d/scene.py index 722057f..5c35022 100644 --- a/generat3d/scene.py +++ b/generat3d/scene.py @@ -102,6 +102,7 @@ class _Loader: self.graph = Graph() self.loaded = set() self.hd = 0 + self.other_geometry = 0 def run(self): nodes = self.doc.get("scene", {}).get("nodes", []) @@ -138,6 +139,8 @@ class _Loader: warn("pose in scene ignored: the .dbz holds rest data") if self.hd: warn(f"{self.hd} HD morphs: detail ignored (v1)") + if self.other_geometry: + warn(f"{self.other_geometry} morphs for other geometry skipped") return Scene(self.path, self.figure, self.graph) def _figure(self, inst, fpath, asset): @@ -195,6 +198,8 @@ class _Loader: if parent and parent != self.figure.id: continue ch = mod.get("channel", {}) + if ch.get("type", "float") not in ("float", "int"): + continue # file launchers, aliases on bones: not dials for name in ("value", "min", "max"): if name in ch and not _finite(ch[name]): raise Error(f"{path}#{mod['id']}: {name} is not a finite number") @@ -207,7 +212,7 @@ class _Loader: self.hd += 1 d = morph.get("deltas", {}).get("values", []) if morph.get("vertex_count", nverts) != nverts: - warn(f"{path}#{mod['id']}: vertex count mismatch, morph skipped") + self.other_geometry += 1 elif d: arr = np.array(d, dtype=float) if (arr.ndim != 2 or arr.shape[1] != 4 diff --git a/tests/test_scene.py b/tests/test_scene.py index fe6c34d..812ea60 100644 --- a/tests/test_scene.py +++ b/tests/test_scene.py @@ -182,6 +182,21 @@ class SceneTest(unittest.TestCase): _, err = load_quiet(DATA / "scene.duf", [root]) self.assertEqual(err.count("2 HD morphs"), 1) + def test_non_numeric_channel_skipped(self): + launcher = self.mod("Tools") + launcher["channel"] = {"id": "value", "type": "file", "value": "/x/tool.dsa"} + root = self.root(self.MORPHS + "Tools.dsf", self.morph_doc(launcher)) + scene, _ = load_quiet(DATA / "scene.duf", [root]) + self.assertNotIn("Fig:Tools?value", scene.graph.props) + + def test_other_geometry_warning_once(self): + other = {"vertex_count": 99, "deltas": {"values": [[0, 1, 0, 0]]}} + root = self.root(self.MORPHS + "Other.dsf", self.morph_doc( + self.mod("Lash1", other), self.mod("Lash2", other))) + scene, err = load_quiet(DATA / "scene.duf", [root]) + self.assertEqual(err.count("2 morphs for other geometry skipped"), 1) + self.assertNotIn("Fig:Lash1?value", scene.figure.morphs) + def test_on_demand_morph_outside_morphs_dir(self): root = self.root("data/Test/Extra/Bulk.dsf", self.morph_doc( self.mod("Bulk", {"vertex_count": 3, "deltas": {"values": [[2, 0, 0, 1]]}}))) -- cgit v1.2.3