// pathfinder/partitioner/src/mesh_library.rs // // Copyright © 2017 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use bincode::{self, Infinite}; use byteorder::{LittleEndian, WriteBytesExt}; use euclid::Point2D; use serde::Serialize; use std::io::{self, ErrorKind, Seek, SeekFrom, Write}; use std::ops::Range; use {BQuad, BVertexLoopBlinnData, CurveIndices, LineIndices}; #[derive(Debug, Clone)] pub struct MeshLibrary { pub b_quads: Vec, pub b_vertex_positions: Vec>, pub b_vertex_path_ids: Vec, pub b_vertex_loop_blinn_data: Vec, pub cover_indices: MeshLibraryCoverIndices, pub edge_indices: MeshLibraryEdgeIndices, } impl MeshLibrary { #[inline] pub fn new() -> MeshLibrary { MeshLibrary { b_quads: vec![], b_vertex_positions: vec![], b_vertex_path_ids: vec![], b_vertex_loop_blinn_data: vec![], cover_indices: MeshLibraryCoverIndices::new(), edge_indices: MeshLibraryEdgeIndices::new(), } } pub fn clear(&mut self) { self.b_quads.clear(); self.b_vertex_positions.clear(); self.b_vertex_path_ids.clear(); self.b_vertex_loop_blinn_data.clear(); self.cover_indices.clear(); self.edge_indices.clear(); } /// Reverses interior indices so that they draw front-to-back. /// /// This enables early Z optimizations. pub fn optimize(&mut self) { let mut new_cover_interior_indices = Vec::with_capacity(self.cover_indices.interior_indices.len()); let mut last_cover_interior_index_index = self.cover_indices.interior_indices.len(); while last_cover_interior_index_index != 0 { let mut first_cover_interior_index_index = last_cover_interior_index_index - 1; let path_id = self.b_vertex_path_ids[self.cover_indices .interior_indices[first_cover_interior_index_index] as usize]; while first_cover_interior_index_index != 0 { let prev_path_id = self.b_vertex_path_ids[ self.cover_indices.interior_indices[first_cover_interior_index_index - 1] as usize]; if prev_path_id != path_id { break } first_cover_interior_index_index -= 1 } let range = first_cover_interior_index_index..last_cover_interior_index_index; new_cover_interior_indices.extend_from_slice(&self.cover_indices .interior_indices[range]); last_cover_interior_index_index = first_cover_interior_index_index; } self.cover_indices.interior_indices = new_cover_interior_indices } /// Writes this mesh library to a RIFF file. /// /// RIFF is a dead-simple extensible binary format documented here: /// https://msdn.microsoft.com/en-us/library/windows/desktop/ee415713(v=vs.85).aspx pub fn serialize_into(&self, writer: &mut W) -> io::Result<()> where W: Write + Seek { // `PFML` for "Pathfinder Mesh Library". try!(writer.write_all(b"RIFF\0\0\0\0PFML")); // NB: The RIFF spec requires that all chunks be padded to an even byte offset. However, // for us, this is guaranteed by construction because each instance of all of the data that // we're writing has a byte size that is a multiple of 4. So we don't bother with doing it // explicitly here. try!(write_chunk(writer, b"bqua", &self.b_quads)); try!(write_chunk(writer, b"bvpo", &self.b_vertex_positions)); try!(write_chunk(writer, b"bvpi", &self.b_vertex_path_ids)); try!(write_chunk(writer, b"bvlb", &self.b_vertex_loop_blinn_data)); try!(write_chunk(writer, b"cvii", &self.cover_indices.interior_indices)); try!(write_chunk(writer, b"cvci", &self.cover_indices.curve_indices)); try!(write_chunk(writer, b"euli", &self.edge_indices.upper_line_indices)); try!(write_chunk(writer, b"euci", &self.edge_indices.upper_curve_indices)); try!(write_chunk(writer, b"elli", &self.edge_indices.lower_line_indices)); try!(write_chunk(writer, b"elci", &self.edge_indices.lower_curve_indices)); let total_length = try!(writer.seek(SeekFrom::Current(0))); try!(writer.seek(SeekFrom::Start(4))); try!(writer.write_u32::((total_length - 8) as u32)); return Ok(()); fn write_chunk(writer: &mut W, tag: &[u8; 4], data: &[T]) -> io::Result<()> where W: Write + Seek, T: Serialize { try!(writer.write_all(tag)); try!(writer.write_all(b"\0\0\0\0")); let start_position = try!(writer.seek(SeekFrom::Current(0))); for datum in data { try!(bincode::serialize_into(writer, datum, Infinite).map_err(|_| { io::Error::from(ErrorKind::Other) })); } let end_position = try!(writer.seek(SeekFrom::Current(0))); try!(writer.seek(SeekFrom::Start(start_position - 4))); try!(writer.write_u32::((end_position - start_position) as u32)); try!(writer.seek(SeekFrom::Start(end_position))); Ok(()) } } pub(crate) fn snapshot_lengths(&self) -> MeshLibraryLengths { MeshLibraryLengths { b_quads: self.b_quads.len(), b_vertices: self.b_vertex_positions.len(), cover_interior_indices: self.cover_indices.interior_indices.len(), cover_curve_indices: self.cover_indices.curve_indices.len(), edge_upper_line_indices: self.edge_indices.upper_line_indices.len(), edge_upper_curve_indices: self.edge_indices.upper_curve_indices.len(), edge_lower_line_indices: self.edge_indices.lower_line_indices.len(), edge_lower_curve_indices: self.edge_indices.lower_curve_indices.len(), } } } #[derive(Debug, Clone)] pub struct MeshLibraryCoverIndices { pub interior_indices: Vec, pub curve_indices: Vec, } impl MeshLibraryCoverIndices { #[inline] fn new() -> MeshLibraryCoverIndices { MeshLibraryCoverIndices { interior_indices: vec![], curve_indices: vec![], } } fn clear(&mut self) { self.interior_indices.clear(); self.curve_indices.clear(); } } #[derive(Debug, Clone)] pub struct MeshLibraryEdgeIndices { pub upper_line_indices: Vec, pub upper_curve_indices: Vec, pub lower_line_indices: Vec, pub lower_curve_indices: Vec, } impl MeshLibraryEdgeIndices { #[inline] fn new() -> MeshLibraryEdgeIndices { MeshLibraryEdgeIndices { upper_line_indices: vec![], upper_curve_indices: vec![], lower_line_indices: vec![], lower_curve_indices: vec![], } } fn clear(&mut self) { self.upper_line_indices.clear(); self.upper_curve_indices.clear(); self.lower_line_indices.clear(); self.lower_curve_indices.clear(); } } pub(crate) struct MeshLibraryLengths { b_quads: usize, b_vertices: usize, cover_interior_indices: usize, cover_curve_indices: usize, edge_upper_line_indices: usize, edge_upper_curve_indices: usize, edge_lower_line_indices: usize, edge_lower_curve_indices: usize, } pub struct MeshLibraryIndexRanges { pub b_quads: Range, pub b_vertices: Range, pub cover_interior_indices: Range, pub cover_curve_indices: Range, pub edge_upper_line_indices: Range, pub edge_upper_curve_indices: Range, pub edge_lower_line_indices: Range, pub edge_lower_curve_indices: Range, } impl MeshLibraryIndexRanges { pub(crate) fn new(start: &MeshLibraryLengths, end: &MeshLibraryLengths) -> MeshLibraryIndexRanges { MeshLibraryIndexRanges { b_quads: start.b_quads..end.b_quads, b_vertices: start.b_vertices..end.b_vertices, cover_interior_indices: start.cover_interior_indices..end.cover_interior_indices, cover_curve_indices: start.cover_curve_indices..end.cover_curve_indices, edge_upper_line_indices: start.edge_upper_line_indices..end.edge_upper_line_indices, edge_upper_curve_indices: start.edge_upper_curve_indices..end.edge_upper_curve_indices, edge_lower_line_indices: start.edge_lower_line_indices..end.edge_lower_line_indices, edge_lower_curve_indices: start.edge_lower_curve_indices..end.edge_lower_curve_indices, } } }