Skip to content

Commit 48a2860

Browse files
authored
Fix hybrid file parsing (#33)
Fix parsing hybrid files containing both drawing commands and sub-file references. Stop trying to guess based on sub-file extension. Fixes #32
1 parent 01c1359 commit 48a2860

File tree

5 files changed

+53
-47
lines changed

5 files changed

+53
-47
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
rust:
2020
- stable
2121
- beta
22-
- 1.58.1
22+
- 1.61.0
2323

2424
steps:
2525
- name: Checkout

README.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![License: MIT or Apache 2.0](https://img.shields.io/badge/License-MIT%20or%20Apache2-blue.svg)](https://github.com/djeedai/weldr#license)
44
[![CI](https://github.com/djeedai/weldr/workflows/CI/badge.svg?branch=main)](https://github.com/djeedai/weldr/actions?query=workflow%3ACI)
55
[![Coverage Status](https://coveralls.io/repos/github/djeedai/weldr/badge.svg?branch=main)](https://coveralls.io/github/djeedai/weldr?branch=main)
6-
[![Minimum rustc version](https://img.shields.io/badge/rustc-1.56.0+-lightgray.svg)](#rust-version-requirements)
6+
![Minimum rustc version](https://img.shields.io/badge/rustc-1.61.0+-lightgray.svg)
77

88
weldr is a Rust library and command-line tool to manipulate [LDraw](https://www.ldraw.org/) files ([format specification](https://www.ldraw.org/article/218.html)), which are files describing 3D models of [LEGO®](http://www.lego.com)* pieces.
99

@@ -21,8 +21,6 @@ The weldr library allows building command-line tools and applications leveraging
2121
Parse the content of a single LDraw file containing 2 commands:
2222

2323
```rust
24-
extern crate weldr;
25-
2624
use weldr::{parse_raw, CommandType, CommentCmd, LineCmd, Vec3};
2725

2826
fn main() {}

bin/weldr/src/convert.rs

+32-35
Original file line numberDiff line numberDiff line change
@@ -124,41 +124,38 @@ impl ConvertCommand {
124124
};
125125
gltf.nodes.push(node);
126126

127-
// TODO: Check the part type rather than the extension.
128-
if filename.ends_with(".dat") {
129-
// Create geometry if the node is a part.
130-
let mesh_index = mesh_cache.entry(filename.into()).or_insert_with(|| {
131-
let mesh_index = gltf.meshes.len() as u32;
132-
let geometry = self.create_geometry(source_file, source_map);
133-
// Don't set empty meshes to avoid import errors.
134-
if !geometry.vertices.is_empty() && !geometry.triangle_indices.is_empty() {
135-
self.add_mesh(&geometry, gltf, buffer);
136-
Some(mesh_index)
137-
} else {
138-
None
139-
}
140-
});
141-
142-
gltf.nodes[node_index].mesh_index = *mesh_index;
143-
} else {
144-
for cmd in &source_file.cmds {
145-
if let Command::SubFileRef(sfr_cmd) = cmd {
146-
if let Some(subfile) = source_map.get(&sfr_cmd.file) {
147-
// Don't apply node transforms to preserve the scene hierarchy.
148-
// Applications should handle combining the transforms.
149-
let transform = sfr_cmd.matrix();
150-
151-
let child_node_index = self.add_nodes(
152-
&sfr_cmd.file,
153-
subfile,
154-
Some(transform),
155-
source_map,
156-
gltf,
157-
buffer,
158-
mesh_cache,
159-
);
160-
gltf.nodes[node_index].children.push(child_node_index);
161-
}
127+
// Create geometry if any for this node
128+
let opt_mesh_index = mesh_cache.entry(filename.into()).or_insert_with(|| {
129+
let mesh_index = gltf.meshes.len() as u32;
130+
let geometry = self.create_geometry(source_file, source_map);
131+
// Don't set empty meshes to avoid import errors.
132+
if !geometry.vertices.is_empty() && !geometry.triangle_indices.is_empty() {
133+
self.add_mesh(&geometry, gltf, buffer);
134+
Some(mesh_index)
135+
} else {
136+
None
137+
}
138+
});
139+
gltf.nodes[node_index].mesh_index = *opt_mesh_index;
140+
141+
// Recursively parse sub-files
142+
for cmd in &source_file.cmds {
143+
if let Command::SubFileRef(sfr_cmd) = cmd {
144+
if let Some(subfile) = source_map.get(&sfr_cmd.file) {
145+
// Don't apply node transforms to preserve the scene hierarchy.
146+
// Applications should handle combining the transforms.
147+
let transform = sfr_cmd.matrix();
148+
149+
let child_node_index = self.add_nodes(
150+
&sfr_cmd.file,
151+
subfile,
152+
Some(transform),
153+
source_map,
154+
gltf,
155+
buffer,
156+
mesh_cache,
157+
);
158+
gltf.nodes[node_index].children.push(child_node_index);
162159
}
163160
}
164161
}

bin/weldr/src/weldr.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -305,13 +305,15 @@ impl GeometryCache {
305305
}
306306

307307
fn add_line(&mut self, draw_ctx: &DrawContext, vertices: &[Vec3; 2]) {
308+
trace!("LINE: {:?}", vertices);
308309
let i0 = self.insert_vertex(&vertices[0], &draw_ctx.transform);
309310
let i1 = self.insert_vertex(&vertices[1], &draw_ctx.transform);
310311
self.line_indices.push(i0);
311312
self.line_indices.push(i1);
312313
}
313314

314315
fn add_triangle(&mut self, draw_ctx: &DrawContext, vertices: &[Vec3; 3]) {
316+
trace!("TRI: {:?}", vertices);
315317
let i0 = self.insert_vertex(&vertices[0], &draw_ctx.transform);
316318
let i1 = self.insert_vertex(&vertices[1], &draw_ctx.transform);
317319
let i2 = self.insert_vertex(&vertices[2], &draw_ctx.transform);
@@ -321,8 +323,17 @@ impl GeometryCache {
321323
}
322324

323325
fn add_quad(&mut self, draw_ctx: &DrawContext, vertices: &[Vec3; 4]) {
324-
self.add_triangle(draw_ctx, &[vertices[0], vertices[1], vertices[2]]);
325-
self.add_triangle(draw_ctx, &[vertices[0], vertices[2], vertices[3]]);
326+
trace!("QUAD: {:?}", vertices);
327+
let i0 = self.insert_vertex(&vertices[0], &draw_ctx.transform);
328+
let i1 = self.insert_vertex(&vertices[1], &draw_ctx.transform);
329+
let i2 = self.insert_vertex(&vertices[2], &draw_ctx.transform);
330+
let i3 = self.insert_vertex(&vertices[3], &draw_ctx.transform);
331+
self.triangle_indices.push(i0);
332+
self.triangle_indices.push(i2);
333+
self.triangle_indices.push(i1);
334+
self.triangle_indices.push(i0);
335+
self.triangle_indices.push(i3);
336+
self.triangle_indices.push(i2);
326337
}
327338
}
328339

lib/tests/parse.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
extern crate weldr;
2-
31
use weldr::{error::ResolveError, Command, FileRefResolver, SourceFile, SourceMap, SubFileRefCmd};
42

53
use std::collections::HashMap;
@@ -67,7 +65,7 @@ fn test_memory_resolver() {
6765
#[test]
6866
fn parse_recursive() {
6967
let mut memory_resolver = MemoryResolver::new();
70-
memory_resolver.add("root.ldr", b"1 16 0 0 0 1 0 0 0 1 0 0 0 1 a.ldr\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 b.ldr\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 a.ldr");
68+
memory_resolver.add("root.ldr", b"1 16 0 0 0 1 0 0 0 1 0 0 0 1 a.ldr\n4 16 0 0 0 1 1 1 2 2 2 3 3 3\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 b.ldr\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 a.ldr");
7169
memory_resolver.add("a.ldr", b"4 16 1 1 0 0.9239 1 0.3827 0.9239 0 0.3827 1 0 0");
7270
memory_resolver.add(
7371
"b.ldr",
@@ -76,16 +74,18 @@ fn parse_recursive() {
7674
let mut source_map = weldr::SourceMap::new();
7775
let root_file_name = weldr::parse("root.ldr", &memory_resolver, &mut source_map).unwrap();
7876
let root_file = source_map.get(&root_file_name).unwrap();
79-
assert_eq!(3, root_file.cmds.len());
77+
assert_eq!(4, root_file.cmds.len());
78+
// Regression #32: top-level drawing commands work with sub-file references
79+
assert!(matches!(root_file.cmds[1], Command::Quad(_)));
8080

8181
let file0 = get_resolved_subfile_ref(&root_file.cmds[0]).unwrap();
8282
assert_eq!(file0.file, "a.ldr");
8383
assert_eq!(1, source_map.get(&file0.file).unwrap().cmds.len());
8484

85-
let file1 = get_resolved_subfile_ref(&root_file.cmds[1]).unwrap();
85+
let file1 = get_resolved_subfile_ref(&root_file.cmds[2]).unwrap();
8686
assert_eq!(2, source_map.get(&file1.file).unwrap().cmds.len());
8787

88-
let file2 = get_resolved_subfile_ref(&root_file.cmds[2]).unwrap();
88+
let file2 = get_resolved_subfile_ref(&root_file.cmds[3]).unwrap();
8989
assert_eq!(1, source_map.get(&file2.file).unwrap().cmds.len());
9090
assert_eq!(file0, file2);
9191

0 commit comments

Comments
 (0)