Add a SIMD rect type
This commit is contained in:
parent
63b47f1abe
commit
fe410e066f
|
@ -566,7 +566,6 @@ version = "0.3.0"
|
||||||
name = "pathfinder_svg"
|
name = "pathfinder_svg"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pathfinder_geometry 0.3.0",
|
"pathfinder_geometry 0.3.0",
|
||||||
"pathfinder_renderer 0.1.0",
|
"pathfinder_renderer 0.1.0",
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::Size2D;
|
||||||
use jemallocator;
|
use jemallocator;
|
||||||
use pathfinder_geometry::basic::point::Point3DF32;
|
use pathfinder_geometry::basic::point::{Point2DF32, Point3DF32};
|
||||||
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
|
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
|
||||||
use pathfinder_gl::renderer::Renderer;
|
use pathfinder_gl::renderer::Renderer;
|
||||||
use pathfinder_renderer::builder::SceneBuilder;
|
use pathfinder_renderer::builder::SceneBuilder;
|
||||||
|
@ -211,7 +212,6 @@ impl SceneThread {
|
||||||
fn run(self) {
|
fn run(self) {
|
||||||
while let Ok(msg) = self.receiver.recv() {
|
while let Ok(msg) = self.receiver.recv() {
|
||||||
match msg {
|
match msg {
|
||||||
MainToSceneMsg::Exit => return,
|
|
||||||
MainToSceneMsg::Build(perspective) => {
|
MainToSceneMsg::Build(perspective) => {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let built_scene = build_scene(&self.scene, perspective, &self.options);
|
let built_scene = build_scene(&self.scene, perspective, &self.options);
|
||||||
|
@ -225,7 +225,6 @@ impl SceneThread {
|
||||||
|
|
||||||
enum MainToSceneMsg {
|
enum MainToSceneMsg {
|
||||||
Build(Option<Perspective>),
|
Build(Option<Perspective>),
|
||||||
Exit,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SceneToMainMsg {
|
enum SceneToMainMsg {
|
||||||
|
@ -285,7 +284,9 @@ fn load_scene(options: &Options, window_size: &Size2D<u32>) -> Scene {
|
||||||
let usvg = Tree::from_file(&options.input_path, &UsvgOptions::default()).unwrap();
|
let usvg = Tree::from_file(&options.input_path, &UsvgOptions::default()).unwrap();
|
||||||
|
|
||||||
let mut scene = Scene::from_tree(usvg);
|
let mut scene = Scene::from_tree(usvg);
|
||||||
scene.view_box = Rect::new(Point2D::zero(), window_size.to_f32());
|
scene.view_box =
|
||||||
|
RectF32::new(Point2DF32::default(),
|
||||||
|
Point2DF32::new(window_size.width as f32, window_size.height as f32));
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Scene bounds: {:?} View box: {:?}",
|
"Scene bounds: {:?} View box: {:?}",
|
||||||
|
@ -301,7 +302,7 @@ fn load_scene(options: &Options, window_size: &Size2D<u32>) -> Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_scene(scene: &Scene, perspective: Option<Perspective>, options: &Options) -> BuiltScene {
|
fn build_scene(scene: &Scene, perspective: Option<Perspective>, options: &Options) -> BuiltScene {
|
||||||
let z_buffer = ZBuffer::new(&scene.view_box);
|
let z_buffer = ZBuffer::new(scene.view_box);
|
||||||
|
|
||||||
let build_transform = match perspective {
|
let build_transform = match perspective {
|
||||||
None => BuildTransform::None,
|
None => BuildTransform::None,
|
||||||
|
@ -324,10 +325,10 @@ fn build_scene(scene: &Scene, perspective: Option<Perspective>, options: &Option
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut built_scene = BuiltScene::new(&scene.view_box);
|
let mut built_scene = BuiltScene::new(scene.view_box);
|
||||||
built_scene.shaders = scene.build_shaders();
|
built_scene.shaders = scene.build_shaders();
|
||||||
|
|
||||||
let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, &scene.view_box);
|
let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, scene.view_box);
|
||||||
built_scene.solid_tiles = scene_builder.build_solid_tiles();
|
built_scene.solid_tiles = scene_builder.build_solid_tiles();
|
||||||
while let Some(batch) = scene_builder.build_batch() {
|
while let Some(batch) = scene_builder.build_batch() {
|
||||||
built_scene.batches.push(batch);
|
built_scene.batches.push(batch);
|
||||||
|
|
|
@ -12,5 +12,6 @@
|
||||||
|
|
||||||
pub mod line_segment;
|
pub mod line_segment;
|
||||||
pub mod point;
|
pub mod point;
|
||||||
|
pub mod rect;
|
||||||
pub mod transform2d;
|
pub mod transform2d;
|
||||||
pub mod transform3d;
|
pub mod transform3d;
|
||||||
|
|
|
@ -40,10 +40,9 @@ impl Point2DF32 {
|
||||||
Point2D::new(self.0[0], self.0[1])
|
Point2D::new(self.0[0], self.0[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Optimize this!
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_4d(self) -> Point3DF32 {
|
pub fn to_3d(self) -> Point3DF32 {
|
||||||
Point3DF32::new(self.0[0], self.0[1], 0.0, 1.0)
|
Point3DF32(self.0.concat_xy_xy(F32x4::new(0.0, 1.0, 0.0, 0.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
// pathfinder/geometry/src/basic/rect.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! 2D axis-aligned rectangles, optimized with SIMD.
|
||||||
|
|
||||||
|
use crate::basic::point::Point2DF32;
|
||||||
|
use pathfinder_simd::default::F32x4;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||||
|
pub struct RectF32(pub F32x4);
|
||||||
|
|
||||||
|
impl RectF32 {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(origin: Point2DF32, size: Point2DF32) -> RectF32 {
|
||||||
|
RectF32(origin.0.concat_xy_xy(origin.0 + size.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_points(origin: Point2DF32, lower_right: Point2DF32) -> RectF32 {
|
||||||
|
RectF32(origin.0.concat_xy_xy(lower_right.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn origin(&self) -> Point2DF32 {
|
||||||
|
Point2DF32(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn size(&self) -> Point2DF32 {
|
||||||
|
Point2DF32(self.0.zwxy() - self.0.xyxy())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn upper_right(&self) -> Point2DF32 {
|
||||||
|
Point2DF32(self.0.zyxw())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn lower_left(&self) -> Point2DF32 {
|
||||||
|
Point2DF32(self.0.xwzy())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn lower_right(&self) -> Point2DF32 {
|
||||||
|
Point2DF32(self.0.zwxy())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn contains_point(&self, point: Point2DF32) -> bool {
|
||||||
|
// self.origin <= point && point <= self.lower_right
|
||||||
|
self.0.concat_xy_xy(point.0).packed_le(point.0.concat_xy_zw(self.0)).is_all_ones()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn contains_rect(&self, other: RectF32) -> bool {
|
||||||
|
// self.origin <= other.origin && other.lower_right <= self.lower_right
|
||||||
|
self.0.concat_xy_zw(other.0).packed_le(other.0.concat_xy_zw(self.0)).is_all_ones()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.origin() == self.lower_right()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn union_point(&self, point: Point2DF32) -> RectF32 {
|
||||||
|
RectF32::from_points(self.origin().min(point), self.lower_right().max(point))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn union_rect(&self, other: RectF32) -> RectF32 {
|
||||||
|
RectF32::from_points(self.origin().min(other.origin()),
|
||||||
|
self.lower_right().max(other.lower_right()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn intersects(&self, other: RectF32) -> bool {
|
||||||
|
// self.origin < other.lower_right && other.origin < self.lower_right
|
||||||
|
self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).is_all_ones()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn intersection(&self, other: RectF32) -> Option<RectF32> {
|
||||||
|
if !self.intersects(other) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(RectF32::from_points(self.origin().max(other.origin()),
|
||||||
|
self.lower_right().min(other.lower_right())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn min_x(self) -> f32 {
|
||||||
|
self.0[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn min_y(self) -> f32 {
|
||||||
|
self.0[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn max_x(self) -> f32 {
|
||||||
|
self.0[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn max_y(self) -> f32 {
|
||||||
|
self.0[3]
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,9 +11,10 @@
|
||||||
//! 2D affine transforms.
|
//! 2D affine transforms.
|
||||||
|
|
||||||
use crate::basic::point::Point2DF32;
|
use crate::basic::point::Point2DF32;
|
||||||
|
use crate::basic::rect::RectF32;
|
||||||
use crate::basic::transform3d::Transform3DF32;
|
use crate::basic::transform3d::Transform3DF32;
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use euclid::{Point2D, Rect, Size2D, Transform2D};
|
use euclid::Transform2D;
|
||||||
use lyon_path::PathEvent;
|
use lyon_path::PathEvent;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
|
@ -145,19 +146,15 @@ impl Transform2DF32 {
|
||||||
self.matrix.transform_point(point) + self.vector
|
self.matrix.transform_point(point) + self.vector
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): SIMD.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_rect(&self, rect: &Rect<f32>) -> Rect<f32> {
|
pub fn transform_rect(&self, rect: &RectF32) -> RectF32 {
|
||||||
let upper_left = self.transform_point(&Point2DF32::from_euclid(rect.origin));
|
let upper_left = self.transform_point(&rect.origin());
|
||||||
let upper_right = self.transform_point(&Point2DF32::from_euclid(rect.top_right()));
|
let upper_right = self.transform_point(&rect.upper_right());
|
||||||
let lower_left = self.transform_point(&Point2DF32::from_euclid(rect.bottom_left()));
|
let lower_left = self.transform_point(&rect.lower_left());
|
||||||
let lower_right = self.transform_point(&Point2DF32::from_euclid(rect.bottom_right()));
|
let lower_right = self.transform_point(&rect.lower_right());
|
||||||
let min_x = upper_left.x().min(upper_right.x()).min(lower_left.x()).min(lower_right.x());
|
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
|
||||||
let min_y = upper_left.y().min(upper_right.y()).min(lower_left.y()).min(lower_right.y());
|
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
|
||||||
let max_x = upper_left.x().max(upper_right.x()).max(lower_left.x()).max(lower_right.x());
|
RectF32::from_points(min_point, max_point)
|
||||||
let max_y = upper_left.y().max(upper_right.y()).max(lower_left.y()).max(lower_right.y());
|
|
||||||
let (width, height) = (max_x - min_x, max_y - min_y);
|
|
||||||
Rect::new(Point2D::new(min_x, min_y), Size2D::new(width, height))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -11,9 +11,10 @@
|
||||||
//! 3D transforms that can be applied to paths.
|
//! 3D transforms that can be applied to paths.
|
||||||
|
|
||||||
use crate::basic::point::{Point2DF32, Point3DF32};
|
use crate::basic::point::{Point2DF32, Point3DF32};
|
||||||
|
use crate::basic::rect::RectF32;
|
||||||
use crate::basic::transform2d::Matrix2x2F32;
|
use crate::basic::transform2d::Matrix2x2F32;
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::Size2D;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::{Add, Neg};
|
use std::ops::{Add, Neg};
|
||||||
|
|
||||||
|
@ -260,7 +261,7 @@ impl Perspective {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_point_2d(&self, point: &Point2DF32) -> Point2DF32 {
|
pub fn transform_point_2d(&self, point: &Point2DF32) -> Point2DF32 {
|
||||||
let point = self.transform.transform_point(point.to_4d()).perspective_divide().to_2d();
|
let point = self.transform.transform_point(point.to_3d()).perspective_divide().to_2d();
|
||||||
let window_size = self.window_size.to_f32();
|
let window_size = self.window_size.to_f32();
|
||||||
let size_scale = Point2DF32::new(window_size.width * 0.5, window_size.height * 0.5);
|
let size_scale = Point2DF32::new(window_size.width * 0.5, window_size.height * 0.5);
|
||||||
(point + Point2DF32::splat(1.0)) * size_scale
|
(point + Point2DF32::splat(1.0)) * size_scale
|
||||||
|
@ -268,17 +269,14 @@ impl Perspective {
|
||||||
|
|
||||||
// TODO(pcwalton): SIMD?
|
// TODO(pcwalton): SIMD?
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_rect(&self, rect: &Rect<f32>) -> Rect<f32> {
|
pub fn transform_rect(&self, rect: RectF32) -> RectF32 {
|
||||||
let upper_left = self.transform_point_2d(&Point2DF32::from_euclid(rect.origin));
|
let upper_left = self.transform_point_2d(&rect.origin());
|
||||||
let upper_right = self.transform_point_2d(&Point2DF32::from_euclid(rect.top_right()));
|
let upper_right = self.transform_point_2d(&rect.upper_right());
|
||||||
let lower_left = self.transform_point_2d(&Point2DF32::from_euclid(rect.bottom_left()));
|
let lower_left = self.transform_point_2d(&rect.lower_left());
|
||||||
let lower_right = self.transform_point_2d(&Point2DF32::from_euclid(rect.bottom_right()));
|
let lower_right = self.transform_point_2d(&rect.lower_right());
|
||||||
let min_x = upper_left.x().min(upper_right.x()).min(lower_left.x()).min(lower_right.x());
|
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
|
||||||
let min_y = upper_left.y().min(upper_right.y()).min(lower_left.y()).min(lower_right.y());
|
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
|
||||||
let max_x = upper_left.x().max(upper_right.x()).max(lower_left.x()).max(lower_right.x());
|
RectF32::from_points(min_point, max_point)
|
||||||
let max_y = upper_left.y().max(upper_right.y()).max(lower_left.y()).max(lower_right.y());
|
|
||||||
let (width, height) = (max_x - min_x, max_y - min_y);
|
|
||||||
Rect::new(Point2D::new(min_x, min_y), Size2D::new(width, height))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,34 +10,31 @@
|
||||||
|
|
||||||
use crate::basic::line_segment::LineSegmentF32;
|
use crate::basic::line_segment::LineSegmentF32;
|
||||||
use crate::basic::point::{Point2DF32, Point3DF32};
|
use crate::basic::point::{Point2DF32, Point3DF32};
|
||||||
|
use crate::basic::rect::RectF32;
|
||||||
use crate::outline::{Contour, PointFlags};
|
use crate::outline::{Contour, PointFlags};
|
||||||
use crate::segment::{CubicSegment, Segment};
|
use crate::segment::{CubicSegment, Segment};
|
||||||
use crate::util::lerp;
|
use crate::util::lerp;
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use euclid::Rect;
|
|
||||||
use lyon_path::PathEvent;
|
use lyon_path::PathEvent;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
pub struct RectClipper<'a> {
|
pub struct RectClipper<'a> {
|
||||||
clip_rect: Rect<f32>,
|
clip_rect: RectF32,
|
||||||
subject: &'a [PathEvent],
|
subject: &'a [PathEvent],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RectClipper<'a> {
|
impl<'a> RectClipper<'a> {
|
||||||
pub fn new<'aa>(clip_rect: &Rect<f32>, subject: &'aa [PathEvent]) -> RectClipper<'aa> {
|
pub fn new<'aa>(clip_rect: RectF32, subject: &'aa [PathEvent]) -> RectClipper<'aa> {
|
||||||
RectClipper {
|
RectClipper { clip_rect, subject }
|
||||||
clip_rect: *clip_rect,
|
|
||||||
subject,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clip(&self) -> Vec<PathEvent> {
|
pub fn clip(&self) -> Vec<PathEvent> {
|
||||||
let mut output = self.subject.to_vec();
|
let mut output = self.subject.to_vec();
|
||||||
self.clip_against(Edge::left(&self.clip_rect), &mut output);
|
self.clip_against(Edge::left(self.clip_rect), &mut output);
|
||||||
self.clip_against(Edge::top(&self.clip_rect), &mut output);
|
self.clip_against(Edge::top(self.clip_rect), &mut output);
|
||||||
self.clip_against(Edge::right(&self.clip_rect), &mut output);
|
self.clip_against(Edge::right(self.clip_rect), &mut output);
|
||||||
self.clip_against(Edge::bottom(&self.clip_rect), &mut output);
|
self.clip_against(Edge::bottom(self.clip_rect), &mut output);
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,27 +122,23 @@ impl TEdge for Edge {
|
||||||
|
|
||||||
impl Edge {
|
impl Edge {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn left(rect: &Rect<f32>) -> Edge {
|
fn left(rect: RectF32) -> Edge {
|
||||||
Edge(LineSegmentF32::new(&Point2DF32::from_euclid(rect.bottom_left()),
|
Edge(LineSegmentF32::new(&rect.lower_left(), &rect.origin()))
|
||||||
&Point2DF32::from_euclid(rect.origin)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn top(rect: &Rect<f32>) -> Edge {
|
fn top(rect: RectF32) -> Edge {
|
||||||
Edge(LineSegmentF32::new(&Point2DF32::from_euclid(rect.origin),
|
Edge(LineSegmentF32::new(&rect.origin(), &rect.upper_right()))
|
||||||
&Point2DF32::from_euclid(rect.top_right())))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn right(rect: &Rect<f32>) -> Edge {
|
fn right(rect: RectF32) -> Edge {
|
||||||
Edge(LineSegmentF32::new(&Point2DF32::from_euclid(rect.top_right()),
|
Edge(LineSegmentF32::new(&rect.upper_right(), &rect.lower_right()))
|
||||||
&Point2DF32::from_euclid(rect.bottom_right())))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bottom(rect: &Rect<f32>) -> Edge {
|
fn bottom(rect: RectF32) -> Edge {
|
||||||
Edge(LineSegmentF32::new(&Point2DF32::from_euclid(rect.bottom_right()),
|
Edge(LineSegmentF32::new(&rect.lower_right(), &rect.lower_left()))
|
||||||
&Point2DF32::from_euclid(rect.bottom_left())))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +419,7 @@ enum EdgeRelativeLocation {
|
||||||
// Fast axis-aligned box 2D clipping
|
// Fast axis-aligned box 2D clipping
|
||||||
|
|
||||||
pub(crate) struct ContourRectClipper {
|
pub(crate) struct ContourRectClipper {
|
||||||
clip_rect: Rect<f32>,
|
clip_rect: RectF32,
|
||||||
contour: Contour,
|
contour: Contour,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,17 +434,17 @@ impl ContourClipper for ContourRectClipper {
|
||||||
|
|
||||||
impl ContourRectClipper {
|
impl ContourRectClipper {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new(clip_rect: &Rect<f32>, contour: Contour) -> ContourRectClipper {
|
pub(crate) fn new(clip_rect: RectF32, contour: Contour) -> ContourRectClipper {
|
||||||
ContourRectClipper { clip_rect: *clip_rect, contour }
|
ContourRectClipper { clip_rect, contour }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clip(mut self) -> Contour {
|
pub(crate) fn clip(mut self) -> Contour {
|
||||||
if self.clip_rect.contains_rect(&self.contour.bounds()) {
|
if self.clip_rect.contains_rect(self.contour.bounds()) {
|
||||||
return self.contour
|
return self.contour
|
||||||
}
|
}
|
||||||
|
|
||||||
self.clip_against(AxisAlignedEdge::Left(self.clip_rect.origin.x));
|
self.clip_against(AxisAlignedEdge::Left(self.clip_rect.min_x()));
|
||||||
self.clip_against(AxisAlignedEdge::Top(self.clip_rect.origin.y));
|
self.clip_against(AxisAlignedEdge::Top(self.clip_rect.min_y()));
|
||||||
self.clip_against(AxisAlignedEdge::Right(self.clip_rect.max_x()));
|
self.clip_against(AxisAlignedEdge::Right(self.clip_rect.max_x()));
|
||||||
self.clip_against(AxisAlignedEdge::Bottom(self.clip_rect.max_y()));
|
self.clip_against(AxisAlignedEdge::Bottom(self.clip_rect.max_y()));
|
||||||
|
|
||||||
|
|
|
@ -12,26 +12,26 @@
|
||||||
|
|
||||||
use crate::basic::line_segment::LineSegmentF32;
|
use crate::basic::line_segment::LineSegmentF32;
|
||||||
use crate::basic::point::Point2DF32;
|
use crate::basic::point::Point2DF32;
|
||||||
|
use crate::basic::rect::RectF32;
|
||||||
use crate::basic::transform2d::Transform2DF32;
|
use crate::basic::transform2d::Transform2DF32;
|
||||||
use crate::basic::transform3d::Perspective;
|
use crate::basic::transform3d::Perspective;
|
||||||
use crate::clip::{ContourPolygonClipper, ContourRectClipper};
|
use crate::clip::{ContourPolygonClipper, ContourRectClipper};
|
||||||
use crate::monotonic::MonotonicConversionIter;
|
use crate::monotonic::MonotonicConversionIter;
|
||||||
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Outline {
|
pub struct Outline {
|
||||||
pub contours: Vec<Contour>,
|
pub contours: Vec<Contour>,
|
||||||
bounds: Rect<f32>,
|
bounds: RectF32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Contour {
|
pub struct Contour {
|
||||||
pub(crate) points: Vec<Point2DF32>,
|
pub(crate) points: Vec<Point2DF32>,
|
||||||
pub(crate) flags: Vec<PointFlags>,
|
pub(crate) flags: Vec<PointFlags>,
|
||||||
pub(crate) bounds: Rect<f32>,
|
pub(crate) bounds: RectF32,
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -44,10 +44,7 @@ bitflags! {
|
||||||
impl Outline {
|
impl Outline {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Outline {
|
pub fn new() -> Outline {
|
||||||
Outline {
|
Outline { contours: vec![], bounds: RectF32::default() }
|
||||||
contours: vec![],
|
|
||||||
bounds: Rect::zero(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -107,8 +104,8 @@ impl Outline {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn bounds(&self) -> &Rect<f32> {
|
pub fn bounds(&self) -> RectF32 {
|
||||||
&self.bounds
|
self.bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform(&mut self, transform: &Transform2DF32) {
|
pub fn transform(&mut self, transform: &Transform2DF32) {
|
||||||
|
@ -117,7 +114,7 @@ impl Outline {
|
||||||
contour.transform(transform);
|
contour.transform(transform);
|
||||||
contour.update_bounds(&mut new_bounds);
|
contour.update_bounds(&mut new_bounds);
|
||||||
}
|
}
|
||||||
self.bounds = new_bounds.unwrap_or_else(|| Rect::zero());
|
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_perspective(&mut self, perspective: &Perspective) {
|
pub fn apply_perspective(&mut self, perspective: &Perspective) {
|
||||||
|
@ -126,14 +123,14 @@ impl Outline {
|
||||||
contour.apply_perspective(perspective);
|
contour.apply_perspective(perspective);
|
||||||
contour.update_bounds(&mut new_bounds);
|
contour.update_bounds(&mut new_bounds);
|
||||||
}
|
}
|
||||||
self.bounds = new_bounds.unwrap_or_else(|| Rect::zero());
|
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_for_tiling(&mut self, view_box: &Rect<f32>) {
|
pub fn prepare_for_tiling(&mut self, view_box: RectF32) {
|
||||||
for contour in &mut self.contours {
|
for contour in &mut self.contours {
|
||||||
contour.prepare_for_tiling(view_box);
|
contour.prepare_for_tiling(view_box);
|
||||||
}
|
}
|
||||||
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| Rect::zero());
|
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clip_against_polygon(&mut self, clip_polygon: &[Point2DF32]) {
|
pub fn clip_against_polygon(&mut self, clip_polygon: &[Point2DF32]) {
|
||||||
|
@ -145,11 +142,11 @@ impl Outline {
|
||||||
self.contours.push(contour);
|
self.contours.push(contour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.bounds = new_bounds.unwrap_or_else(|| Rect::zero());
|
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clip_against_rect(&mut self, clip_rect: &Rect<f32>) {
|
pub fn clip_against_rect(&mut self, clip_rect: RectF32) {
|
||||||
if clip_rect.contains_rect(&self.bounds) {
|
if clip_rect.contains_rect(self.bounds) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +158,7 @@ impl Outline {
|
||||||
self.contours.push(contour);
|
self.contours.push(contour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.bounds = new_bounds.unwrap_or_else(|| Rect::zero());
|
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +177,7 @@ impl Debug for Outline {
|
||||||
impl Contour {
|
impl Contour {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Contour {
|
pub fn new() -> Contour {
|
||||||
Contour { points: vec![], flags: vec![], bounds: Rect::zero() }
|
Contour { points: vec![], flags: vec![], bounds: RectF32::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces this contour with a new one, with arrays preallocated to match `self`.
|
// Replaces this contour with a new one, with arrays preallocated to match `self`.
|
||||||
|
@ -190,7 +187,7 @@ impl Contour {
|
||||||
mem::replace(self, Contour {
|
mem::replace(self, Contour {
|
||||||
points: Vec::with_capacity(length),
|
points: Vec::with_capacity(length),
|
||||||
flags: Vec::with_capacity(length),
|
flags: Vec::with_capacity(length),
|
||||||
bounds: Rect::zero(),
|
bounds: RectF32::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,8 +207,8 @@ impl Contour {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn bounds(&self) -> &Rect<f32> {
|
pub fn bounds(&self) -> RectF32 {
|
||||||
&self.bounds
|
self.bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -362,11 +359,10 @@ impl Contour {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_for_tiling(&mut self, view_box: &Rect<f32>) {
|
fn prepare_for_tiling(&mut self, view_box: RectF32) {
|
||||||
// Snap points to the view box bounds. This mops up floating point error from the clipping
|
// Snap points to the view box bounds. This mops up floating point error from the clipping
|
||||||
// process.
|
// process.
|
||||||
let origin_upper_left = Point2DF32::from_euclid(view_box.origin);
|
let (origin_upper_left, origin_lower_right) = (view_box.origin(), view_box.lower_right());
|
||||||
let origin_lower_right = Point2DF32::from_euclid(view_box.bottom_right());
|
|
||||||
let (mut last_endpoint_index, mut contour_is_monotonic) = (None, true);
|
let (mut last_endpoint_index, mut contour_is_monotonic) = (None, true);
|
||||||
for point_index in 0..(self.points.len() as u32) {
|
for point_index in 0..(self.points.len() as u32) {
|
||||||
let position = &mut self.points[point_index as usize];
|
let position = &mut self.points[point_index as usize];
|
||||||
|
@ -395,7 +391,7 @@ impl Contour {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update bounds.
|
// Update bounds.
|
||||||
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| Rect::zero());
|
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn curve_with_endpoints_is_monotonic(&self, start_endpoint_index: u32, end_endpoint_index: u32)
|
fn curve_with_endpoints_is_monotonic(&self, start_endpoint_index: u32, end_endpoint_index: u32)
|
||||||
|
@ -438,10 +434,10 @@ impl Contour {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_bounds(&self, bounds: &mut Option<Rect<f32>>) {
|
fn update_bounds(&self, bounds: &mut Option<RectF32>) {
|
||||||
*bounds = Some(match *bounds {
|
*bounds = Some(match *bounds {
|
||||||
None => self.bounds,
|
None => self.bounds,
|
||||||
Some(bounds) => bounds.union(&self.bounds),
|
Some(bounds) => bounds.union_rect(self.bounds),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -558,17 +554,10 @@ impl<'a> Iterator for ContourIter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn union_rect(bounds: &mut Rect<f32>, new_point: Point2DF32, first: bool) {
|
fn union_rect(bounds: &mut RectF32, new_point: Point2DF32, first: bool) {
|
||||||
if first {
|
if first {
|
||||||
*bounds = Rect::new(new_point.as_euclid(), Size2D::zero());
|
*bounds = RectF32::from_points(new_point, new_point);
|
||||||
return;
|
} else {
|
||||||
|
*bounds = bounds.union_point(new_point)
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut min_x, mut min_y) = (bounds.origin.x, bounds.origin.y);
|
|
||||||
let (mut max_x, mut max_y) = (bounds.max_x(), bounds.max_y());
|
|
||||||
min_x = min_x.min(new_point.x());
|
|
||||||
min_y = min_y.min(new_point.y());
|
|
||||||
max_x = max_x.max(new_point.x());
|
|
||||||
max_y = max_y.max(new_point.y());
|
|
||||||
*bounds = Rect::new(Point2D::new(min_x, min_y), Size2D::new(max_x - min_x, max_y - min_y));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ use crate::scene;
|
||||||
use crate::tiles;
|
use crate::tiles;
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use euclid::Rect;
|
use euclid::Rect;
|
||||||
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
|
|
||||||
|
@ -31,8 +32,7 @@ pub struct SceneBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SceneBuilder {
|
impl SceneBuilder {
|
||||||
pub fn new(objects: Vec<BuiltObject>, z_buffer: ZBuffer, view_box: &Rect<f32>)
|
pub fn new(objects: Vec<BuiltObject>, z_buffer: ZBuffer, view_box: RectF32) -> SceneBuilder {
|
||||||
-> SceneBuilder {
|
|
||||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
|
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
|
||||||
SceneBuilder {
|
SceneBuilder {
|
||||||
objects,
|
objects,
|
||||||
|
|
|
@ -16,12 +16,13 @@ use euclid::Rect;
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use pathfinder_geometry::basic::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8};
|
use pathfinder_geometry::basic::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8};
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
use pathfinder_geometry::basic::point::Point2DF32;
|
||||||
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use pathfinder_geometry::util;
|
use pathfinder_geometry::util;
|
||||||
use pathfinder_simd::default::{F32x4, I32x4};
|
use pathfinder_simd::default::{F32x4, I32x4};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BuiltObject {
|
pub struct BuiltObject {
|
||||||
pub bounds: Rect<f32>,
|
pub bounds: RectF32,
|
||||||
pub tile_rect: Rect<i16>,
|
pub tile_rect: Rect<i16>,
|
||||||
pub tiles: Vec<TileObjectPrimitive>,
|
pub tiles: Vec<TileObjectPrimitive>,
|
||||||
pub fills: Vec<FillObjectPrimitive>,
|
pub fills: Vec<FillObjectPrimitive>,
|
||||||
|
@ -31,7 +32,7 @@ pub struct BuiltObject {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BuiltScene {
|
pub struct BuiltScene {
|
||||||
pub view_box: Rect<f32>,
|
pub view_box: RectF32,
|
||||||
pub batches: Vec<Batch>,
|
pub batches: Vec<Batch>,
|
||||||
pub solid_tiles: Vec<SolidTileScenePrimitive>,
|
pub solid_tiles: Vec<SolidTileScenePrimitive>,
|
||||||
pub shaders: Vec<ObjectShader>,
|
pub shaders: Vec<ObjectShader>,
|
||||||
|
@ -86,9 +87,9 @@ pub struct MaskTileBatchPrimitive {
|
||||||
// Utilities for built objects
|
// Utilities for built objects
|
||||||
|
|
||||||
impl BuiltObject {
|
impl BuiltObject {
|
||||||
pub fn new(bounds: &Rect<f32>, shader: ShaderId) -> BuiltObject {
|
pub fn new(bounds: RectF32, shader: ShaderId) -> BuiltObject {
|
||||||
// Compute the tile rect.
|
// Compute the tile rect.
|
||||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(&bounds);
|
let tile_rect = tiles::round_rect_out_to_tile_bounds(bounds);
|
||||||
|
|
||||||
// Allocate tiles.
|
// Allocate tiles.
|
||||||
let tile_count = tile_rect.size.width as usize * tile_rect.size.height as usize;
|
let tile_count = tile_rect.size.width as usize * tile_rect.size.height as usize;
|
||||||
|
@ -102,14 +103,7 @@ impl BuiltObject {
|
||||||
let mut solid_tiles = FixedBitSet::with_capacity(tile_count);
|
let mut solid_tiles = FixedBitSet::with_capacity(tile_count);
|
||||||
solid_tiles.insert_range(..);
|
solid_tiles.insert_range(..);
|
||||||
|
|
||||||
BuiltObject {
|
BuiltObject { bounds, tile_rect, tiles, fills: vec![], solid_tiles, shader }
|
||||||
bounds: *bounds,
|
|
||||||
tile_rect,
|
|
||||||
tiles,
|
|
||||||
fills: vec![],
|
|
||||||
solid_tiles,
|
|
||||||
shader,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): SIMD-ify `tile_x` and `tile_y`.
|
// TODO(pcwalton): SIMD-ify `tile_x` and `tile_y`.
|
||||||
|
@ -256,13 +250,8 @@ impl BuiltObject {
|
||||||
|
|
||||||
impl BuiltScene {
|
impl BuiltScene {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(view_box: &Rect<f32>) -> BuiltScene {
|
pub fn new(view_box: RectF32) -> BuiltScene {
|
||||||
BuiltScene {
|
BuiltScene { view_box, batches: vec![], solid_tiles: vec![], shaders: vec![] }
|
||||||
view_box: *view_box,
|
|
||||||
batches: vec![],
|
|
||||||
solid_tiles: vec![],
|
|
||||||
shaders: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ use crate::tiles::Tiler;
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use euclid::Rect;
|
use euclid::Rect;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use pathfinder_geometry::basic::point::{Point2DF32, Point3DF32};
|
use pathfinder_geometry::basic::point::Point2DF32;
|
||||||
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
||||||
use pathfinder_geometry::basic::transform3d::Perspective;
|
use pathfinder_geometry::basic::transform3d::Perspective;
|
||||||
use pathfinder_geometry::clip::PolygonClipper3D;
|
use pathfinder_geometry::clip::PolygonClipper3D;
|
||||||
|
@ -29,8 +30,8 @@ pub struct Scene {
|
||||||
pub objects: Vec<PathObject>,
|
pub objects: Vec<PathObject>,
|
||||||
pub paints: Vec<Paint>,
|
pub paints: Vec<Paint>,
|
||||||
pub paint_cache: HashMap<Paint, PaintId>,
|
pub paint_cache: HashMap<Paint, PaintId>,
|
||||||
pub bounds: Rect<f32>,
|
pub bounds: RectF32,
|
||||||
pub view_box: Rect<f32>,
|
pub view_box: RectF32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
|
@ -40,8 +41,8 @@ impl Scene {
|
||||||
objects: vec![],
|
objects: vec![],
|
||||||
paints: vec![],
|
paints: vec![],
|
||||||
paint_cache: HashMap::new(),
|
paint_cache: HashMap::new(),
|
||||||
bounds: Rect::zero(),
|
bounds: RectF32::default(),
|
||||||
view_box: Rect::zero(),
|
view_box: RectF32::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ impl Scene {
|
||||||
|
|
||||||
pub fn build_objects_sequentially(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
|
pub fn build_objects_sequentially(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
|
||||||
-> Vec<BuiltObject> {
|
-> Vec<BuiltObject> {
|
||||||
let build_transform = build_transform.prepare(&self.bounds);
|
let build_transform = build_transform.prepare(self.bounds);
|
||||||
self.objects
|
self.objects
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -76,7 +77,7 @@ impl Scene {
|
||||||
let outline = self.apply_build_transform(&object.outline, &build_transform);
|
let outline = self.apply_build_transform(&object.outline, &build_transform);
|
||||||
let mut tiler = Tiler::new(
|
let mut tiler = Tiler::new(
|
||||||
&outline,
|
&outline,
|
||||||
&self.view_box,
|
self.view_box,
|
||||||
object_index as u16,
|
object_index as u16,
|
||||||
ShaderId(object.paint.0),
|
ShaderId(object.paint.0),
|
||||||
z_buffer,
|
z_buffer,
|
||||||
|
@ -89,7 +90,7 @@ impl Scene {
|
||||||
|
|
||||||
pub fn build_objects(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
|
pub fn build_objects(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
|
||||||
-> Vec<BuiltObject> {
|
-> Vec<BuiltObject> {
|
||||||
let build_transform = build_transform.prepare(&self.bounds);
|
let build_transform = build_transform.prepare(self.bounds);
|
||||||
self.objects
|
self.objects
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -97,7 +98,7 @@ impl Scene {
|
||||||
let outline = self.apply_build_transform(&object.outline, &build_transform);
|
let outline = self.apply_build_transform(&object.outline, &build_transform);
|
||||||
let mut tiler = Tiler::new(
|
let mut tiler = Tiler::new(
|
||||||
&outline,
|
&outline,
|
||||||
&self.view_box,
|
self.view_box,
|
||||||
object_index as u16,
|
object_index as u16,
|
||||||
ShaderId(object.paint.0),
|
ShaderId(object.paint.0),
|
||||||
z_buffer,
|
z_buffer,
|
||||||
|
@ -116,17 +117,17 @@ impl Scene {
|
||||||
PreparedBuildTransform::Perspective(ref perspective, ref quad) => {
|
PreparedBuildTransform::Perspective(ref perspective, ref quad) => {
|
||||||
outline.clip_against_polygon(quad);
|
outline.clip_against_polygon(quad);
|
||||||
outline.apply_perspective(perspective);
|
outline.apply_perspective(perspective);
|
||||||
outline.prepare_for_tiling(&self.view_box);
|
outline.prepare_for_tiling(self.view_box);
|
||||||
}
|
}
|
||||||
PreparedBuildTransform::Transform2D(ref transform) => {
|
PreparedBuildTransform::Transform2D(ref transform) => {
|
||||||
outline.transform(transform);
|
outline.transform(transform);
|
||||||
outline.clip_against_rect(&self.view_box);
|
outline.clip_against_rect(self.view_box);
|
||||||
}
|
}
|
||||||
PreparedBuildTransform::None => {
|
PreparedBuildTransform::None => {
|
||||||
outline.clip_against_rect(&self.view_box);
|
outline.clip_against_rect(self.view_box);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outline.prepare_for_tiling(&self.view_box);
|
outline.prepare_for_tiling(self.view_box);
|
||||||
outline
|
outline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,10 +136,10 @@ impl Debug for Scene {
|
||||||
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
writeln!(formatter,
|
writeln!(formatter,
|
||||||
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"{} {} {} {}\">",
|
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"{} {} {} {}\">",
|
||||||
self.view_box.origin.x,
|
self.view_box.origin().x(),
|
||||||
self.view_box.origin.y,
|
self.view_box.origin().y(),
|
||||||
self.view_box.size.width,
|
self.view_box.size().x(),
|
||||||
self.view_box.size.height)?;
|
self.view_box.size().y())?;
|
||||||
for object in &self.objects {
|
for object in &self.objects {
|
||||||
let paint = &self.paints[object.paint.0 as usize];
|
let paint = &self.paints[object.paint.0 as usize];
|
||||||
write!(formatter, " <path")?;
|
write!(formatter, " <path")?;
|
||||||
|
@ -197,7 +198,7 @@ pub enum BuildTransform {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildTransform {
|
impl BuildTransform {
|
||||||
fn prepare(&self, bounds: &Rect<f32>) -> PreparedBuildTransform {
|
fn prepare(&self, bounds: RectF32) -> PreparedBuildTransform {
|
||||||
let perspective = match self {
|
let perspective = match self {
|
||||||
BuildTransform::None => return PreparedBuildTransform::None,
|
BuildTransform::None => return PreparedBuildTransform::None,
|
||||||
BuildTransform::Transform2D(ref transform) => {
|
BuildTransform::Transform2D(ref transform) => {
|
||||||
|
@ -207,10 +208,10 @@ impl BuildTransform {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut points = vec![
|
let mut points = vec![
|
||||||
Point3DF32::from_euclid_2d(&bounds.origin),
|
bounds.origin().to_3d(),
|
||||||
Point3DF32::from_euclid_2d(&bounds.top_right()),
|
bounds.upper_right().to_3d(),
|
||||||
Point3DF32::from_euclid_2d(&bounds.bottom_right()),
|
bounds.lower_right().to_3d(),
|
||||||
Point3DF32::from_euclid_2d(&bounds.bottom_left()),
|
bounds.lower_left().to_3d(),
|
||||||
];
|
];
|
||||||
//println!("-----");
|
//println!("-----");
|
||||||
//println!("bounds={:?} ORIGINAL quad={:?}", self.bounds, points);
|
//println!("bounds={:?} ORIGINAL quad={:?}", self.bounds, points);
|
||||||
|
|
|
@ -54,10 +54,10 @@ impl RiffSerialize for BuiltScene {
|
||||||
writer.write_u32::<LittleEndian>(header_size as u32)?;
|
writer.write_u32::<LittleEndian>(header_size as u32)?;
|
||||||
writer.write_u32::<LittleEndian>(FILE_VERSION)?;
|
writer.write_u32::<LittleEndian>(FILE_VERSION)?;
|
||||||
writer.write_u32::<LittleEndian>(self.batches.len() as u32)?;
|
writer.write_u32::<LittleEndian>(self.batches.len() as u32)?;
|
||||||
writer.write_f32::<LittleEndian>(self.view_box.origin.x)?;
|
writer.write_f32::<LittleEndian>(self.view_box.origin().x())?;
|
||||||
writer.write_f32::<LittleEndian>(self.view_box.origin.y)?;
|
writer.write_f32::<LittleEndian>(self.view_box.origin().y())?;
|
||||||
writer.write_f32::<LittleEndian>(self.view_box.size.width)?;
|
writer.write_f32::<LittleEndian>(self.view_box.size().x())?;
|
||||||
writer.write_f32::<LittleEndian>(self.view_box.size.height)?;
|
writer.write_f32::<LittleEndian>(self.view_box.size().y())?;
|
||||||
|
|
||||||
writer.write_all(b"shad")?;
|
writer.write_all(b"shad")?;
|
||||||
writer.write_u32::<LittleEndian>(shaders_size as u32)?;
|
writer.write_u32::<LittleEndian>(shaders_size as u32)?;
|
||||||
|
|
|
@ -15,6 +15,7 @@ use crate::z_buffer::ZBuffer;
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
use pathfinder_geometry::basic::point::Point2DF32;
|
||||||
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use pathfinder_geometry::outline::{Contour, Outline, PointIndex};
|
use pathfinder_geometry::outline::{Contour, Outline, PointIndex};
|
||||||
use pathfinder_geometry::segment::Segment;
|
use pathfinder_geometry::segment::Segment;
|
||||||
use pathfinder_geometry::util;
|
use pathfinder_geometry::util;
|
||||||
|
@ -42,16 +43,13 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
#[allow(clippy::or_fun_call)]
|
#[allow(clippy::or_fun_call)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
outline: &'o Outline,
|
outline: &'o Outline,
|
||||||
view_box: &Rect<f32>,
|
view_box: RectF32,
|
||||||
object_index: u16,
|
object_index: u16,
|
||||||
shader: ShaderId,
|
shader: ShaderId,
|
||||||
z_buffer: &'z ZBuffer,
|
z_buffer: &'z ZBuffer,
|
||||||
) -> Tiler<'o, 'z> {
|
) -> Tiler<'o, 'z> {
|
||||||
let bounds = outline
|
let bounds = outline.bounds().intersection(view_box).unwrap_or(RectF32::default());
|
||||||
.bounds()
|
let built_object = BuiltObject::new(bounds, shader);
|
||||||
.intersection(&view_box)
|
|
||||||
.unwrap_or(Rect::zero());
|
|
||||||
let built_object = BuiltObject::new(&bounds, shader);
|
|
||||||
|
|
||||||
Tiler {
|
Tiler {
|
||||||
outline,
|
outline,
|
||||||
|
@ -304,11 +302,9 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn round_rect_out_to_tile_bounds(rect: &Rect<f32>) -> Rect<i16> {
|
pub fn round_rect_out_to_tile_bounds(rect: RectF32) -> Rect<i16> {
|
||||||
let tile_origin = Point2D::new(
|
let tile_origin = Point2D::new((f32::floor(rect.min_x()) as i32 / TILE_WIDTH as i32) as i16,
|
||||||
(f32::floor(rect.origin.x) as i32 / TILE_WIDTH as i32) as i16,
|
(f32::floor(rect.min_y()) as i32 / TILE_HEIGHT as i32) as i16);
|
||||||
(f32::floor(rect.origin.y) as i32 / TILE_HEIGHT as i32) as i16,
|
|
||||||
);
|
|
||||||
let tile_extent = Point2D::new(
|
let tile_extent = Point2D::new(
|
||||||
util::alignup_i32(f32::ceil(rect.max_x()) as i32, TILE_WIDTH as i32) as i16,
|
util::alignup_i32(f32::ceil(rect.max_x()) as i32, TILE_WIDTH as i32) as i16,
|
||||||
util::alignup_i32(f32::ceil(rect.max_y()) as i32, TILE_HEIGHT as i32) as i16,
|
util::alignup_i32(f32::ceil(rect.max_y()) as i32, TILE_HEIGHT as i32) as i16,
|
||||||
|
@ -377,7 +373,7 @@ impl ActiveEdge {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&mut self, built_object: &mut BuiltObject, tile_y: i16) {
|
fn process(&mut self, built_object: &mut BuiltObject, tile_y: i16) {
|
||||||
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
|
//let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
|
||||||
//println!("process_active_edge({:#?}, tile_y={}({}))", self, tile_y, tile_bottom);
|
//println!("process_active_edge({:#?}, tile_y={}({}))", self, tile_y, tile_bottom);
|
||||||
|
|
||||||
let mut segment = self.segment;
|
let mut segment = self.segment;
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::gpu_data::{BuiltObject, SolidTileScenePrimitive};
|
||||||
use crate::scene;
|
use crate::scene;
|
||||||
use crate::tiles;
|
use crate::tiles;
|
||||||
use euclid::Rect;
|
use euclid::Rect;
|
||||||
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
|
|
||||||
pub struct ZBuffer {
|
pub struct ZBuffer {
|
||||||
|
@ -22,7 +23,7 @@ pub struct ZBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ZBuffer {
|
impl ZBuffer {
|
||||||
pub fn new(view_box: &Rect<f32>) -> ZBuffer {
|
pub fn new(view_box: RectF32) -> ZBuffer {
|
||||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
|
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
|
||||||
let tile_area = tile_rect.size.width as usize * tile_rect.size.height as usize;
|
let tile_area = tile_rect.size.width as usize * tile_rect.size.height as usize;
|
||||||
ZBuffer {
|
ZBuffer {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::default::F32x4;
|
use crate::default::{F32x4, U32x4};
|
||||||
|
|
||||||
impl F32x4 {
|
impl F32x4 {
|
||||||
// Accessors
|
// Accessors
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::arch::x86_64::{self, __m128, __m128i};
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Add, AddAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, BitXor, Index, IndexMut, Mul, MulAssign, Neg, Not, Sub, SubAssign};
|
||||||
|
|
||||||
// 32-bit floats
|
// 32-bit floats
|
||||||
|
|
||||||
|
@ -75,6 +75,16 @@ impl F32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_lt(self, other: F32x4) -> U32x4 {
|
||||||
|
other.packed_gt(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_le(self, other: F32x4) -> U32x4 {
|
||||||
|
!self.packed_gt(other)
|
||||||
|
}
|
||||||
|
|
||||||
// Conversions
|
// Conversions
|
||||||
|
|
||||||
/// Converts these packed floats to integers.
|
/// Converts these packed floats to integers.
|
||||||
|
@ -1592,6 +1602,11 @@ impl U32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn splat(x: u32) -> U32x4 {
|
||||||
|
unsafe { U32x4(x86_64::_mm_set1_epi32(x as i32)) }
|
||||||
|
}
|
||||||
|
|
||||||
// Basic operations
|
// Basic operations
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1634,6 +1649,24 @@ impl PartialEq for U32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Not for U32x4 {
|
||||||
|
type Output = U32x4;
|
||||||
|
#[inline]
|
||||||
|
fn not(self) -> U32x4 {
|
||||||
|
self ^ U32x4::splat(!0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitXor<U32x4> for U32x4 {
|
||||||
|
type Output = U32x4;
|
||||||
|
#[inline]
|
||||||
|
fn bitxor(self, other: U32x4) -> U32x4 {
|
||||||
|
unsafe {
|
||||||
|
U32x4(x86_64::_mm_xor_si128(self.0, other.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 8-bit unsigned integers
|
// 8-bit unsigned integers
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
|
@ -5,7 +5,6 @@ edition = "2018"
|
||||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
euclid = "0.19"
|
|
||||||
lyon_path = "0.12"
|
lyon_path = "0.12"
|
||||||
usvg = "0.4"
|
usvg = "0.4"
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
|
|
||||||
//! Converts a subset of SVG to a Pathfinder scene.
|
//! Converts a subset of SVG to a Pathfinder scene.
|
||||||
|
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
|
||||||
use lyon_path::iterator::PathIter;
|
use lyon_path::iterator::PathIter;
|
||||||
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
use pathfinder_geometry::basic::point::Point2DF32;
|
||||||
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use pathfinder_geometry::basic::transform2d::{Transform2DF32, Transform2DF32PathIter};
|
use pathfinder_geometry::basic::transform2d::{Transform2DF32, Transform2DF32PathIter};
|
||||||
use pathfinder_geometry::monotonic::MonotonicConversionIter;
|
use pathfinder_geometry::monotonic::MonotonicConversionIter;
|
||||||
use pathfinder_geometry::outline::Outline;
|
use pathfinder_geometry::outline::Outline;
|
||||||
|
@ -78,7 +78,7 @@ fn process_node(scene: &mut Scene, node: &Node, transform: &Transform2DF32) {
|
||||||
let path = MonotonicConversionIter::new(path);
|
let path = MonotonicConversionIter::new(path);
|
||||||
let outline = Outline::from_segments(path);
|
let outline = Outline::from_segments(path);
|
||||||
|
|
||||||
scene.bounds = scene.bounds.union(outline.bounds());
|
scene.bounds = scene.bounds.union_rect(outline.bounds());
|
||||||
scene.objects.push(PathObject::new(
|
scene.objects.push(PathObject::new(
|
||||||
outline,
|
outline,
|
||||||
style,
|
style,
|
||||||
|
@ -101,7 +101,7 @@ fn process_node(scene: &mut Scene, node: &Node, transform: &Transform2DF32) {
|
||||||
let path = MonotonicConversionIter::new(path);
|
let path = MonotonicConversionIter::new(path);
|
||||||
let outline = Outline::from_segments(path);
|
let outline = Outline::from_segments(path);
|
||||||
|
|
||||||
scene.bounds = scene.bounds.union(outline.bounds());
|
scene.bounds = scene.bounds.union_rect(outline.bounds());
|
||||||
scene.objects.push(PathObject::new(
|
scene.objects.push(PathObject::new(
|
||||||
outline,
|
outline,
|
||||||
style,
|
style,
|
||||||
|
@ -135,12 +135,11 @@ impl PaintExt for Paint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> Rect<f32> {
|
fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> RectF32 {
|
||||||
Rect::new(
|
RectF32::new(
|
||||||
Point2D::new(rect.x, rect.y),
|
Point2DF32::new(rect.x as f32, rect.y as f32),
|
||||||
Size2D::new(rect.width, rect.height),
|
Point2DF32::new(rect.width as f32, rect.height as f32),
|
||||||
)
|
)
|
||||||
.to_f32()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usvg_transform_to_transform_2d(transform: &UsvgTransform) -> Transform2DF32 {
|
fn usvg_transform_to_transform_2d(transform: &UsvgTransform) -> Transform2DF32 {
|
||||||
|
|
Loading…
Reference in New Issue