wip
This commit is contained in:
parent
7da8bdef89
commit
938bd30a78
|
@ -90,19 +90,19 @@ fn main() {
|
||||||
let window_size = Size2D::new(drawable_width, drawable_height);
|
let window_size = Size2D::new(drawable_width, drawable_height);
|
||||||
|
|
||||||
let mut base_scene = load_scene(&options, &window_size);
|
let mut base_scene = load_scene(&options, &window_size);
|
||||||
let base_transform = Transform2DF32::from_scale(&Point2DF32::splat(1.0 / 800.0));
|
|
||||||
base_scene.transform(&base_transform);
|
|
||||||
|
|
||||||
while !exit {
|
while !exit {
|
||||||
let rotation = Transform3DF32::from_rotation(-camera_yaw, -camera_pitch, 0.0);
|
let rotation = Transform3DF32::from_rotation(-camera_yaw, -camera_pitch, 0.0);
|
||||||
camera_position = camera_position + rotation.transform_point(camera_velocity);
|
camera_position = camera_position + rotation.transform_point(camera_velocity);
|
||||||
|
|
||||||
let mut transform = Transform3DF32::from_perspective(FRAC_PI_4, 4.0 / 3.0, 0.01, 100.0);
|
let mut transform = Transform3DF32::from_perspective(FRAC_PI_4, 4.0 / 3.0, 0.01, 100.0);
|
||||||
transform =
|
transform = transform.post_mul(&Transform3DF32::from_rotation(camera_yaw,
|
||||||
transform.post_mul(&Transform3DF32::from_rotation(camera_yaw, camera_pitch, 0.0));
|
camera_pitch,
|
||||||
|
0.0));
|
||||||
transform = transform.post_mul(&Transform3DF32::from_translation(-camera_position.x(),
|
transform = transform.post_mul(&Transform3DF32::from_translation(-camera_position.x(),
|
||||||
-camera_position.y(),
|
-camera_position.y(),
|
||||||
-camera_position.z()));
|
-camera_position.z()));
|
||||||
|
transform = transform.post_mul(&Transform3DF32::from_scale(1.0 / 800.0, 1.0 / 800.0, 1.0));
|
||||||
let perspective = Perspective::new(&transform, &window_size);
|
let perspective = Perspective::new(&transform, &window_size);
|
||||||
|
|
||||||
let mut scene = base_scene.clone();
|
let mut scene = base_scene.clone();
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use crate::line_segment::LineSegmentF32;
|
use crate::line_segment::LineSegmentF32;
|
||||||
use crate::outline::{Contour, PointFlags};
|
use crate::outline::{Contour, PointFlags};
|
||||||
use crate::point::Point2DF32;
|
use crate::point::{Point2DF32, Point3DF32};
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use crate::simd::F32x4;
|
use crate::simd::F32x4;
|
||||||
use crate::util::lerp;
|
use crate::util::lerp;
|
||||||
|
@ -353,3 +353,82 @@ enum EdgeRelativeLocation {
|
||||||
Inside,
|
Inside,
|
||||||
Outside,
|
Outside,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3D quad clipping
|
||||||
|
|
||||||
|
pub struct PolygonClipper3D {
|
||||||
|
subject: Vec<Point3DF32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolygonClipper3D {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(subject: Vec<Point3DF32>) -> PolygonClipper3D {
|
||||||
|
PolygonClipper3D { subject }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clip(mut self) -> Vec<Point3DF32> {
|
||||||
|
// TODO(pcwalton): Fast path for completely contained polygon?
|
||||||
|
|
||||||
|
self.clip_against(Edge3D::Left);
|
||||||
|
self.clip_against(Edge3D::Right);
|
||||||
|
self.clip_against(Edge3D::Bottom);
|
||||||
|
self.clip_against(Edge3D::Top);
|
||||||
|
self.clip_against(Edge3D::Near);
|
||||||
|
self.clip_against(Edge3D::Far);
|
||||||
|
|
||||||
|
self.subject
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clip_against(&mut self, edge: Edge3D) {
|
||||||
|
let input = mem::replace(&mut self.subject, vec![]);
|
||||||
|
let mut prev = match input.last() {
|
||||||
|
None => return,
|
||||||
|
Some(point) => *point,
|
||||||
|
};
|
||||||
|
for next in input {
|
||||||
|
if edge.point_is_inside(next) {
|
||||||
|
if !edge.point_is_inside(prev) {
|
||||||
|
self.subject.push(edge.line_intersection(prev, next));
|
||||||
|
}
|
||||||
|
self.subject.push(next);
|
||||||
|
} else if edge.point_is_inside(prev) {
|
||||||
|
self.subject.push(edge.line_intersection(prev, next));
|
||||||
|
}
|
||||||
|
prev = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum Edge3D {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Bottom,
|
||||||
|
Top,
|
||||||
|
Near,
|
||||||
|
Far
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Edge3D {
|
||||||
|
#[inline]
|
||||||
|
fn point_is_inside(self, point: Point3DF32) -> bool {
|
||||||
|
match self {
|
||||||
|
Edge3D::Left => point.x() > -1.0, Edge3D::Right => point.x() < 1.0,
|
||||||
|
Edge3D::Bottom => point.y() > -1.0, Edge3D::Top => point.y() < 1.0,
|
||||||
|
Edge3D::Near => point.z() > -1.0, Edge3D::Far => point.z() < 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_intersection(self, prev: Point3DF32, next: Point3DF32) -> Point3DF32 {
|
||||||
|
let (x0, x1) = match self {
|
||||||
|
Edge3D::Left | Edge3D::Right => (prev.x(), next.x()),
|
||||||
|
Edge3D::Bottom | Edge3D::Top => (prev.y(), next.y()),
|
||||||
|
Edge3D::Near | Edge3D::Far => (prev.z(), next.z()),
|
||||||
|
};
|
||||||
|
let x = match self {
|
||||||
|
Edge3D::Left | Edge3D::Bottom | Edge3D::Near => -1.0,
|
||||||
|
Edge3D::Right | Edge3D::Top | Edge3D::Far => 1.0,
|
||||||
|
};
|
||||||
|
prev.lerp(next, (x0 - x) / (x1 - x0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub struct LineSegmentF32(pub F32x4);
|
||||||
impl LineSegmentF32 {
|
impl LineSegmentF32 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(from: &Point2DF32, to: &Point2DF32) -> LineSegmentF32 {
|
pub fn new(from: &Point2DF32, to: &Point2DF32) -> LineSegmentF32 {
|
||||||
LineSegmentF32(from.0.as_f64x2().interleave(to.0.as_f64x2()).0.as_f32x4())
|
LineSegmentF32(from.0.combine_axaybxby(to.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -36,12 +36,12 @@ impl LineSegmentF32 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_from(&mut self, point: &Point2DF32) {
|
pub fn set_from(&mut self, point: &Point2DF32) {
|
||||||
self.0 = point.0.as_f64x2().combine_low_high(self.0.as_f64x2()).as_f32x4()
|
self.0 = point.0.combine_axaybzbw(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_to(&mut self, point: &Point2DF32) {
|
pub fn set_to(&mut self, point: &Point2DF32) {
|
||||||
self.0 = self.0.as_f64x2().interleave(point.0.as_f64x2()).0.as_f32x4()
|
self.0 = self.0.combine_axaybxby(point.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
|
@ -97,8 +97,8 @@ impl LineSegmentF32 {
|
||||||
let (from_from, to_to) = (self.0.xyxy(), self.0.zwzw());
|
let (from_from, to_to) = (self.0.xyxy(), self.0.zwzw());
|
||||||
let d_d = to_to - from_from;
|
let d_d = to_to - from_from;
|
||||||
let mid_mid = from_from + d_d * F32x4::splat(t);
|
let mid_mid = from_from + d_d * F32x4::splat(t);
|
||||||
(LineSegmentF32(from_from.as_f64x2().interleave(mid_mid.as_f64x2()).0.as_f32x4()),
|
(LineSegmentF32(from_from.combine_axaybxby(mid_mid)),
|
||||||
LineSegmentF32(mid_mid.as_f64x2().interleave(to_to.as_f64x2()).0.as_f32x4()))
|
LineSegmentF32(mid_mid.combine_axaybxby(to_to)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the left segment first, followed by the right segment.
|
// Returns the left segment first, followed by the right segment.
|
||||||
|
|
|
@ -302,7 +302,7 @@ impl Contour {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn apply_perspective(&mut self, perspective: &Perspective) {
|
pub fn apply_perspective(&mut self, perspective: &Perspective) {
|
||||||
for (point_index, point) in self.points.iter_mut().enumerate() {
|
for (point_index, point) in self.points.iter_mut().enumerate() {
|
||||||
*point = perspective.transform_point(point);
|
*point = perspective.transform_point_2d(point);
|
||||||
union_rect(&mut self.bounds, *point, point_index == 0);
|
union_rect(&mut self.bounds, *point, point_index == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,55 @@ impl Mul<Point2DF32> for Point2DF32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3D points.
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||||
|
pub struct Point3DF32(pub F32x4);
|
||||||
|
|
||||||
|
impl Point3DF32 {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(x: f32, y: f32, z: f32) -> Point3DF32 {
|
||||||
|
Point3DF32(F32x4::new(x, y, z, 1.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_euclid_2d(point: &Point2D<f32>) -> Point3DF32 {
|
||||||
|
Point3DF32::new(point.x, point.y, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn x(self) -> f32 {
|
||||||
|
self.0[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn y(self) -> f32 {
|
||||||
|
self.0[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn z(self) -> f32 {
|
||||||
|
self.0[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_2d(self) -> Point2DF32 {
|
||||||
|
Point2DF32(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_4d(self) -> Point4DF32 {
|
||||||
|
let mut point = Point4DF32(self.0);
|
||||||
|
point.set_w(1.0);
|
||||||
|
point
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn lerp(self, other: Point3DF32, t: f32) -> Point3DF32 {
|
||||||
|
Point3DF32(self.0 + (other.0 - self.0) * F32x4::splat(t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 3D homogeneous points.
|
// 3D homogeneous points.
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||||
|
@ -167,8 +216,13 @@ impl Point4DF32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn perspective_divide(self) -> Point4DF32 {
|
pub fn perspective_divide(self) -> Point3DF32 {
|
||||||
self * Point4DF32::splat(1.0 / self.w())
|
Point3DF32(self.0 * F32x4::splat(1.0 / self.w()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn approx_eq(&self, other: &Point4DF32, epsilon: f32) -> bool {
|
||||||
|
self.0.approx_eq(other.0, epsilon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,12 +196,12 @@ impl<'s> CubicSegment<'s> {
|
||||||
let tttt = F32x4::splat(t);
|
let tttt = F32x4::splat(t);
|
||||||
|
|
||||||
let (p0p3, p1p2) = (self.0.baseline.0, self.0.ctrl.0);
|
let (p0p3, p1p2) = (self.0.baseline.0, self.0.ctrl.0);
|
||||||
let p0p1 = p0p3.as_f64x2().interleave(p1p2.as_f64x2()).0.as_f32x4();
|
let p0p1 = p0p3.combine_axaybxby(p1p2);
|
||||||
|
|
||||||
// p01 = lerp(p0, p1, t), p12 = lerp(p1, p2, t), p23 = lerp(p2, p3, t)
|
// p01 = lerp(p0, p1, t), p12 = lerp(p1, p2, t), p23 = lerp(p2, p3, t)
|
||||||
let p01p12 = p0p1 + tttt * (p1p2 - p0p1);
|
let p01p12 = p0p1 + tttt * (p1p2 - p0p1);
|
||||||
let pxxp23 = p1p2 + tttt * (p0p3 - p1p2);
|
let pxxp23 = p1p2 + tttt * (p0p3 - p1p2);
|
||||||
let p12p23 = p01p12.as_f64x2().interleave(pxxp23.as_f64x2()).1.as_f32x4();
|
let p12p23 = p01p12.combine_azawbzbw(pxxp23);
|
||||||
|
|
||||||
// p012 = lerp(p01, p12, t), p123 = lerp(p12, p23, t)
|
// p012 = lerp(p01, p12, t), p123 = lerp(p12, p23, t)
|
||||||
let p012p123 = p01p12 + tttt * (p12p23 - p01p12);
|
let p012p123 = p01p12 + tttt * (p12p23 - p01p12);
|
||||||
|
@ -210,10 +210,10 @@ impl<'s> CubicSegment<'s> {
|
||||||
// p0123 = lerp(p012, p123, t)
|
// p0123 = lerp(p012, p123, t)
|
||||||
let p0123 = p012p123 + tttt * (p123 - p012p123);
|
let p0123 = p012p123 + tttt * (p123 - p012p123);
|
||||||
|
|
||||||
let baseline0 = p0p3.as_f64x2().interleave(p0123.as_f64x2()).0.as_f32x4();
|
let baseline0 = p0p3.combine_axaybxby(p0123);
|
||||||
let ctrl0 = p01p12.as_f64x2().interleave(p012p123.as_f64x2()).0.as_f32x4();
|
let ctrl0 = p01p12.combine_axaybxby(p012p123);
|
||||||
let baseline1 = p0123.as_f64x2().combine_low_high(p0p3.as_f64x2()).as_f32x4();
|
let baseline1 = p0123.combine_axaybzbw(p0p3);
|
||||||
let ctrl1 = p012p123.as_f64x2().interleave(p12p23.as_f64x2()).1.as_f32x4();
|
let ctrl1 = p012p123.combine_azawbzbw(p12p23);
|
||||||
|
|
||||||
(Segment {
|
(Segment {
|
||||||
baseline: LineSegmentF32(baseline0),
|
baseline: LineSegmentF32(baseline0),
|
||||||
|
|
|
@ -337,11 +337,11 @@ mod scalar {
|
||||||
|
|
||||||
#[cfg(all(not(feature = "pf-no-simd"), any(target_arch = "x86", target_arch = "x86_64")))]
|
#[cfg(all(not(feature = "pf-no-simd"), any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
mod x86 {
|
mod x86 {
|
||||||
use std::arch::x86_64::{self, __m128, __m128d, __m128i};
|
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, Sub};
|
use std::ops::{Add, AddAssign, Index, IndexMut, Mul, Neg, Sub};
|
||||||
|
|
||||||
// 32-bit floats
|
// 32-bit floats
|
||||||
|
|
||||||
|
@ -372,6 +372,14 @@ mod x86 {
|
||||||
unsafe { F32x4(x86_64::_mm_max_ps(self.0, other.0)) }
|
unsafe { F32x4(x86_64::_mm_max_ps(self.0, other.0)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn abs(self) -> F32x4 {
|
||||||
|
unsafe {
|
||||||
|
let tmp = x86_64::_mm_srli_epi32(I32x4::splat(-1).0, 1);
|
||||||
|
F32x4(x86_64::_mm_and_ps(x86_64::_mm_castsi128_ps(tmp), self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn packed_eq(self, other: F32x4) -> U32x4 {
|
pub fn packed_eq(self, other: F32x4) -> U32x4 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -381,13 +389,18 @@ mod x86 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Casts these packed floats to 64-bit floats.
|
|
||||||
//
|
|
||||||
// NB: This is a pure bitcast and does no actual conversion; only use this if you know what
|
|
||||||
// you're doing.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_f64x2(self) -> F64x2 {
|
pub fn packed_gt(self, other: F32x4) -> U32x4 {
|
||||||
unsafe { F64x2(x86_64::_mm_castps_pd(self.0)) }
|
unsafe {
|
||||||
|
U32x4(x86_64::_mm_castps_si128(x86_64::_mm_cmpgt_ps(
|
||||||
|
self.0, other.0,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn approx_eq(self, other: F32x4, epsilon: f32) -> bool {
|
||||||
|
(self - other).abs().packed_gt(F32x4::splat(epsilon)).is_all_zeroes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts these packed floats to integers.
|
// Converts these packed floats to integers.
|
||||||
|
@ -403,6 +416,11 @@ mod x86 {
|
||||||
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b0101_0000)) }
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b0101_0000)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xxzz(self) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b1010_0000)) }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn xyxy(self) -> F32x4 {
|
pub fn xyxy(self) -> F32x4 {
|
||||||
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b0100_0100)) }
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b0100_0100)) }
|
||||||
|
@ -433,6 +451,11 @@ mod x86 {
|
||||||
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b1011_0001)) }
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b1011_0001)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yyww(self) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b1111_0101)) }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn yzxw(self) -> F32x4 {
|
pub fn yzxw(self) -> F32x4 {
|
||||||
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b1100_1001)) }
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b1100_1001)) }
|
||||||
|
@ -474,15 +497,60 @@ mod x86 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn interleave(self, other: F32x4) -> (F32x4, F32x4) {
|
pub fn wyzx(self) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, self.0, 0b0010_0111)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn combine_axbxayby(self, other: F32x4) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_unpacklo_ps(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn combine_axaybxby(self, other: F32x4) -> F32x4 {
|
||||||
unsafe {
|
unsafe {
|
||||||
(
|
let this = x86_64::_mm_castps_pd(self.0);
|
||||||
F32x4(x86_64::_mm_unpacklo_ps(self.0, other.0)),
|
let other = x86_64::_mm_castps_pd(other.0);
|
||||||
F32x4(x86_64::_mm_unpackhi_ps(self.0, other.0)),
|
let result = x86_64::_mm_unpacklo_pd(this, other);
|
||||||
)
|
F32x4(x86_64::_mm_castpd_ps(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn combine_axaybzbw(self, other: F32x4) -> F32x4 {
|
||||||
|
unsafe {
|
||||||
|
let this = x86_64::_mm_castps_pd(self.0);
|
||||||
|
let other = x86_64::_mm_castps_pd(other.0);
|
||||||
|
let result = x86_64::_mm_shuffle_pd(this, other, 0b10);
|
||||||
|
F32x4(x86_64::_mm_castpd_ps(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn combine_axazbxbz(self, other: F32x4) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, other.0, 0b1000_1000)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn combine_ayawbybw(self, other: F32x4) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, other.0, 0b1101_1101)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn combine_azawbzbw(self, other: F32x4) -> F32x4 {
|
||||||
|
unsafe {
|
||||||
|
let this = x86_64::_mm_castps_pd(self.0);
|
||||||
|
let other = x86_64::_mm_castps_pd(other.0);
|
||||||
|
let result = x86_64::_mm_unpackhi_pd(this, other);
|
||||||
|
F32x4(x86_64::_mm_castpd_ps(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn combine_azbzawbw(self, other: F32x4) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_unpackhi_ps(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transpose_4x4(a: &mut F32x4, b: &mut F32x4, c: &mut F32x4, d: &mut F32x4) {
|
pub fn transpose_4x4(a: &mut F32x4, b: &mut F32x4, c: &mut F32x4, d: &mut F32x4) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -490,6 +558,7 @@ mod x86 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(pcwalton): Move to `Point4DF32`!
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cross(&self, other: F32x4) -> F32x4 {
|
pub fn cross(&self, other: F32x4) -> F32x4 {
|
||||||
self.yzxw() * other.zxyw() - self.zxyw() * other.yzxw()
|
self.yzxw() * other.zxyw() - self.zxyw() * other.yzxw()
|
||||||
|
@ -563,10 +632,19 @@ mod x86 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 64-bit floats
|
impl Neg for F32x4 {
|
||||||
|
type Output = F32x4;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self) -> F32x4 {
|
||||||
|
F32x4::default() - self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Two pairs of 32-bit floats
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct F64x2(pub __m128d);
|
pub struct F64x2x2(pub __m128d);
|
||||||
|
|
||||||
impl F64x2 {
|
impl F64x2 {
|
||||||
// Shuffles
|
// Shuffles
|
||||||
|
@ -600,6 +678,7 @@ mod x86 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// 32-bit signed integers
|
// 32-bit signed integers
|
||||||
|
|
||||||
|
@ -657,6 +736,11 @@ mod x86 {
|
||||||
fn is_all_ones(&self) -> bool {
|
fn is_all_ones(&self) -> bool {
|
||||||
unsafe { x86_64::_mm_test_all_ones(self.0) != 0 }
|
unsafe { x86_64::_mm_test_all_ones(self.0) != 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_all_zeroes(&self) -> bool {
|
||||||
|
unsafe { x86_64::_mm_test_all_zeros(self.0, self.0) != 0 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for U32x4 {
|
impl Index<usize> for U32x4 {
|
||||||
|
|
|
@ -13,14 +13,89 @@
|
||||||
use crate::point::Point2DF32;
|
use crate::point::Point2DF32;
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use crate::simd::F32x4;
|
use crate::simd::F32x4;
|
||||||
|
use crate::transform3d::Transform3DF32;
|
||||||
use euclid::{Point2D, Rect, Size2D, Transform2D};
|
use euclid::{Point2D, Rect, Size2D, Transform2D};
|
||||||
use lyon_path::PathEvent;
|
use lyon_path::PathEvent;
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
|
/// A 2x2 matrix, optimized with SIMD, in column-major order.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Matrix2x2F32(pub F32x4);
|
||||||
|
|
||||||
|
impl Default for Matrix2x2F32 {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Matrix2x2F32 {
|
||||||
|
Self::from_scale(&Point2DF32::splat(1.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Matrix2x2F32 {
|
||||||
|
#[inline]
|
||||||
|
pub fn from_scale(scale: &Point2DF32) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(F32x4::new(scale.x(), 0.0, 0.0, scale.y()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_rotation(theta: f32) -> Matrix2x2F32 {
|
||||||
|
let (sin_theta, cos_theta) = (theta.sin(), theta.cos());
|
||||||
|
Matrix2x2F32(F32x4::new(cos_theta, sin_theta, -sin_theta, cos_theta))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(F32x4::new(m11, m21, m12, m22))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn post_mul(&self, other: &Matrix2x2F32) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.0.xyxy() * other.0.xxzz() + self.0.zwzw() * other.0.yyww())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn pre_mul(&self, other: &Matrix2x2F32) -> Matrix2x2F32 {
|
||||||
|
other.post_mul(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn entrywise_mul(&self, other: &Matrix2x2F32) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.0 * other.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn adjugate(&self) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.0.wyzx() * F32x4::new(1.0, -1.0, -1.0, 1.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn transform_point(&self, point: &Point2DF32) -> Point2DF32 {
|
||||||
|
let halves = self.0 * point.0.xxyy();
|
||||||
|
Point2DF32(halves + halves.zwzw())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn det(&self) -> f32 {
|
||||||
|
self.0[0] * self.0[3] - self.0[2] * self.0[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn inverse(&self) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(F32x4::splat(1.0 / self.det()) * self.adjugate().0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<Matrix2x2F32> for Matrix2x2F32 {
|
||||||
|
type Output = Matrix2x2F32;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: Matrix2x2F32) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.0 - other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An affine transform, optimized with SIMD.
|
/// An affine transform, optimized with SIMD.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Transform2DF32 {
|
pub struct Transform2DF32 {
|
||||||
// Row-major order.
|
// Row-major order.
|
||||||
matrix: F32x4,
|
matrix: Matrix2x2F32,
|
||||||
vector: Point2DF32,
|
vector: Point2DF32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,16 +110,15 @@ impl Transform2DF32 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_scale(scale: &Point2DF32) -> Transform2DF32 {
|
pub fn from_scale(scale: &Point2DF32) -> Transform2DF32 {
|
||||||
Transform2DF32 {
|
Transform2DF32 {
|
||||||
matrix: F32x4::new(scale.x(), 0.0, 0.0, scale.y()),
|
matrix: Matrix2x2F32::from_scale(scale),
|
||||||
vector: Point2DF32::default(),
|
vector: Point2DF32::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_rotation(theta: f32) -> Transform2DF32 {
|
pub fn from_rotation(theta: f32) -> Transform2DF32 {
|
||||||
let (sin_theta, cos_theta) = (theta.sin(), theta.cos());
|
|
||||||
Transform2DF32 {
|
Transform2DF32 {
|
||||||
matrix: F32x4::new(cos_theta, -sin_theta, sin_theta, cos_theta),
|
matrix: Matrix2x2F32::from_rotation(theta),
|
||||||
vector: Point2DF32::default(),
|
vector: Point2DF32::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +126,7 @@ impl Transform2DF32 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_translation(vector: &Point2DF32) -> Transform2DF32 {
|
pub fn from_translation(vector: &Point2DF32) -> Transform2DF32 {
|
||||||
Transform2DF32 {
|
Transform2DF32 {
|
||||||
matrix: F32x4::new(1.0, 0.0, 0.0, 1.0),
|
matrix: Matrix2x2F32::default(),
|
||||||
vector: *vector,
|
vector: *vector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,15 +135,14 @@ impl Transform2DF32 {
|
||||||
pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32)
|
pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32)
|
||||||
-> Transform2DF32 {
|
-> Transform2DF32 {
|
||||||
Transform2DF32 {
|
Transform2DF32 {
|
||||||
matrix: F32x4::new(m11, m12, m21, m22),
|
matrix: Matrix2x2F32::row_major(m11, m12, m21, m22),
|
||||||
vector: Point2DF32::new(m31, m32),
|
vector: Point2DF32::new(m31, m32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_point(&self, point: &Point2DF32) -> Point2DF32 {
|
pub fn transform_point(&self, point: &Point2DF32) -> Point2DF32 {
|
||||||
let bxbzbybw = point.0.xxyy() * self.matrix.xzyw();
|
self.matrix.transform_point(point) + self.vector
|
||||||
Point2DF32(bxbzbybw + bxbzbybw.zwzw() + self.vector.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): SIMD.
|
// TODO(pcwalton): SIMD.
|
||||||
|
@ -89,9 +162,7 @@ impl Transform2DF32 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn post_mul(&self, other: &Transform2DF32) -> Transform2DF32 {
|
pub fn post_mul(&self, other: &Transform2DF32) -> Transform2DF32 {
|
||||||
let lhs = self.matrix.xwxw() * other.matrix;
|
let matrix = self.matrix.post_mul(&other.matrix);
|
||||||
let rhs = self.matrix.zyzy() * other.matrix.yxwz();
|
|
||||||
let matrix = lhs + rhs;
|
|
||||||
let vector = other.transform_point(&self.vector);
|
let vector = other.transform_point(&self.vector);
|
||||||
Transform2DF32 { matrix, vector }
|
Transform2DF32 { matrix, vector }
|
||||||
}
|
}
|
||||||
|
@ -100,6 +171,15 @@ impl Transform2DF32 {
|
||||||
pub fn pre_mul(&self, other: &Transform2DF32) -> Transform2DF32 {
|
pub fn pre_mul(&self, other: &Transform2DF32) -> Transform2DF32 {
|
||||||
other.post_mul(self)
|
other.post_mul(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(pcwalton): Optimize better with SIMD.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_3d(&self) -> Transform3DF32 {
|
||||||
|
Transform3DF32::row_major(self.matrix.0[0], self.matrix.0[1], 0.0, self.vector.x(),
|
||||||
|
self.matrix.0[2], self.matrix.0[3], 0.0, self.vector.y(),
|
||||||
|
0.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transforms a path with a SIMD 2D transform.
|
/// Transforms a path with a SIMD 2D transform.
|
||||||
|
|
|
@ -10,10 +10,12 @@
|
||||||
|
|
||||||
//! 3D transforms that can be applied to paths.
|
//! 3D transforms that can be applied to paths.
|
||||||
|
|
||||||
use crate::point::{Point2DF32, Point4DF32};
|
use crate::point::{Point2DF32, Point3DF32, Point4DF32};
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use crate::simd::F32x4;
|
use crate::simd::F32x4;
|
||||||
|
use crate::transform::Matrix2x2F32;
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
|
use std::ops::{Add, Neg};
|
||||||
|
|
||||||
/// An transform, optimized with SIMD.
|
/// An transform, optimized with SIMD.
|
||||||
///
|
///
|
||||||
|
@ -121,6 +123,21 @@ impl Transform3DF32 {
|
||||||
0.0, 0.0, m32, 0.0)
|
0.0, 0.0, m32, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +- -+
|
||||||
|
// | A B |
|
||||||
|
// | C D |
|
||||||
|
// +- -+
|
||||||
|
#[inline]
|
||||||
|
pub fn from_submatrices(a: Matrix2x2F32, b: Matrix2x2F32, c: Matrix2x2F32, d: Matrix2x2F32)
|
||||||
|
-> Transform3DF32 {
|
||||||
|
Transform3DF32 {
|
||||||
|
c0: a.0.combine_axaybxby(c.0),
|
||||||
|
c1: a.0.combine_azawbzbw(c.0),
|
||||||
|
c2: b.0.combine_axaybxby(d.0),
|
||||||
|
c3: b.0.combine_azawbzbw(d.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transpose(&self) -> Transform3DF32 {
|
pub fn transpose(&self) -> Transform3DF32 {
|
||||||
let mut m = *self;
|
let mut m = *self;
|
||||||
|
@ -161,6 +178,69 @@ impl Transform3DF32 {
|
||||||
let term3 = self.c3 * F32x4::splat(point.w());
|
let term3 = self.c3 * F32x4::splat(point.w());
|
||||||
Point4DF32(term0 + term1 + term2 + term3)
|
Point4DF32(term0 + term1 + term2 + term3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn upper_left(&self) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.c0.combine_axaybxby(self.c1))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn upper_right(&self) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.c2.combine_axaybxby(self.c3))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn lower_left(&self) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.c0.combine_azawbzbw(self.c1))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn lower_right(&self) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.c2.combine_azawbzbw(self.c3))
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion
|
||||||
|
pub fn inverse(&self) -> Transform3DF32 {
|
||||||
|
// Extract submatrices.
|
||||||
|
let (a, b) = (self.upper_left(), self.upper_right());
|
||||||
|
let (c, d) = (self.lower_left(), self.lower_right());
|
||||||
|
|
||||||
|
// Compute temporary matrices.
|
||||||
|
let a_inv = a.inverse();
|
||||||
|
let x = c.post_mul(&a_inv);
|
||||||
|
let y = (d - x.post_mul(&b)).inverse();
|
||||||
|
let z = a_inv.post_mul(&b);
|
||||||
|
|
||||||
|
// Compute new submatrices.
|
||||||
|
let (a_new, b_new) = (a_inv + z.post_mul(&y).post_mul(&x), (-z).post_mul(&y));
|
||||||
|
let (c_new, d_new) = ((-y).post_mul(&x), y);
|
||||||
|
|
||||||
|
// Construct inverse.
|
||||||
|
Transform3DF32::from_submatrices(a_new, b_new, c_new, d_new)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn approx_eq(&self, other: &Transform3DF32, epsilon: f32) -> bool {
|
||||||
|
self.c0.approx_eq(other.c0, epsilon) &&
|
||||||
|
self.c1.approx_eq(other.c1, epsilon) &&
|
||||||
|
self.c2.approx_eq(other.c2, epsilon) &&
|
||||||
|
self.c3.approx_eq(other.c3, epsilon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Matrix2x2F32> for Matrix2x2F32 {
|
||||||
|
type Output = Matrix2x2F32;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: Matrix2x2F32) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(self.0 + other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Matrix2x2F32 {
|
||||||
|
type Output = Matrix2x2F32;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self) -> Matrix2x2F32 {
|
||||||
|
Matrix2x2F32(-self.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
@ -176,20 +256,25 @@ impl Perspective {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_point(&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_4d()).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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn transform_point_3d(&self, point: &Point3DF32) -> Point3DF32 {
|
||||||
|
self.transform.transform_point(point.to_4d()).perspective_divide()
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): SIMD?
|
// TODO(pcwalton): SIMD?
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_rect(&self, rect: &Rect<f32>) -> Rect<f32> {
|
pub fn transform_rect(&self, rect: &Rect<f32>) -> Rect<f32> {
|
||||||
let upper_left = self.transform_point(&Point2DF32::from_euclid(rect.origin));
|
let upper_left = self.transform_point_2d(&Point2DF32::from_euclid(rect.origin));
|
||||||
let upper_right = self.transform_point(&Point2DF32::from_euclid(rect.top_right()));
|
let upper_right = self.transform_point_2d(&Point2DF32::from_euclid(rect.top_right()));
|
||||||
let lower_left = self.transform_point(&Point2DF32::from_euclid(rect.bottom_left()));
|
let lower_left = self.transform_point_2d(&Point2DF32::from_euclid(rect.bottom_left()));
|
||||||
let lower_right = self.transform_point(&Point2DF32::from_euclid(rect.bottom_right()));
|
let lower_right = self.transform_point_2d(&Point2DF32::from_euclid(rect.bottom_right()));
|
||||||
let min_x = upper_left.x().min(upper_right.x()).min(lower_left.x()).min(lower_right.x());
|
let min_x = upper_left.x().min(upper_right.x()).min(lower_left.x()).min(lower_right.x());
|
||||||
let min_y = upper_left.y().min(upper_right.y()).min(lower_left.y()).min(lower_right.y());
|
let min_y = upper_left.y().min(upper_right.y()).min(lower_left.y()).min(lower_right.y());
|
||||||
let max_x = upper_left.x().max(upper_right.x()).max(lower_left.x()).max(lower_right.x());
|
let max_x = upper_left.x().max(upper_right.x()).max(lower_left.x()).max(lower_right.x());
|
||||||
|
@ -218,12 +303,13 @@ where
|
||||||
fn next(&mut self) -> Option<Segment> {
|
fn next(&mut self) -> Option<Segment> {
|
||||||
let mut segment = self.iter.next()?;
|
let mut segment = self.iter.next()?;
|
||||||
if !segment.is_none() {
|
if !segment.is_none() {
|
||||||
segment.baseline.set_from(&self.perspective.transform_point(&segment.baseline.from()));
|
segment.baseline.set_from(&self.perspective
|
||||||
segment.baseline.set_to(&self.perspective.transform_point(&segment.baseline.to()));
|
.transform_point_2d(&segment.baseline.from()));
|
||||||
|
segment.baseline.set_to(&self.perspective.transform_point_2d(&segment.baseline.to()));
|
||||||
if !segment.is_line() {
|
if !segment.is_line() {
|
||||||
segment.ctrl.set_from(&self.perspective.transform_point(&segment.ctrl.from()));
|
segment.ctrl.set_from(&self.perspective.transform_point_2d(&segment.ctrl.from()));
|
||||||
if !segment.is_quadratic() {
|
if !segment.is_quadratic() {
|
||||||
segment.ctrl.set_to(&self.perspective.transform_point(&segment.ctrl.to()));
|
segment.ctrl.set_to(&self.perspective.transform_point_2d(&segment.ctrl.to()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,4 +389,24 @@ mod test {
|
||||||
5.0, 5.0, 9.0, 2.0);
|
5.0, 5.0, 9.0, 2.0);
|
||||||
assert_eq!(a.transpose(), b);
|
assert_eq!(a.transpose(), b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inverse() {
|
||||||
|
// Random matrix.
|
||||||
|
let m = Transform3DF32::row_major(0.86277982, 0.15986552, 0.90739898, 0.60066808,
|
||||||
|
0.17386167, 0.016353 , 0.8535783 , 0.12969608,
|
||||||
|
0.0946466 , 0.43248631, 0.63480505, 0.08154603,
|
||||||
|
0.50305436, 0.48359687, 0.51057162, 0.24812012);
|
||||||
|
let p0 = Point4DF32::new(0.95536648, 0.80633691, 0.16357357, 0.5477598);
|
||||||
|
let p1 = m.transform_point(p0);
|
||||||
|
let m_inv = m.inverse();
|
||||||
|
let m_inv_exp =
|
||||||
|
Transform3DF32::row_major(-2.47290136 , 3.48865688, -6.12298336 , 6.17536696 ,
|
||||||
|
0.00124033357, -1.72561993, 2.16876606 , 0.186227748,
|
||||||
|
-0.375021729 , 1.53883017, -0.0558194403, 0.121857058,
|
||||||
|
5.78300323 , -6.87635769, 8.30196620 , -9.10374060);
|
||||||
|
assert!(m_inv.approx_eq(&m_inv_exp, 0.0001));
|
||||||
|
let p2 = m_inv.transform_point(p1);
|
||||||
|
assert!(p0.approx_eq(&p2, 0.0001));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@ 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::clip::PolygonClipper3D;
|
||||||
use pathfinder_geometry::outline::Outline;
|
use pathfinder_geometry::outline::Outline;
|
||||||
|
use pathfinder_geometry::point::Point3DF32;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::transform::Transform2DF32;
|
use pathfinder_geometry::transform::Transform2DF32;
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
|
@ -117,6 +119,9 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_perspective(&mut self, perspective: &Perspective) {
|
pub fn apply_perspective(&mut self, perspective: &Perspective) {
|
||||||
|
let quad = self.clip_bounding_quad_with_perspective(perspective);
|
||||||
|
println!("bounds={:?} quad={:?}", self.bounds, quad);
|
||||||
|
|
||||||
let mut bounds = Rect::zero();
|
let mut bounds = Rect::zero();
|
||||||
for (object_index, object) in self.objects.iter_mut().enumerate() {
|
for (object_index, object) in self.objects.iter_mut().enumerate() {
|
||||||
object.outline.apply_perspective(perspective);
|
object.outline.apply_perspective(perspective);
|
||||||
|
@ -132,6 +137,19 @@ impl Scene {
|
||||||
//println!("new bounds={:?}", bounds);
|
//println!("new bounds={:?}", bounds);
|
||||||
self.bounds = bounds;
|
self.bounds = bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clip_bounding_quad_with_perspective(&self, perspective: &Perspective) -> Vec<Point3DF32> {
|
||||||
|
let mut points = vec![
|
||||||
|
Point3DF32::from_euclid_2d(&self.bounds.origin),
|
||||||
|
Point3DF32::from_euclid_2d(&self.bounds.top_right()),
|
||||||
|
Point3DF32::from_euclid_2d(&self.bounds.bottom_right()),
|
||||||
|
Point3DF32::from_euclid_2d(&self.bounds.bottom_left()),
|
||||||
|
];
|
||||||
|
for point in &mut points {
|
||||||
|
*point = perspective.transform_point_3d(point);
|
||||||
|
}
|
||||||
|
PolygonClipper3D::new(points).clip()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
Loading…
Reference in New Issue