Allow devices to set transforms for each camera
This commit is contained in:
parent
21563d9d7f
commit
61caaeb2ff
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use crate::device::{GroundLineVertexArray, GroundProgram, GroundSolidVertexArray};
|
use crate::device::{GroundLineVertexArray, GroundProgram, GroundSolidVertexArray};
|
||||||
use crate::ui::{BackgroundColor, DemoUI, UIAction};
|
use crate::ui::{BackgroundColor, DemoUI, UIAction};
|
||||||
use crate::window::{Event, Keycode, SVGPath, Window, WindowSize};
|
use crate::window::{CameraTransform, Event, Keycode, SVGPath, Window, WindowSize};
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use image::ColorType;
|
use image::ColorType;
|
||||||
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32};
|
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32};
|
||||||
|
@ -44,7 +44,7 @@ use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant, SystemTime};
|
use std::time::{Duration, Instant};
|
||||||
use usvg::{Options as UsvgOptions, Tree};
|
use usvg::{Options as UsvgOptions, Tree};
|
||||||
|
|
||||||
static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg";
|
static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg";
|
||||||
|
@ -137,11 +137,7 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let scene_thread_proxy = SceneThreadProxy::new(built_svg.scene, options.clone());
|
let scene_thread_proxy = SceneThreadProxy::new(built_svg.scene, options.clone());
|
||||||
scene_thread_proxy.set_drawable_size(view_box_size);
|
scene_thread_proxy.set_drawable_size(view_box_size);
|
||||||
|
|
||||||
let camera = if options.mode == Mode::TwoD {
|
let camera = Camera::new(options.mode, scene_view_box, view_box_size);
|
||||||
Camera::new_2d(scene_view_box, view_box_size)
|
|
||||||
} else {
|
|
||||||
Camera::new_3d(scene_view_box)
|
|
||||||
};
|
|
||||||
|
|
||||||
let ground_program = GroundProgram::new(&renderer.device, resources);
|
let ground_program = GroundProgram::new(&renderer.device, resources);
|
||||||
let ground_solid_vertex_array =
|
let ground_solid_vertex_array =
|
||||||
|
@ -213,17 +209,20 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_scene(&mut self) {
|
fn build_scene(&mut self) {
|
||||||
let view_box_size = view_box_size(self.ui.mode, &self.window_size);
|
let render_transforms = match self.camera {
|
||||||
|
Camera::ThreeD { ref transforms, ref mut transform, ref mut velocity, .. } => {
|
||||||
let render_transform = match self.camera {
|
|
||||||
Camera::ThreeD { ref mut transform, ref mut velocity } => {
|
|
||||||
if transform.offset(*velocity) {
|
if transform.offset(*velocity) {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
let perspective = transform.to_perspective(view_box_size);
|
transforms.iter()
|
||||||
|
.map(|tr| {
|
||||||
|
let perspective = tr.perspective
|
||||||
|
.post_mul(&tr.view)
|
||||||
|
.post_mul(&transform.to_transform());
|
||||||
RenderTransform::Perspective(perspective)
|
RenderTransform::Perspective(perspective)
|
||||||
|
}).collect()
|
||||||
}
|
}
|
||||||
Camera::TwoD(transform) => RenderTransform::Transform2D(transform),
|
Camera::TwoD(transform) => vec![RenderTransform::Transform2D(transform)],
|
||||||
};
|
};
|
||||||
|
|
||||||
let barrel_distortion = match self.ui.mode {
|
let barrel_distortion = match self.ui.mode {
|
||||||
|
@ -231,9 +230,6 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let viewport_count = self.ui.mode.viewport_count();
|
|
||||||
let render_transforms =
|
|
||||||
iter::repeat(render_transform.clone()).take(viewport_count).collect();
|
|
||||||
self.scene_thread_proxy.sender.send(MainToSceneMsg::Build(BuildOptions {
|
self.scene_thread_proxy.sender.send(MainToSceneMsg::Build(BuildOptions {
|
||||||
render_transforms,
|
render_transforms,
|
||||||
stem_darkening_font_size: if self.ui.stem_darkening_effect_enabled {
|
stem_darkening_font_size: if self.ui.stem_darkening_effect_enabled {
|
||||||
|
@ -300,6 +296,11 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
transform.yaw += yaw;
|
transform.yaw += yaw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::CameraTransforms(new_transforms) => {
|
||||||
|
if let Camera::ThreeD { ref mut transforms, .. } = self.camera {
|
||||||
|
*transforms = new_transforms;
|
||||||
|
}
|
||||||
|
}
|
||||||
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
|
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
|
||||||
if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
|
if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
|
||||||
let scale_factor = scale_factor_for_view_box(self.scene_view_box);
|
let scale_factor = scale_factor_for_view_box(self.scene_view_box);
|
||||||
|
@ -356,13 +357,7 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let view_box_size = view_box_size(self.ui.mode, &self.window_size);
|
let view_box_size = view_box_size(self.ui.mode, &self.window_size);
|
||||||
self.scene_view_box = built_svg.scene.view_box;
|
self.scene_view_box = built_svg.scene.view_box;
|
||||||
self.monochrome_scene_color = built_svg.scene.monochrome_color();
|
self.monochrome_scene_color = built_svg.scene.monochrome_color();
|
||||||
|
self.camera = Camera::new(self.ui.mode, self.scene_view_box, view_box_size);
|
||||||
self.camera = if self.ui.mode == Mode::TwoD {
|
|
||||||
Camera::new_2d(self.scene_view_box, view_box_size)
|
|
||||||
} else {
|
|
||||||
Camera::new_3d(self.scene_view_box)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.scene_thread_proxy.load_scene(built_svg.scene, view_box_size);
|
self.scene_thread_proxy.load_scene(built_svg.scene, view_box_size);
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
|
@ -447,16 +442,10 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
|
|
||||||
// Switch camera mode (2D/3D) if requested.
|
// Switch camera mode (2D/3D) if requested.
|
||||||
//
|
//
|
||||||
// FIXME(pcwalton): This mess should really be an MVC setup.
|
// FIXME(pcwalton): This should really be an MVC setup.
|
||||||
match (&self.camera, self.ui.mode) {
|
if self.camera.mode() != self.ui.mode {
|
||||||
(&Camera::TwoD { .. }, Mode::ThreeD) | (&Camera::TwoD { .. }, Mode::VR) => {
|
let view_box_size = view_box_size(self.ui.mode, &self.window_size);
|
||||||
self.camera = Camera::new_3d(self.scene_view_box);
|
self.camera = Camera::new(self.ui.mode, self.scene_view_box, view_box_size);
|
||||||
}
|
|
||||||
(&Camera::ThreeD { .. }, Mode::TwoD) => {
|
|
||||||
let drawable_size = self.window_size.device_size();
|
|
||||||
self.camera = Camera::new_2d(self.scene_view_box, drawable_size);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for ui_event in frame.ui_events {
|
for ui_event in frame.ui_events {
|
||||||
|
@ -733,12 +722,14 @@ impl SceneThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
enum MainToSceneMsg {
|
enum MainToSceneMsg {
|
||||||
LoadScene { scene: Scene, view_box_size: Point2DI32 },
|
LoadScene { scene: Scene, view_box_size: Point2DI32 },
|
||||||
SetDrawableSize(Point2DI32),
|
SetDrawableSize(Point2DI32),
|
||||||
Build(BuildOptions),
|
Build(BuildOptions),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct BuildOptions {
|
struct BuildOptions {
|
||||||
render_transforms: Vec<RenderTransform>,
|
render_transforms: Vec<RenderTransform>,
|
||||||
stem_darkening_font_size: Option<f32>,
|
stem_darkening_font_size: Option<f32>,
|
||||||
|
@ -952,19 +943,48 @@ fn center_of_window(window_size: &WindowSize) -> Point2DF32 {
|
||||||
|
|
||||||
enum Camera {
|
enum Camera {
|
||||||
TwoD(Transform2DF32),
|
TwoD(Transform2DF32),
|
||||||
ThreeD { transform: CameraTransform3D, velocity: Point3DF32 },
|
ThreeD {
|
||||||
|
// The mode will either be 3D or VR
|
||||||
|
mode: Mode,
|
||||||
|
// For each camera, the perspective from camera coordinates to display coordinates,
|
||||||
|
// and the view transform from world coordinates to camera coordinates.
|
||||||
|
transforms: Vec<CameraTransform>,
|
||||||
|
// The model transform from world coordinates to SVG coordinates
|
||||||
|
transform: CameraTransform3D,
|
||||||
|
// The camera's velocity (in world coordinates)
|
||||||
|
velocity: Point3DF32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Camera {
|
impl Camera {
|
||||||
fn new_2d(view_box: RectF32, drawable_size: Point2DI32) -> Camera {
|
fn new(mode: Mode, view_box: RectF32, view_box_size: Point2DI32) -> Camera {
|
||||||
let scale = i32::min(drawable_size.x(), drawable_size.y()) as f32 *
|
if mode == Mode::TwoD {
|
||||||
|
Camera::new_2d(view_box, view_box_size)
|
||||||
|
} else {
|
||||||
|
Camera::new_3d(mode, view_box, view_box_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_2d(view_box: RectF32, view_box_size: Point2DI32) -> Camera {
|
||||||
|
let scale = i32::min(view_box_size.x(), view_box_size.y()) as f32 *
|
||||||
scale_factor_for_view_box(view_box);
|
scale_factor_for_view_box(view_box);
|
||||||
let origin = drawable_size.to_f32().scale(0.5) - view_box.size().scale(scale * 0.5);
|
let origin = view_box_size.to_f32().scale(0.5) - view_box.size().scale(scale * 0.5);
|
||||||
Camera::TwoD(Transform2DF32::from_scale(&Point2DF32::splat(scale)).post_translate(origin))
|
Camera::TwoD(Transform2DF32::from_scale(&Point2DF32::splat(scale)).post_translate(origin))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_3d(view_box: RectF32) -> Camera {
|
fn new_3d(mode: Mode, view_box: RectF32, view_box_size: Point2DI32) -> Camera {
|
||||||
|
let viewport_count = mode.viewport_count();
|
||||||
|
let aspect = view_box_size.x() as f32 / view_box_size.y() as f32;
|
||||||
|
let projection = Transform3DF32::from_perspective(FRAC_PI_4, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
|
||||||
|
let transform = CameraTransform {
|
||||||
|
perspective: Perspective::new(&projection, view_box_size),
|
||||||
|
view: Transform3DF32::default(),
|
||||||
|
};
|
||||||
|
let transforms = iter::repeat(transform).take(viewport_count).collect();
|
||||||
|
|
||||||
Camera::ThreeD {
|
Camera::ThreeD {
|
||||||
|
mode,
|
||||||
|
transforms,
|
||||||
transform: CameraTransform3D::new(view_box),
|
transform: CameraTransform3D::new(view_box),
|
||||||
velocity: Point3DF32::default(),
|
velocity: Point3DF32::default(),
|
||||||
}
|
}
|
||||||
|
@ -973,6 +993,10 @@ impl Camera {
|
||||||
fn is_3d(&self) -> bool {
|
fn is_3d(&self) -> bool {
|
||||||
match *self { Camera::ThreeD { .. } => true, Camera::TwoD { .. } => false }
|
match *self { Camera::ThreeD { .. } => true, Camera::TwoD { .. } => false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mode(&self) -> Mode {
|
||||||
|
match *self { Camera::ThreeD { mode, .. } => mode, Camera::TwoD { .. } => Mode::TwoD }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -1006,12 +1030,8 @@ impl CameraTransform3D {
|
||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_perspective(&self, drawable_size: Point2DI32) -> Perspective {
|
fn to_transform(&self) -> Transform3DF32 {
|
||||||
let aspect = drawable_size.x() as f32 / drawable_size.y() as f32;
|
let mut transform = Transform3DF32::from_rotation(self.yaw, self.pitch, 0.0);
|
||||||
let mut transform =
|
|
||||||
Transform3DF32::from_perspective(FRAC_PI_4, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
|
|
||||||
|
|
||||||
transform = transform.post_mul(&Transform3DF32::from_rotation(self.yaw, self.pitch, 0.0));
|
|
||||||
transform = transform.post_mul(&Transform3DF32::from_uniform_scale(2.0 * self.scale));
|
transform = transform.post_mul(&Transform3DF32::from_uniform_scale(2.0 * self.scale));
|
||||||
transform = transform.post_mul(&Transform3DF32::from_translation(-self.position.x(),
|
transform = transform.post_mul(&Transform3DF32::from_translation(-self.position.x(),
|
||||||
-self.position.y(),
|
-self.position.y(),
|
||||||
|
@ -1020,7 +1040,7 @@ impl CameraTransform3D {
|
||||||
// Flip Y.
|
// Flip Y.
|
||||||
transform = transform.post_mul(&Transform3DF32::from_scale(1.0, -1.0, 1.0));
|
transform = transform.post_mul(&Transform3DF32::from_scale(1.0, -1.0, 1.0));
|
||||||
|
|
||||||
Perspective::new(&transform, drawable_size)
|
transform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
use gl::types::GLuint;
|
use gl::types::GLuint;
|
||||||
use pathfinder_geometry::basic::point::Point2DI32;
|
use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
|
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
|
||||||
|
use pathfinder_geometry::basic::transform3d::Perspective;
|
||||||
|
use pathfinder_geometry::basic::transform3d::Transform3DF32;
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
use pathfinder_gpu::resources::ResourceLoader;
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
use rayon::ThreadPoolBuilder;
|
use rayon::ThreadPoolBuilder;
|
||||||
|
@ -49,6 +51,7 @@ pub enum Event {
|
||||||
MouseDragged(Point2DI32),
|
MouseDragged(Point2DI32),
|
||||||
Zoom(f32),
|
Zoom(f32),
|
||||||
Look { pitch: f32, yaw: f32 },
|
Look { pitch: f32, yaw: f32 },
|
||||||
|
CameraTransforms(Vec<CameraTransform>),
|
||||||
OpenSVG(SVGPath),
|
OpenSVG(SVGPath),
|
||||||
User { message_type: u32, message_data: u32 },
|
User { message_type: u32, message_data: u32 },
|
||||||
}
|
}
|
||||||
|
@ -73,6 +76,15 @@ impl WindowSize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct CameraTransform {
|
||||||
|
// The perspective which converts from camera coordinates to display coordinates
|
||||||
|
pub perspective: Perspective,
|
||||||
|
|
||||||
|
// The view transform which converts from world coordinates to camera coordinates
|
||||||
|
pub view: Transform3DF32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum SVGPath {
|
pub enum SVGPath {
|
||||||
Default,
|
Default,
|
||||||
|
|
Loading…
Reference in New Issue