diff --git a/crates/polymodel-renderer-worker/tests/ldraw_preview.rs b/crates/polymodel-renderer-worker/tests/ldraw_preview.rs index 24a4446..fa79e5b 100644 --- a/crates/polymodel-renderer-worker/tests/ldraw_preview.rs +++ b/crates/polymodel-renderer-worker/tests/ldraw_preview.rs @@ -6,14 +6,56 @@ use std::process::Command; use std::time::{SystemTime, UNIX_EPOCH}; use polymodel_ldraw_core::{ - AdapterRequest, CancellationPolicy, InProcessRustAdapter, Materialization, NormalizedPath, - ParserProfile, RootId, + AdapterRequest, CacheKey, CancellationPolicy, GeometryRecord, InProcessRustAdapter, + Materialization, NoopSemanticSink, NormalizedPath, ParserProfile, RootId, SemanticEvent, + SemanticSink, }; use polymodel_renderer_worker::{ LdrawLightingMaterialPolicy, official_materializations, parse_and_adapt_ldraw, preview_limits, scene_instance_batches, scene_mesh_topology, }; +#[derive(Default)] +struct GeometryCollector { + geometry: std::collections::HashMap>, +} + +impl SemanticSink for GeometryCollector { + fn on_event( + &mut self, + event: &SemanticEvent<'_>, + _context: &polymodel_ldraw_core::TraversalContext, + ) { + if let SemanticEvent::GeometryEmitted { + source, + line_type, + colour, + vertices, + bfc, + texmap, + inverted, + primitive_id, + span, + } = event + { + self.geometry + .entry(source.clone()) + .or_default() + .push(GeometryRecord { + primitive_id: *primitive_id, + source: source.clone(), + span: *span, + line_type: *line_type, + colour: *colour, + vertices: vertices.to_vec(), + bfc: *bfc, + texmap: texmap.cloned(), + inverted: *inverted, + }); + } + } +} + const OMR: &str = "crates/polymodel-ldraw-testkit/corpus/omr-10030-1.mpd"; const PLATE_2_X_3: &str = "parts/3021.dat"; @@ -40,7 +82,8 @@ fn isolated_plate() -> IsolatedPlate { ); let plate_key = plate.key(); materializations.insert(0, plate); - let result = InProcessRustAdapter::parse_with_limits( + let mut sink = GeometryCollector::default(); + let result = InProcessRustAdapter::parse_with_limits_and_sink( AdapterRequest { bytes: &bytes, profile: ParserProfile::Compatibility, @@ -52,6 +95,7 @@ fn isolated_plate() -> IsolatedPlate { cancellation: CancellationPolicy::default(), }, preview_limits(), + &mut sink, ) .expect("official 3021.dat must parse with its real closure"); let model = result @@ -59,7 +103,7 @@ fn isolated_plate() -> IsolatedPlate { .iter() .find(|model| model.cache_key == plate_key) .expect("3021 CacheKey must own a parsed model"); - let body = result + let body = sink .geometry .get(&model.cache_key) .into_iter() @@ -215,7 +259,8 @@ fn assert_official_subpart_identity(part: &str, authored_target: &str, physical_ Some("official-ldraw-library".into()), ), ); - let result = InProcessRustAdapter::parse_with_limits( + let mut noop = NoopSemanticSink; + let result = InProcessRustAdapter::parse_with_limits_and_sink( AdapterRequest { bytes: &bytes, profile: ParserProfile::Compatibility, @@ -227,6 +272,7 @@ fn assert_official_subpart_identity(part: &str, authored_target: &str, physical_ cancellation: CancellationPolicy::default(), }, preview_limits(), + &mut noop, ) .expect("official parent must parse with its exact closure"); let parsed_child = result @@ -377,16 +423,21 @@ fn official_materializations_seed_ldconfig_colour_table() { ); let root_key = root_materialization.key(); materializations.insert(0, root_materialization); - let parsed = InProcessRustAdapter::parse(AdapterRequest { - bytes: root_bytes, - profile: ParserProfile::Compatibility, - provenance_id: "official-ldconfig-root", - root_name: path.as_str(), - root: RootId::OfficialLibrary, - materializations: &materializations, - target_selections: &closure.target_selections, - cancellation: CancellationPolicy::default(), - }) + let mut noop = NoopSemanticSink; + let parsed = InProcessRustAdapter::parse_with_limits_and_sink( + AdapterRequest { + bytes: root_bytes, + profile: ParserProfile::Compatibility, + provenance_id: "official-ldconfig-root", + root_name: path.as_str(), + root: RootId::OfficialLibrary, + materializations: &materializations, + target_selections: &closure.target_selections, + cancellation: CancellationPolicy::default(), + }, + preview_limits(), + &mut noop, + ) .expect("model should parse with seeded LDConfig"); parsed .models @@ -510,7 +561,8 @@ fn pinned_scene() -> polymodel_renderer_protocol::scene::Scene { ); materializations.insert(0, materialization); eprintln!("[ldraw-preview-test] parsing pinned OMR"); - let result = InProcessRustAdapter::parse_with_limits( + let mut noop = NoopSemanticSink; + let result = InProcessRustAdapter::parse_with_limits_and_sink( AdapterRequest { bytes: &bytes, profile: ParserProfile::Compatibility, @@ -522,6 +574,7 @@ fn pinned_scene() -> polymodel_renderer_protocol::scene::Scene { cancellation: CancellationPolicy::default(), }, preview_limits(), + &mut noop, ) .expect("pinned OMR must parse"); eprintln!("[ldraw-preview-test] parse complete");