// 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 std::u32; use {BQuad, BVertexLoopBlinnData}; #[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_data: MeshLibraryEdgeData, } 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_data: MeshLibraryEdgeData::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_data.clear(); } pub(crate) fn add_b_quad(&mut self, b_quad: &BQuad) { self.b_quads.push(*b_quad); let path_id = self.b_vertex_path_ids[b_quad.upper_left_vertex_index as usize]; let upper_left_position = &self.b_vertex_positions[b_quad.upper_left_vertex_index as usize]; let upper_right_position = &self.b_vertex_positions[b_quad.upper_right_vertex_index as usize]; let lower_left_position = &self.b_vertex_positions[b_quad.lower_left_vertex_index as usize]; let lower_right_position = &self.b_vertex_positions[b_quad.lower_right_vertex_index as usize]; let upper_left_bounding_box_position = Point2D::new(upper_left_position.x, f32::min(upper_left_position.y, upper_right_position.y)); let lower_right_bounding_box_position = Point2D::new(lower_right_position.x, f32::max(lower_left_position.y, lower_right_position.y)); self.edge_data.bounding_box_vertex_positions.push(EdgeBoundingBoxVertexPositions { upper_left: upper_left_bounding_box_position, lower_right: lower_right_bounding_box_position, }); self.edge_data.bounding_box_path_ids.push(path_id); if b_quad.upper_control_point_vertex_index == u32::MAX { self.edge_data.upper_line_vertex_positions.push(EdgeLineVertexPositions { left: *upper_left_position, right: *upper_right_position, }); self.edge_data.upper_line_path_ids.push(path_id); } else { let upper_control_point_position = &self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize]; self.edge_data.upper_curve_vertex_positions.push(EdgeCurveVertexPositions { left: *upper_left_position, control_point: *upper_control_point_position, right: *upper_right_position, }); self.edge_data.upper_curve_path_ids.push(path_id); } if b_quad.lower_control_point_vertex_index == u32::MAX { self.edge_data.lower_line_vertex_positions.push(EdgeLineVertexPositions { left: *lower_left_position, right: *lower_right_position, }); self.edge_data.lower_line_path_ids.push(path_id); } else { let lower_control_point_position = &self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize]; self.edge_data.lower_curve_vertex_positions.push(EdgeCurveVertexPositions { left: *lower_left_position, control_point: *lower_control_point_position, right: *lower_right_position, }); self.edge_data.lower_curve_path_ids.push(path_id); } } /// 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"ebbv", &self.edge_data.bounding_box_vertex_positions)); try!(write_chunk(writer, b"eulv", &self.edge_data.upper_line_vertex_positions)); try!(write_chunk(writer, b"ellv", &self.edge_data.lower_line_vertex_positions)); try!(write_chunk(writer, b"eucv", &self.edge_data.upper_curve_vertex_positions)); try!(write_chunk(writer, b"elcv", &self.edge_data.lower_curve_vertex_positions)); try!(write_chunk(writer, b"ebbp", &self.edge_data.bounding_box_path_ids)); try!(write_chunk(writer, b"eulp", &self.edge_data.upper_line_path_ids)); try!(write_chunk(writer, b"ellp", &self.edge_data.lower_line_path_ids)); try!(write_chunk(writer, b"eucp", &self.edge_data.upper_curve_path_ids)); try!(write_chunk(writer, b"elcp", &self.edge_data.lower_curve_path_ids)); 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_bounding_box_indices: self.edge_data.bounding_box_vertex_positions.len(), edge_upper_line_indices: self.edge_data.upper_line_vertex_positions.len(), edge_upper_curve_indices: self.edge_data.upper_curve_vertex_positions.len(), edge_lower_line_indices: self.edge_data.lower_line_vertex_positions.len(), edge_lower_curve_indices: self.edge_data.lower_curve_vertex_positions.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(); } } pub(crate) struct MeshLibraryLengths { b_quads: usize, b_vertices: usize, cover_interior_indices: usize, cover_curve_indices: usize, edge_bounding_box_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_bounding_box_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_bounding_box_indices: start.edge_bounding_box_indices..end.edge_bounding_box_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, } } } #[derive(Clone, Debug)] pub struct MeshLibraryEdgeData { pub bounding_box_vertex_positions: Vec, pub upper_line_vertex_positions: Vec, pub lower_line_vertex_positions: Vec, pub upper_curve_vertex_positions: Vec, pub lower_curve_vertex_positions: Vec, pub bounding_box_path_ids: Vec, pub upper_line_path_ids: Vec, pub lower_line_path_ids: Vec, pub upper_curve_path_ids: Vec, pub lower_curve_path_ids: Vec, } impl MeshLibraryEdgeData { fn new() -> MeshLibraryEdgeData { MeshLibraryEdgeData { bounding_box_vertex_positions: vec![], upper_line_vertex_positions: vec![], lower_line_vertex_positions: vec![], upper_curve_vertex_positions: vec![], lower_curve_vertex_positions: vec![], bounding_box_path_ids: vec![], upper_line_path_ids: vec![], lower_line_path_ids: vec![], upper_curve_path_ids: vec![], lower_curve_path_ids: vec![], } } fn clear(&mut self) { self.bounding_box_vertex_positions.clear(); self.upper_line_vertex_positions.clear(); self.upper_curve_vertex_positions.clear(); self.lower_line_vertex_positions.clear(); self.lower_curve_vertex_positions.clear(); self.bounding_box_path_ids.clear(); self.upper_line_path_ids.clear(); self.upper_curve_path_ids.clear(); self.lower_line_path_ids.clear(); self.lower_curve_path_ids.clear(); } } #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct EdgeBoundingBoxVertexPositions { pub upper_left: Point2D, pub lower_right: Point2D, } #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct EdgeLineVertexPositions { pub left: Point2D, pub right: Point2D, } #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct EdgeCurveVertexPositions { pub left: Point2D, pub control_point: Point2D, pub right: Point2D, }