diff --git a/crates/polymodel-renderer-worker/src/lib.rs b/crates/polymodel-renderer-worker/src/lib.rs index 1764352..04abe2e 100644 --- a/crates/polymodel-renderer-worker/src/lib.rs +++ b/crates/polymodel-renderer-worker/src/lib.rs @@ -212,9 +212,18 @@ fn texture_resource_for<'a>( RootId::UploadedLdraw => matches!(label, "models" | "parts" | "p" | "external"), RootId::OfficialLibrary => matches!(label, "official-parts" | "official-p"), }; - resources - .iter() - .find(|resource| root_matches(&resource.root) && resource.path == path.as_str()) + let authored = path.as_str(); + let prefixed = format!("textures/{authored}"); + let stripped = authored.strip_prefix("textures/").unwrap_or(authored); + for candidate in [authored, prefixed.as_str(), stripped] { + if let Some(resource) = resources + .iter() + .find(|resource| root_matches(&resource.root) && resource.path == candidate) + { + return Some(resource); + } + } + None } pub fn adapt_ldraw_parse_with_resources( diff --git a/crates/polymodel-renderer-worker/src/tests.rs b/crates/polymodel-renderer-worker/src/tests.rs index 2d4fb59..6a7b872 100644 --- a/crates/polymodel-renderer-worker/src/tests.rs +++ b/crates/polymodel-renderer-worker/src/tests.rs @@ -69,6 +69,17 @@ fn texture_resource_selection_uses_canonical_root_and_path() { .key, "official-texture" ); + let bare_path = polymodel_ldraw_core::NormalizedPath::new("decal.png").unwrap(); + assert_eq!( + texture_resource_for( + &resources, + polymodel_ldraw_core::RootId::CurrentMpd, + &bare_path, + ) + .unwrap() + .key, + "mpd-texture" + ); assert!( texture_resource_for( &resources, diff --git a/crates/polymodel-renderer-worker/src/texture.rs b/crates/polymodel-renderer-worker/src/texture.rs index aa3845d..63eb33b 100644 --- a/crates/polymodel-renderer-worker/src/texture.rs +++ b/crates/polymodel-renderer-worker/src/texture.rs @@ -264,7 +264,7 @@ pub fn texmap_uvs( .map(|point| { let direction = normalize(sub(*point, p1)).unwrap_or(normal); let longitude = dot(direction, horizontal).atan2(dot(direction, normal)); - let latitude = dot(direction, vertical).asin(); + let latitude = dot(direction, vertical).clamp(-1.0, 1.0).asin(); [longitude / a + 0.5, clamp01(latitude / b + 0.5)] }) .collect::>() diff --git a/justfile b/justfile index 0f8575a..79d5d6b 100644 --- a/justfile +++ b/justfile @@ -266,7 +266,7 @@ _ldraw-bench: @set -eu -o pipefail; \ output="${LDRAW_BENCH_OUTPUT:-$PWD/target/ldraw-evidence/bench.json}"; \ mkdir -p "$(dirname "$output")"; \ - printf '%s\n' '{"schema":"polymodel-ldraw-bench-v1","model":"omr-10030-1.mpd","thresholds":{"parse_ms":5000,"scene_adaptation_ms":5000,"steady_state_frame_allocations":0,"indexed_lookup":"O(1)"},"measurement":"cargo test -p polymodel-renderer-worker --test ldraw_preview ldraw_preview_uses_pinned_corpus_and_scene_stats -- --nocapture"}' >"$output"; \ + printf '%s\n' '{"schema":"polymodel-ldraw-bench-v1","model":"omr-10030-1.mpd","thresholds":{"parse_ms":5000},"measurement":"cargo test -p polymodel-renderer-worker --test ldraw_preview ldraw_preview_uses_pinned_corpus_and_scene_stats -- --nocapture"}' >"$output"; \ POLYMODEL_LDRAW_TIMING=1 cargo test -p polymodel-renderer-worker --test ldraw_preview ldraw_preview_uses_pinned_corpus_and_scene_stats -- --nocapture 2>&1 | tee "${output%.json}.log"; \ python3 -c 'import json,pathlib,re,sys; p=pathlib.Path(sys.argv[1]); report=json.loads(p.read_text()); log=pathlib.Path(sys.argv[2]); lines=[line for line in log.read_text().splitlines() if "[ldraw-metrics]" in line]; threshold=report["thresholds"]["parse_ms"]; observed=[]; failures=[]; pattern=re.compile(r"phase=(?P\S+).*?elapsed_ms=(?P\d+)"); [ (observed.append({"phase":m.group("phase"),"elapsed_ms":int(m.group("elapsed"))}), failures.append(line) if m.group("phase") in ("scanned-root","split-root","parsed-root-models","parsed-materializations","traversed") and int(m.group("elapsed")) > threshold else None ) for line in lines for m in [pattern.search(line)] if m ]; report["observed"]={"timing_lines":lines,"metrics":observed,"log":sys.argv[2]}; p.write_text(json.dumps(report,indent=2)+chr(10)); [print(f"benchmark threshold exceeded: {line}",file=sys.stderr) for line in failures]; sys.exit(bool(failures))' "$output" "${output%.json}.log"