Add window resizing support to the demo
This commit is contained in:
parent
a6963d5f3b
commit
a81850a899
|
@ -13,15 +13,16 @@ use euclid::Size2D;
|
||||||
use jemallocator;
|
use jemallocator;
|
||||||
use pathfinder_geometry::basic::point::{Point2DF32, Point3DF32};
|
use pathfinder_geometry::basic::point::{Point2DF32, Point3DF32};
|
||||||
use pathfinder_geometry::basic::rect::RectF32;
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
|
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
||||||
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::{RenderOptions, RenderTransform, SceneBuilder};
|
||||||
use pathfinder_renderer::gpu_data::BuiltScene;
|
use pathfinder_renderer::gpu_data::BuiltScene;
|
||||||
use pathfinder_renderer::scene::{BuildTransform, Scene};
|
use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_renderer::z_buffer::ZBuffer;
|
use pathfinder_renderer::z_buffer::ZBuffer;
|
||||||
use pathfinder_svg::SceneExt;
|
use pathfinder_svg::SceneExt;
|
||||||
use rayon::ThreadPoolBuilder;
|
use rayon::ThreadPoolBuilder;
|
||||||
use sdl2::event::Event;
|
use sdl2::event::{Event, WindowEvent};
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
use sdl2::video::GLProfile;
|
use sdl2::video::GLProfile;
|
||||||
use std::f32::consts::FRAC_PI_4;
|
use std::f32::consts::FRAC_PI_4;
|
||||||
|
@ -55,6 +56,7 @@ fn main() {
|
||||||
let window =
|
let window =
|
||||||
sdl_video.window("Pathfinder Demo", MAIN_FRAMEBUFFER_WIDTH, MAIN_FRAMEBUFFER_HEIGHT)
|
sdl_video.window("Pathfinder Demo", MAIN_FRAMEBUFFER_WIDTH, MAIN_FRAMEBUFFER_HEIGHT)
|
||||||
.opengl()
|
.opengl()
|
||||||
|
.resizable()
|
||||||
.allow_highdpi()
|
.allow_highdpi()
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -66,20 +68,20 @@ fn main() {
|
||||||
let mut exit = false;
|
let mut exit = false;
|
||||||
|
|
||||||
let (drawable_width, drawable_height) = window.drawable_size();
|
let (drawable_width, drawable_height) = window.drawable_size();
|
||||||
let mut renderer = Renderer::new(&Size2D::new(drawable_width, drawable_height));
|
let mut window_size = Size2D::new(drawable_width, drawable_height);
|
||||||
|
let mut renderer = Renderer::new(&window_size);
|
||||||
|
|
||||||
let mut camera_position = Point3DF32::new(500.0, 500.0, 3000.0, 1.0);
|
let mut camera_position = Point3DF32::new(500.0, 500.0, 3000.0, 1.0);
|
||||||
let mut camera_velocity = Point3DF32::new(0.0, 0.0, 0.0, 1.0);
|
let mut camera_velocity = Point3DF32::new(0.0, 0.0, 0.0, 1.0);
|
||||||
let (mut camera_yaw, mut camera_pitch) = (0.0, 0.0);
|
let (mut camera_yaw, mut camera_pitch) = (0.0, 0.0);
|
||||||
|
|
||||||
let window_size = Size2D::new(drawable_width, drawable_height);
|
let base_scene = load_scene(&options);
|
||||||
renderer.debug_renderer.set_framebuffer_size(&window_size);
|
|
||||||
|
|
||||||
let base_scene = load_scene(&options, &window_size);
|
|
||||||
let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone());
|
let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone());
|
||||||
|
scene_thread_proxy.set_window_size(&window_size);
|
||||||
|
|
||||||
let mut events = vec![];
|
let mut events = vec![];
|
||||||
let mut first_frame = true;
|
let mut first_frame = true;
|
||||||
|
let mut mouselook_enabled = false;
|
||||||
|
|
||||||
while !exit {
|
while !exit {
|
||||||
// Update the scene.
|
// Update the scene.
|
||||||
|
@ -87,8 +89,8 @@ fn main() {
|
||||||
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 =
|
let aspect = window_size.width as f32 / window_size.height as f32;
|
||||||
Transform3DF32::from_perspective(FRAC_PI_4, 4.0 / 3.0, 0.025, 100.0);
|
let mut transform = Transform3DF32::from_perspective(FRAC_PI_4, aspect, 0.025, 100.0);
|
||||||
|
|
||||||
transform = transform.post_mul(&Transform3DF32::from_scale(1.0 / 800.0,
|
transform = transform.post_mul(&Transform3DF32::from_scale(1.0 / 800.0,
|
||||||
1.0 / 800.0,
|
1.0 / 800.0,
|
||||||
|
@ -142,7 +144,14 @@ fn main() {
|
||||||
Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
||||||
exit = true;
|
exit = true;
|
||||||
}
|
}
|
||||||
Event::MouseMotion { xrel, yrel, .. } => {
|
Event::Window { win_event: WindowEvent::SizeChanged(..), .. } => {
|
||||||
|
let (window_width, window_height) = window.drawable_size();
|
||||||
|
window_size = Size2D::new(window_width as u32, window_height as u32);
|
||||||
|
scene_thread_proxy.set_window_size(&window_size);
|
||||||
|
renderer.set_main_framebuffer_size(&window_size);
|
||||||
|
}
|
||||||
|
Event::MouseButtonDown { .. } => mouselook_enabled = !mouselook_enabled,
|
||||||
|
Event::MouseMotion { xrel, yrel, .. } if mouselook_enabled => {
|
||||||
camera_yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED;
|
camera_yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED;
|
||||||
camera_pitch -= yrel as f32 * MOUSELOOK_ROTATION_SPEED;
|
camera_pitch -= yrel as f32 * MOUSELOOK_ROTATION_SPEED;
|
||||||
}
|
}
|
||||||
|
@ -192,6 +201,10 @@ impl SceneThreadProxy {
|
||||||
SceneThread::new(scene, scene_to_main_sender, main_to_scene_receiver, options);
|
SceneThread::new(scene, scene_to_main_sender, main_to_scene_receiver, options);
|
||||||
SceneThreadProxy { sender: main_to_scene_sender, receiver: scene_to_main_receiver }
|
SceneThreadProxy { sender: main_to_scene_sender, receiver: scene_to_main_receiver }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_window_size(&self, window_size: &Size2D<u32>) {
|
||||||
|
self.sender.send(MainToSceneMsg::SetWindowSize(*window_size)).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SceneThread {
|
struct SceneThread {
|
||||||
|
@ -209,9 +222,14 @@ impl SceneThread {
|
||||||
thread::spawn(move || (SceneThread { scene, sender, receiver, options }).run());
|
thread::spawn(move || (SceneThread { scene, sender, receiver, options }).run());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self) {
|
fn run(mut self) {
|
||||||
while let Ok(msg) = self.receiver.recv() {
|
while let Ok(msg) = self.receiver.recv() {
|
||||||
match msg {
|
match msg {
|
||||||
|
MainToSceneMsg::SetWindowSize(size) => {
|
||||||
|
self.scene.view_box =
|
||||||
|
RectF32::new(Point2DF32::default(),
|
||||||
|
Point2DF32::new(size.width as f32, size.height as f32));
|
||||||
|
}
|
||||||
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);
|
||||||
|
@ -224,6 +242,7 @@ impl SceneThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MainToSceneMsg {
|
enum MainToSceneMsg {
|
||||||
|
SetWindowSize(Size2D<u32>),
|
||||||
Build(Option<Perspective>),
|
Build(Option<Perspective>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,40 +298,29 @@ impl Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_scene(options: &Options, window_size: &Size2D<u32>) -> Scene {
|
fn load_scene(options: &Options) -> Scene {
|
||||||
// Build scene.
|
|
||||||
let usvg = Tree::from_file(&options.input_path, &UsvgOptions::default()).unwrap();
|
let usvg = Tree::from_file(&options.input_path, &UsvgOptions::default()).unwrap();
|
||||||
|
let scene = Scene::from_tree(usvg);
|
||||||
let mut scene = Scene::from_tree(usvg);
|
println!("Scene bounds: {:?}", scene.bounds);
|
||||||
scene.view_box =
|
println!("{} objects, {} paints", scene.objects.len(), scene.paints.len());
|
||||||
RectF32::new(Point2DF32::default(),
|
|
||||||
Point2DF32::new(window_size.width as f32, window_size.height as f32));
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Scene bounds: {:?} View box: {:?}",
|
|
||||||
scene.bounds, scene.view_box
|
|
||||||
);
|
|
||||||
println!(
|
|
||||||
"{} objects, {} paints",
|
|
||||||
scene.objects.len(),
|
|
||||||
scene.paints.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
scene
|
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 render_options = RenderOptions {
|
||||||
None => BuildTransform::None,
|
transform: match perspective {
|
||||||
Some(perspective) => BuildTransform::Perspective(perspective),
|
None => RenderTransform::Transform2D(Transform2DF32::default()),
|
||||||
|
Some(perspective) => RenderTransform::Perspective(perspective),
|
||||||
|
},
|
||||||
|
dilation: Point2DF32::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let built_objects = panic::catch_unwind(|| {
|
let built_objects = panic::catch_unwind(|| {
|
||||||
match options.jobs {
|
match options.jobs {
|
||||||
Some(1) => scene.build_objects_sequentially(&build_transform, &z_buffer),
|
Some(1) => scene.build_objects_sequentially(render_options, &z_buffer),
|
||||||
_ => scene.build_objects(&build_transform, &z_buffer),
|
_ => scene.build_objects(render_options, &z_buffer),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,11 @@ impl Point2DF32 {
|
||||||
pub fn yx(&self) -> Point2DF32 {
|
pub fn yx(&self) -> Point2DF32 {
|
||||||
Point2DF32(self.0.yxwz())
|
Point2DF32(self.0.yxwz())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_zero(&self) -> bool {
|
||||||
|
*self == Point2DF32::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Point2DF32 {
|
impl PartialEq for Point2DF32 {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
|
|
||||||
/// A 2x2 matrix, optimized with SIMD, in column-major order.
|
/// A 2x2 matrix, optimized with SIMD, in column-major order.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct Matrix2x2F32(pub F32x4);
|
pub struct Matrix2x2F32(pub F32x4);
|
||||||
|
|
||||||
impl Default for Matrix2x2F32 {
|
impl Default for Matrix2x2F32 {
|
||||||
|
@ -93,7 +93,7 @@ impl Sub<Matrix2x2F32> for Matrix2x2F32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An affine transform, optimized with SIMD.
|
/// An affine transform, optimized with SIMD.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct Transform2DF32 {
|
pub struct Transform2DF32 {
|
||||||
// Row-major order.
|
// Row-major order.
|
||||||
matrix: Matrix2x2F32,
|
matrix: Matrix2x2F32,
|
||||||
|
@ -177,6 +177,11 @@ impl Transform2DF32 {
|
||||||
0.0, 0.0, 0.0, 0.0,
|
0.0, 0.0, 0.0, 0.0,
|
||||||
0.0, 0.0, 0.0, 1.0)
|
0.0, 0.0, 0.0, 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_identity(&self) -> bool {
|
||||||
|
*self == Transform2DF32::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transforms a path with a SIMD 2D transform.
|
/// Transforms a path with a SIMD 2D transform.
|
||||||
|
|
|
@ -148,6 +148,11 @@ impl Renderer {
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: &Size2D<u32>) {
|
||||||
|
self.main_framebuffer_size = *new_framebuffer_size;
|
||||||
|
self.debug_renderer.set_framebuffer_size(new_framebuffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
fn upload_shaders(&mut self, shaders: &[ObjectShader]) {
|
fn upload_shaders(&mut self, shaders: &[ObjectShader]) {
|
||||||
let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT);
|
let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT);
|
||||||
let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4];
|
let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4];
|
||||||
|
|
|
@ -15,7 +15,11 @@ use crate::gpu_data::{MaskTileBatchPrimitive, SolidTileScenePrimitive};
|
||||||
use crate::scene;
|
use crate::scene;
|
||||||
use crate::tiles;
|
use crate::tiles;
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
|
use pathfinder_geometry::basic::point::Point2DF32;
|
||||||
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
||||||
|
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
||||||
|
use pathfinder_geometry::basic::transform3d::Perspective;
|
||||||
|
use pathfinder_geometry::clip::PolygonClipper3D;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
|
|
||||||
|
@ -117,3 +121,79 @@ impl SceneBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct RenderOptions {
|
||||||
|
pub transform: RenderTransform,
|
||||||
|
pub dilation: Point2DF32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderOptions {
|
||||||
|
pub fn prepare(self, bounds: RectF32) -> PreparedRenderOptions {
|
||||||
|
PreparedRenderOptions {
|
||||||
|
transform: self.transform.prepare(bounds),
|
||||||
|
dilation: self.dilation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum RenderTransform {
|
||||||
|
Transform2D(Transform2DF32),
|
||||||
|
Perspective(Perspective),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RenderTransform {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> RenderTransform {
|
||||||
|
RenderTransform::Transform2D(Transform2DF32::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderTransform {
|
||||||
|
fn prepare(&self, bounds: RectF32) -> PreparedRenderTransform {
|
||||||
|
let perspective = match self {
|
||||||
|
RenderTransform::Transform2D(ref transform) => {
|
||||||
|
if transform.is_identity() {
|
||||||
|
return PreparedRenderTransform::None;
|
||||||
|
}
|
||||||
|
return PreparedRenderTransform::Transform2D(*transform);
|
||||||
|
}
|
||||||
|
RenderTransform::Perspective(ref perspective) => *perspective,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut points = vec![
|
||||||
|
bounds.origin().to_3d(),
|
||||||
|
bounds.upper_right().to_3d(),
|
||||||
|
bounds.lower_right().to_3d(),
|
||||||
|
bounds.lower_left().to_3d(),
|
||||||
|
];
|
||||||
|
//println!("-----");
|
||||||
|
//println!("bounds={:?} ORIGINAL quad={:?}", self.bounds, points);
|
||||||
|
for point in &mut points {
|
||||||
|
*point = perspective.transform.transform_point(*point);
|
||||||
|
}
|
||||||
|
//println!("... PERSPECTIVE quad={:?}", points);
|
||||||
|
points = PolygonClipper3D::new(points).clip();
|
||||||
|
//println!("... CLIPPED quad={:?}", points);
|
||||||
|
for point in &mut points {
|
||||||
|
*point = point.perspective_divide()
|
||||||
|
}
|
||||||
|
let inverse_transform = perspective.transform.inverse();
|
||||||
|
let clip_polygon = points.into_iter().map(|point| {
|
||||||
|
inverse_transform.transform_point(point).perspective_divide().to_2d()
|
||||||
|
}).collect();
|
||||||
|
PreparedRenderTransform::Perspective { perspective, clip_polygon }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PreparedRenderOptions {
|
||||||
|
pub transform: PreparedRenderTransform,
|
||||||
|
pub dilation: Point2DF32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PreparedRenderTransform {
|
||||||
|
None,
|
||||||
|
Transform2D(Transform2DF32),
|
||||||
|
Perspective { perspective: Perspective, clip_polygon: Vec<Point2DF32> }
|
||||||
|
}
|
||||||
|
|
|
@ -10,16 +10,13 @@
|
||||||
|
|
||||||
//! A set of paths to be rendered.
|
//! A set of paths to be rendered.
|
||||||
|
|
||||||
|
use crate::builder::{PreparedRenderOptions, PreparedRenderTransform, RenderOptions};
|
||||||
use crate::gpu_data::BuiltObject;
|
use crate::gpu_data::BuiltObject;
|
||||||
use crate::paint::{ObjectShader, Paint, PaintId, ShaderId};
|
use crate::paint::{ObjectShader, Paint, PaintId, ShaderId};
|
||||||
use crate::tiles::Tiler;
|
use crate::tiles::Tiler;
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
|
||||||
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
||||||
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
|
||||||
use pathfinder_geometry::basic::transform3d::Perspective;
|
|
||||||
use pathfinder_geometry::clip::PolygonClipper3D;
|
|
||||||
use pathfinder_geometry::outline::Outline;
|
use pathfinder_geometry::outline::Outline;
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
@ -66,14 +63,14 @@ impl Scene {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_objects_sequentially(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
|
pub fn build_objects_sequentially(&self, options: RenderOptions, z_buffer: &ZBuffer)
|
||||||
-> Vec<BuiltObject> {
|
-> Vec<BuiltObject> {
|
||||||
let build_transform = build_transform.prepare(self.bounds);
|
let built_options = options.prepare(self.bounds);
|
||||||
self.objects
|
self.objects
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(object_index, object)| {
|
.map(|(object_index, object)| {
|
||||||
let outline = self.apply_build_transform(&object.outline, &build_transform);
|
let outline = self.apply_render_options(&object.outline, &built_options);
|
||||||
let mut tiler = Tiler::new(
|
let mut tiler = Tiler::new(
|
||||||
&outline,
|
&outline,
|
||||||
self.view_box,
|
self.view_box,
|
||||||
|
@ -87,14 +84,13 @@ impl Scene {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_objects(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
|
pub fn build_objects(&self, options: RenderOptions, z_buffer: &ZBuffer) -> Vec<BuiltObject> {
|
||||||
-> Vec<BuiltObject> {
|
let built_options = options.prepare(self.bounds);
|
||||||
let build_transform = build_transform.prepare(self.bounds);
|
|
||||||
self.objects
|
self.objects
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(object_index, object)| {
|
.map(|(object_index, object)| {
|
||||||
let outline = self.apply_build_transform(&object.outline, &build_transform);
|
let outline = self.apply_render_options(&object.outline, &built_options);
|
||||||
let mut tiler = Tiler::new(
|
let mut tiler = Tiler::new(
|
||||||
&outline,
|
&outline,
|
||||||
self.view_box,
|
self.view_box,
|
||||||
|
@ -108,24 +104,27 @@ impl Scene {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_build_transform(&self, outline: &Outline, build_transform: &PreparedBuildTransform)
|
fn apply_render_options(&self, outline: &Outline, options: &PreparedRenderOptions) -> Outline {
|
||||||
-> Outline {
|
|
||||||
// FIXME(pcwalton): Don't clone?
|
// FIXME(pcwalton): Don't clone?
|
||||||
let mut outline = (*outline).clone();
|
let mut outline = (*outline).clone();
|
||||||
match *build_transform {
|
match options.transform {
|
||||||
PreparedBuildTransform::Perspective(ref perspective, ref quad) => {
|
PreparedRenderTransform::Perspective { ref perspective, ref clip_polygon } => {
|
||||||
outline.clip_against_polygon(quad);
|
outline.clip_against_polygon(clip_polygon);
|
||||||
outline.apply_perspective(perspective);
|
outline.apply_perspective(perspective);
|
||||||
outline.dilate(Point2DF32::splat(4.0));
|
|
||||||
}
|
}
|
||||||
PreparedBuildTransform::Transform2D(ref transform) => {
|
PreparedRenderTransform::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 => {
|
PreparedRenderTransform::None => {
|
||||||
outline.clip_against_rect(self.view_box);
|
outline.clip_against_rect(self.view_box);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !options.dilation.is_zero() {
|
||||||
|
outline.dilate(options.dilation);
|
||||||
|
}
|
||||||
|
|
||||||
outline.prepare_for_tiling(self.view_box);
|
outline.prepare_for_tiling(self.view_box);
|
||||||
outline
|
outline
|
||||||
}
|
}
|
||||||
|
@ -190,50 +189,3 @@ pub fn scene_tile_index(tile_x: i32, tile_y: i32, tile_rect: RectI32) -> u32 {
|
||||||
(tile_y - tile_rect.min_y()) as u32 * tile_rect.size().x() as u32
|
(tile_y - tile_rect.min_y()) as u32 * tile_rect.size().x() as u32
|
||||||
+ (tile_x - tile_rect.min_x()) as u32
|
+ (tile_x - tile_rect.min_x()) as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BuildTransform {
|
|
||||||
None,
|
|
||||||
Transform2D(Transform2DF32),
|
|
||||||
Perspective(Perspective),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BuildTransform {
|
|
||||||
fn prepare(&self, bounds: RectF32) -> PreparedBuildTransform {
|
|
||||||
let perspective = match self {
|
|
||||||
BuildTransform::None => return PreparedBuildTransform::None,
|
|
||||||
BuildTransform::Transform2D(ref transform) => {
|
|
||||||
return PreparedBuildTransform::Transform2D(*transform)
|
|
||||||
}
|
|
||||||
BuildTransform::Perspective(ref perspective) => *perspective,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut points = vec![
|
|
||||||
bounds.origin().to_3d(),
|
|
||||||
bounds.upper_right().to_3d(),
|
|
||||||
bounds.lower_right().to_3d(),
|
|
||||||
bounds.lower_left().to_3d(),
|
|
||||||
];
|
|
||||||
//println!("-----");
|
|
||||||
//println!("bounds={:?} ORIGINAL quad={:?}", self.bounds, points);
|
|
||||||
for point in &mut points {
|
|
||||||
*point = perspective.transform.transform_point(*point);
|
|
||||||
}
|
|
||||||
//println!("... PERSPECTIVE quad={:?}", points);
|
|
||||||
points = PolygonClipper3D::new(points).clip();
|
|
||||||
//println!("... CLIPPED quad={:?}", points);
|
|
||||||
for point in &mut points {
|
|
||||||
*point = point.perspective_divide()
|
|
||||||
}
|
|
||||||
let inverse_transform = perspective.transform.inverse();
|
|
||||||
let points = points.into_iter().map(|point| {
|
|
||||||
inverse_transform.transform_point(point).perspective_divide().to_2d()
|
|
||||||
}).collect();
|
|
||||||
PreparedBuildTransform::Perspective(perspective, points)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PreparedBuildTransform {
|
|
||||||
None,
|
|
||||||
Transform2D(Transform2DF32),
|
|
||||||
Perspective(Perspective, Vec<Point2DF32>),
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue