1mod error;
6
7use std::{io, path::Path, str};
8
9use self::error::ErrorKind;
10use crate::{
11 utils::{
12 bytes::{memchr_naive_table, starts_with},
13 float,
14 },
15 Color4, Material, Mesh, Scene, Vec3,
16};
17
18#[inline]
20pub fn from_slice(bytes: &[u8]) -> io::Result<Scene> {
21 from_slice_internal(bytes, None, false)
22}
23
24pub(crate) fn from_slice_internal(
25 bytes: &[u8],
26 path: Option<&Path>,
27 parse_color: bool,
28) -> io::Result<Scene> {
29 let mut meshes = Vec::with_capacity(1);
30 if is_ascii_stl(bytes) {
31 match read_ascii_stl(bytes, &mut meshes) {
32 Ok(()) => {
33 let materials = (0..meshes.len()).map(|_| Material::default()).collect();
34 return Ok(Scene { materials, meshes });
35 }
36 Err(
39 ErrorKind::NotAscii("solid", _)
40 | ErrorKind::ExpectedSpace("solid", _)
41 | ErrorKind::ExpectedNewline("solid", _)
42 | ErrorKind::Expected("facet", _),
43 ) if meshes.is_empty() => {}
44 Err(e) => return Err(e.into_io_error(bytes, path)),
45 }
46 }
47 match read_binary_header(bytes, parse_color) {
48 Ok(header) => {
49 let mesh = read_binary_triangles(&header);
50 let mut material = Material::default();
51 if header.reverse_color && mesh.colors[0].is_empty() {
52 let color = header.default_color;
53 material.color.diffuse = Some(color);
54 material.color.specular = Some(color);
55 }
56 meshes.push(mesh);
57 Ok(Scene {
58 materials: vec![material],
59 meshes,
60 })
61 }
62 Err(e) => Err(e.into_io_error(bytes, path)),
63 }
64}
65
66fn is_ascii_stl(mut bytes: &[u8]) -> bool {
70 let is_ascii = skip_spaces_and_lines_until_token(&mut bytes, b"solid");
74
75 if is_ascii {
76 }
84 is_ascii
85}
86
87const HEADER_SIZE: usize = 80;
105const TRIANGLE_COUNT_SIZE: usize = 4;
106const TRIANGLE_START: usize = HEADER_SIZE + TRIANGLE_COUNT_SIZE;
107const TRIANGLE_SIZE: usize = 50;
108
109struct BinaryHeader<'a> {
110 default_color: Color4,
111 parse_color: bool,
112 reverse_color: bool,
113 triangle_bytes: &'a [u8],
114}
115
116fn read_binary_header(bytes: &[u8], parse_color: bool) -> Result<BinaryHeader<'_>, ErrorKind> {
117 if bytes.len() < TRIANGLE_START {
118 return Err(ErrorKind::TooSmall);
119 }
120
121 let header = &bytes[..HEADER_SIZE];
122 let triangle_bytes = &bytes[TRIANGLE_START..];
123
124 let extra_bytes = triangle_bytes.len() % TRIANGLE_SIZE;
125 if extra_bytes != 0 {
126 if extra_bytes == 1 && triangle_bytes.ends_with(b"\n")
127 || extra_bytes == 2 && triangle_bytes.ends_with(b"\r\n")
128 {
129 } else {
131 return Err(ErrorKind::InvalidSize);
132 }
133 }
134
135 let num_triangles = triangle_bytes.len() / TRIANGLE_SIZE;
141 let num_vertices = num_triangles * 3;
142 if u32::try_from(num_vertices).is_err() {
143 return Err(ErrorKind::TooManyTriangles);
145 }
146
147 let mut default_color = [0.6, 0.6, 0.6, 0.6];
149 let mut reverse_color = false;
150 if parse_color {
151 let mut s = header;
154 let expect = b"COLOR=";
155 while s.len() >= expect.len() + 4 {
156 if token(&mut s, expect) {
157 const INV_BYTE: f32 = 1. / 255.;
158 reverse_color = true;
159 default_color = [
160 s[0] as f32 * INV_BYTE,
161 s[1] as f32 * INV_BYTE,
162 s[2] as f32 * INV_BYTE,
163 s[3] as f32 * INV_BYTE,
164 ];
165 break;
166 }
167 s = &s[1..];
168 }
169 }
170
171 Ok(BinaryHeader {
172 default_color,
173 parse_color,
174 reverse_color,
175 triangle_bytes,
176 })
177}
178
179fn read_binary_triangles(header: &BinaryHeader<'_>) -> Mesh {
180 let bytes = header.triangle_bytes;
181
182 let chunks = bytes.chunks_exact(TRIANGLE_SIZE);
183 let num_triangles = chunks.len();
184 let num_vertices = num_triangles * 3;
185 let mut mesh = Mesh {
194 vertices: vec![[0., 0., 0.]; num_vertices],
195 normals: vec![[0., 0., 0.]; num_vertices],
196 faces: vec![[0, 0, 0]; num_triangles],
197 ..Default::default()
198 };
199
200 let mut vertices_len = 0;
201 let has_color_mask = if header.parse_color { 1 << 15 } else { 0 };
202
203 for (((chunk, vertices), normals), face) in chunks
204 .zip(mesh.vertices.chunks_exact_mut(3))
205 .zip(mesh.normals.chunks_exact_mut(3))
206 .zip(&mut mesh.faces)
207 {
208 let triangle = read_binary_triangle(chunk);
209
210 vertices.clone_from_slice(&triangle.vertices);
211 normals.clone_from_slice(&[triangle.normal; 3]);
212 *face = [vertices_len, vertices_len + 1, vertices_len + 2];
213
214 if triangle.color & has_color_mask != 0 {
217 const INV_VAL: f32 = 1. / 31.;
218 if mesh.colors[0].is_empty() {
219 mesh.colors[0] = vec![header.default_color; num_vertices];
220 }
221 let a = 1.;
222 let color = if header.reverse_color {
223 let r = (triangle.color & 0x1F) as f32 * INV_VAL;
224 let g = ((triangle.color & (0x1F << 5)) >> 5) as f32 * INV_VAL;
225 let b = ((triangle.color & (0x1F << 10)) >> 10) as f32 * INV_VAL;
226 [r, g, b, a]
227 } else {
228 let b = (triangle.color & 0x1F) as f32 * INV_VAL;
229 let g = ((triangle.color & (0x1F << 5)) >> 5) as f32 * INV_VAL;
230 let r = ((triangle.color & (0x1F << 10)) >> 10) as f32 * INV_VAL;
231 [r, g, b, a]
232 };
233 mesh.colors[0][vertices_len as usize..vertices_len as usize + 3]
234 .copy_from_slice(&[color, color, color]);
235 }
236
237 vertices_len += 3;
238 }
239
240 mesh
241}
242
243#[inline]
244fn read_binary_triangle(mut buf: &[u8]) -> Triangle {
245 #[inline]
246 fn f32le(buf: &mut &[u8]) -> f32 {
247 let f = f32::from_le_bytes(buf[..4].try_into().unwrap());
248 *buf = &buf[4..];
249 f
250 }
251
252 let normal = [f32le(&mut buf), f32le(&mut buf), f32le(&mut buf)];
253 let vertex1 = [f32le(&mut buf), f32le(&mut buf), f32le(&mut buf)];
254 let vertex2 = [f32le(&mut buf), f32le(&mut buf), f32le(&mut buf)];
255 let vertex3 = [f32le(&mut buf), f32le(&mut buf), f32le(&mut buf)];
256 let color = u16::from_le_bytes(buf[..2].try_into().unwrap());
257 Triangle {
258 normal,
259 vertices: [vertex1, vertex2, vertex3],
260 color,
261 }
262}
263
264fn read_ascii_stl(mut s: &[u8], meshes: &mut Vec<Mesh>) -> Result<(), ErrorKind> {
283 loop {
284 let mut mesh = Mesh::default();
285
286 let expected = "solid";
288 if !skip_spaces_and_lines_until_token(&mut s, expected.as_bytes()) {
289 if s.is_empty() {
290 if meshes.is_empty() {
292 return Err(ErrorKind::Expected(expected, s.len()));
293 }
294 break;
295 }
296 return Err(ErrorKind::Expected(expected, s.len()));
297 }
298 if !skip_spaces(&mut s) {
299 return Err(ErrorKind::ExpectedSpace(expected, s.len()));
300 }
301 match memchr_naive_table(LINE, &TABLE, s) {
302 Some(n) => {
303 let mut name = &s[..n];
304 if !name.is_ascii() {
309 return Err(ErrorKind::NotAscii(expected, s.len()));
310 }
311 if let Some(n) = memchr_naive_table(SPACE, &TABLE, name) {
312 name = &name[..n];
317 }
318 let name = str::from_utf8(name).unwrap();
319 Mesh::set_name(&mut mesh, name);
320 s = &s[n + 1..];
321 }
322 None => return Err(ErrorKind::ExpectedNewline(expected, s.len())),
323 }
324
325 loop {
326 let expected = "facet";
330 if !skip_spaces_and_lines_until_token(&mut s, expected.as_bytes()) {
331 break;
332 }
333 if !skip_spaces(&mut s) {
334 return Err(ErrorKind::ExpectedSpace(expected, s.len()));
335 }
336 let expected = "normal";
337 if !token(&mut s, expected.as_bytes()) {
338 return Err(ErrorKind::Expected(expected, s.len()));
339 }
340 let mut normal = [0.; 3];
341 for normal in &mut normal {
342 if !skip_spaces(&mut s) {
343 return Err(ErrorKind::ExpectedSpace(expected, s.len()));
344 }
345 match float::parse_partial::<f32>(s) {
346 Some((f, n)) => {
347 *normal = f;
348 s = &s[n..];
349 }
350 None => return Err(ErrorKind::Float(s.len())),
351 }
352 }
353 if !skip_spaces_until_line(&mut s) {
354 return Err(ErrorKind::ExpectedNewline(expected, s.len()));
355 }
356
357 let expected = "outer";
361 if !skip_spaces_and_lines_until_token(&mut s, expected.as_bytes()) {
362 return Err(ErrorKind::Expected(expected, s.len()));
363 }
364 if !skip_spaces(&mut s) {
365 return Err(ErrorKind::ExpectedSpace(expected, s.len()));
366 }
367 let expected = "loop";
368 if !token(&mut s, expected.as_bytes()) {
369 return Err(ErrorKind::Expected(expected, s.len()));
370 }
371 if !skip_spaces_until_line(&mut s) {
372 return Err(ErrorKind::ExpectedNewline(expected, s.len()));
373 }
374
375 let expected = "vertex";
379 let mut vertices = [[0.; 3]; 3];
380 for vertex in &mut vertices {
381 if !skip_spaces_and_lines_until_token(&mut s, expected.as_bytes()) {
382 return Err(ErrorKind::Expected(expected, s.len()));
383 }
384 for vertex in vertex {
385 if !skip_spaces(&mut s) {
386 return Err(ErrorKind::ExpectedSpace(expected, s.len()));
387 }
388 match float::parse_partial::<f32>(s) {
389 Some((f, n)) => {
390 *vertex = f;
391 s = &s[n..];
392 }
393 None => return Err(ErrorKind::Float(s.len())),
394 }
395 }
396 if !skip_spaces_until_line(&mut s) {
397 return Err(ErrorKind::ExpectedNewline(expected, s.len()));
398 }
399 }
400
401 let expected = "endloop";
403 if !skip_spaces_and_lines_until_token(&mut s, expected.as_bytes()) {
404 return Err(ErrorKind::Expected(expected, s.len()));
405 }
406 if !skip_spaces_until_line(&mut s) {
407 return Err(ErrorKind::ExpectedNewline(expected, s.len()));
408 }
409
410 let expected = "endfacet";
412 if !skip_spaces_and_lines_until_token(&mut s, expected.as_bytes()) {
413 return Err(ErrorKind::Expected(expected, s.len()));
414 }
415 if !skip_spaces_until_line(&mut s) {
416 return Err(ErrorKind::ExpectedNewline(expected, s.len()));
417 }
418
419 Mesh::push_triangle(
420 &mut mesh,
421 Triangle {
422 normal,
423 vertices,
424 color: 0,
425 },
426 );
427 }
428
429 let expected = "endsolid";
431 if !token(&mut s, expected.as_bytes()) {
432 return Err(ErrorKind::Expected(expected, s.len()));
433 }
434 match memchr_naive_table(LINE, &TABLE, s) {
437 Some(n) => {
438 if !s[..n].is_ascii() {
439 return Err(ErrorKind::NotAscii(expected, s.len())); }
441 s = &s[n + 1..];
442 }
443 None => {
444 if !s.is_ascii() {
445 return Err(ErrorKind::NotAscii(expected, s.len())); }
447 s = &[];
448 }
449 }
450
451 meshes.push(mesh);
452 }
453
454 Ok(())
455}
456
457const WHITESPACE: u8 = SPACE | LINE;
465const LINE: u8 = 1 << 0;
467const SPACE: u8 = 1 << 1;
469const S_: u8 = 1 << 2;
471const E_: u8 = 1 << 3;
473const F_: u8 = 1 << 4;
475const O_: u8 = 1 << 5;
477const V_: u8 = 1 << 6;
479
480static TABLE: [u8; 256] = {
481 const __: u8 = 0;
482 const LN: u8 = LINE;
483 const NL: u8 = SPACE;
484 [
485 __, __, __, __, __, __, __, __, __, NL, LN, __, __, LN, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, NL, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, E_, F_, __, __, __, __, __, __, __, __, O_, __, __, __, S_, __, __, V_, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, ]
503};
504#[test]
505fn table() {
506 for b in u8::MIN..=u8::MAX {
507 match b {
508 b' ' | b'\t' => {
509 assert_eq!(TABLE[b as usize], SPACE, "{:?}({b:#X})", b as char);
510 }
511 b'\n' | b'\r' => {
512 assert_eq!(TABLE[b as usize], LINE, "{:?}({b:#X})", b as char);
513 }
514 b's' => {
515 assert_eq!(TABLE[b as usize], S_, "{:?}({b:#X})", b as char);
516 }
517 b'e' => {
518 assert_eq!(TABLE[b as usize], E_, "{:?}({b:#X})", b as char);
519 }
520 b'f' => {
521 assert_eq!(TABLE[b as usize], F_, "{:?}({b:#X})", b as char);
522 }
523 b'o' => {
524 assert_eq!(TABLE[b as usize], O_, "{:?}({b:#X})", b as char);
525 }
526 b'v' => {
527 assert_eq!(TABLE[b as usize], V_, "{:?}({b:#X})", b as char);
528 }
529 _ => assert_eq!(TABLE[b as usize], 0, "{:?}({b:#X})", b as char),
530 }
531 }
532}
533
534#[inline]
535fn skip_whitespace_until_byte(s: &mut &[u8], byte_mask: u8, whitespace_mask: u8) -> bool {
536 while let Some((&b, s_next)) = s.split_first() {
537 let b = TABLE[b as usize];
538 if b & byte_mask != 0 {
539 *s = s_next;
540 return true;
541 }
542 if b & whitespace_mask != 0 {
543 *s = s_next;
544 continue;
545 }
546 break;
547 }
548 false
549}
550
551#[inline]
552fn skip_spaces_until_line(s: &mut &[u8]) -> bool {
553 skip_whitespace_until_byte(s, LINE, SPACE)
554}
555
556#[inline]
557fn skip_spaces(s: &mut &[u8]) -> bool {
558 let start = *s;
559 while let Some((&b, s_next)) = s.split_first() {
560 let b = TABLE[b as usize];
561 if b & SPACE != 0 {
562 *s = s_next;
563 continue;
564 }
565 break;
566 }
567 start.len() != s.len()
568}
569
570#[inline]
571fn token(s: &mut &[u8], token: &'static [u8]) -> bool {
572 if starts_with(s, token) {
573 *s = &s[token.len()..];
574 true
575 } else {
576 false
577 }
578}
579
580#[inline(always)] fn skip_spaces_and_lines_until_token(s: &mut &[u8], token: &'static [u8]) -> bool {
582 let token_start_mask = TABLE[token[0] as usize];
583 debug_assert_ne!(token_start_mask, 0);
584 let check_start = match token.len() {
585 4 | 8 | 12 | 16 => 0,
586 _ => 1,
587 };
588 while let Some((&b, s_next)) = s.split_first() {
589 let b = TABLE[b as usize];
590 if b & token_start_mask != 0 {
591 if starts_with(&s[check_start..], &token[check_start..]) {
592 *s = &s[token.len()..];
593 return true;
594 }
595 break;
596 }
597 if b & WHITESPACE != 0 {
598 *s = s_next;
599 continue;
600 }
601 break;
602 }
603 false
604}
605
606struct Triangle {
607 normal: Vec3,
608 vertices: [Vec3; 3],
609 color: u16,
610}
611
612trait FromStl: Sized {
613 type Context;
614
615 fn push_triangle(cx: &mut Self::Context, triangle: Triangle);
617
618 fn set_name(cx: &mut Self::Context, name: &str);
620}
621
622impl FromStl for Mesh {
623 type Context = Self;
624
625 #[inline]
626 fn push_triangle(mesh: &mut Self::Context, triangle: Triangle) {
627 #[allow(clippy::cast_possible_truncation)]
632 let vertices_indices = [
633 mesh.vertices.len() as u32,
634 (mesh.vertices.len() + 1) as u32,
635 (mesh.vertices.len() + 2) as u32,
636 ];
637
638 mesh.vertices.extend_from_slice(&triangle.vertices);
639 mesh.normals.resize(mesh.normals.len() + 3, triangle.normal);
640 mesh.faces.push(vertices_indices);
641 }
642
643 fn set_name(mesh: &mut Self::Context, name: &str) {
644 mesh.name = name.to_owned();
645 }
646}