Rotate and scale around the appropriate points in the demo

This commit is contained in:
Patrick Walton 2019-02-13 16:05:28 -08:00
parent 4053b7dd0c
commit 0983812b90
4 changed files with 123 additions and 23 deletions

View File

@ -191,13 +191,7 @@ impl DemoApp {
RenderTransform::Perspective(Perspective::new(&transform, &drawable_size))
}
Camera::TwoD { ref position, scale } => {
let mut transform = Transform2DF32::from_rotation(self.ui.rotation());
transform =
transform.post_mul(&Transform2DF32::from_scale(&Point2DF32::splat(scale)));
transform = transform.post_mul(&Transform2DF32::from_translation(position));
RenderTransform::Transform2D(transform)
}
Camera::TwoD(transform) => RenderTransform::Transform2D(transform),
};
let count = if self.frame_counter == 0 { 2 } else { 1 };
@ -263,8 +257,14 @@ impl DemoApp {
self.dirty = true;
}
Event::MultiGesture { d_dist, .. } => {
if let Camera::TwoD { ref mut scale, .. } = self.camera {
*scale *= 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
if let Camera::TwoD(ref mut transform) = self.camera {
let mouse_state = self.sdl_event_pump.mouse_state();
let position = Point2DI32::new(mouse_state.x(), mouse_state.y());
let position = position.to_f32().scale(self.scale_factor);
*transform = transform.post_translate(-position);
let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
*transform = transform.post_scale(Point2DF32::splat(scale_delta));
*transform = transform.post_translate(position);
}
}
Event::KeyDown { keycode: Some(Keycode::W), .. } => {
@ -358,17 +358,34 @@ impl DemoApp {
self.dirty = true;
}
UIAction::ZoomIn => {
if let Camera::TwoD { ref mut scale, .. } = self.camera {
*scale *= 1.0 + CAMERA_ZOOM_AMOUNT_2D;
if let Camera::TwoD(ref mut transform) = self.camera {
let scale = Point2DF32::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D);
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_scale(scale)
.post_translate(center);
self.dirty = true;
}
}
UIAction::ZoomOut => {
if let Camera::TwoD { ref mut scale, .. } = self.camera {
*scale *= 1.0 - CAMERA_ZOOM_AMOUNT_2D;
if let Camera::TwoD(ref mut transform) = self.camera {
let scale = Point2DF32::splat(1.0 - CAMERA_ZOOM_AMOUNT_2D);
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_scale(scale)
.post_translate(center);
self.dirty = true;
}
}
UIAction::Rotate(theta) => {
if let Camera::TwoD(ref mut transform) = self.camera {
let old_rotation = transform.rotation();
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_rotate(theta - old_rotation)
.post_translate(center);
}
}
}
// Switch camera mode (2D/3D) if requested.
@ -386,8 +403,8 @@ impl DemoApp {
self.mouselook_enabled = !self.mouselook_enabled;
}
UIEvent::MouseDragged { relative_position, .. } => {
if let Camera::TwoD { ref mut position, .. } = self.camera {
*position = *position + relative_position.to_f32();
if let Camera::TwoD(ref mut transform) = self.camera {
*transform = transform.post_translate(relative_position.to_f32());
}
}
_ => {}
@ -574,14 +591,19 @@ fn update_drawable_size(window: &Window, scene_thread_proxy: &SceneThreadProxy)
drawable_size
}
fn center_of_window(window: &Window) -> Point2DF32 {
let (drawable_width, drawable_height) = window.drawable_size();
Point2DI32::new(drawable_width as i32, drawable_height as i32).to_f32().scale(0.5)
}
enum Camera {
TwoD { position: Point2DF32, scale: f32 },
TwoD(Transform2DF32),
ThreeD { position: Point3DF32, velocity: Point3DF32, yaw: f32, pitch: f32 },
}
impl Camera {
fn two_d() -> Camera {
Camera::TwoD { position: Point2DF32::new(0.0, 0.0), scale: 1.0 }
Camera::TwoD(Transform2DF32::default())
}
fn three_d() -> Camera {

View File

@ -81,7 +81,7 @@ impl DemoUI {
}
}
pub fn rotation(&self) -> f32 {
fn rotation(&self) -> f32 {
(self.rotation as f32 / SLIDER_WIDTH as f32 * 2.0 - 1.0) * PI
}
@ -145,7 +145,7 @@ impl DemoUI {
self.draw_effects_panel(debug_ui, event);
// Draw rotate panel, if necessary.
self.draw_rotate_panel(debug_ui, event);
self.draw_rotate_panel(debug_ui, event, action);
}
fn draw_effects_panel(&mut self, debug_ui: &mut DebugUI, event: &mut UIEvent) {
@ -184,7 +184,10 @@ impl DemoUI {
}
fn draw_rotate_panel(&mut self, debug_ui: &mut DebugUI, event: &mut UIEvent) {
fn draw_rotate_panel(&mut self,
debug_ui: &mut DebugUI,
event: &mut UIEvent,
action: &mut UIAction) {
if !self.rotate_panel_visible {
return;
}
@ -201,6 +204,7 @@ impl DemoUI {
Point2DI32::new(SLIDER_WIDTH, SLIDER_KNOB_HEIGHT));
if let Some(position) = event.handle_mouse_down_or_dragged_in_rect(widget_rect) {
self.rotation = position.x();
*action = UIAction::Rotate(self.rotation());
}
let slider_track_y = rotate_panel_y + PADDING + SLIDER_KNOB_HEIGHT / 2 -
@ -291,6 +295,7 @@ pub enum UIAction {
OpenFile(PathBuf),
ZoomIn,
ZoomOut,
Rotate(f32),
}
pub enum UIEvent {

View File

@ -12,7 +12,7 @@
use euclid::Point2D;
use pathfinder_simd::default::{F32x4, I32x4};
use std::ops::{Add, AddAssign, Mul, Sub};
use std::ops::{Add, AddAssign, Mul, Neg, Sub};
/// 2D points with 32-bit floating point coordinates.
#[derive(Clone, Copy, Debug, Default)]
@ -161,6 +161,14 @@ impl Mul<Point2DF32> for Point2DF32 {
}
}
impl Neg for Point2DF32 {
type Output = Point2DF32;
#[inline]
fn neg(self) -> Point2DF32 {
Point2DF32(-self.0)
}
}
/// 2D points with 32-bit signed integer coordinates.
#[derive(Clone, Copy, Debug, Default)]
pub struct Point2DI32(pub I32x4);

View File

@ -82,6 +82,15 @@ impl Matrix2x2F32 {
pub fn inverse(&self) -> Matrix2x2F32 {
Matrix2x2F32(F32x4::splat(1.0 / self.det()) * self.adjugate().0)
}
#[inline]
pub fn m11(&self) -> f32 { self.0[0] }
#[inline]
pub fn m21(&self) -> f32 { self.0[1] }
#[inline]
pub fn m12(&self) -> f32 { self.0[2] }
#[inline]
pub fn m22(&self) -> f32 { self.0[3] }
}
impl Sub<Matrix2x2F32> for Matrix2x2F32 {
@ -132,6 +141,14 @@ impl Transform2DF32 {
}
}
#[inline]
pub fn from_scale_rotation_translation(scale: Point2DF32, theta: f32, translation: Point2DF32)
-> Transform2DF32 {
let rotation = Transform2DF32::from_rotation(theta);
let translation = Transform2DF32::from_translation(&translation);
Transform2DF32::from_scale(&scale).post_mul(&rotation).post_mul(&translation)
}
#[inline]
pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32)
-> Transform2DF32 {
@ -182,6 +199,54 @@ impl Transform2DF32 {
pub fn is_identity(&self) -> bool {
*self == Transform2DF32::default()
}
#[inline]
pub fn m11(&self) -> f32 { self.matrix.m11() }
#[inline]
pub fn m21(&self) -> f32 { self.matrix.m21() }
#[inline]
pub fn m12(&self) -> f32 { self.matrix.m12() }
#[inline]
pub fn m22(&self) -> f32 { self.matrix.m22() }
#[inline]
pub fn post_translate(&self, vector: Point2DF32) -> Transform2DF32 {
self.post_mul(&Transform2DF32::from_translation(&vector))
}
#[inline]
pub fn post_rotate(&self, theta: f32) -> Transform2DF32 {
self.post_mul(&Transform2DF32::from_rotation(theta))
}
#[inline]
pub fn post_scale(&self, scale: Point2DF32) -> Transform2DF32 {
self.post_mul(&Transform2DF32::from_scale(&scale))
}
/// Returns the translation part of this matrix.
///
/// This decomposition assumes that scale, rotation, and translation are applied in that order.
#[inline]
pub fn translation(&self) -> Point2DF32 {
self.vector
}
/// Returns the rotation angle of this matrix.
///
/// This decomposition assumes that scale, rotation, and translation are applied in that order.
#[inline]
pub fn rotation(&self) -> f32 {
f32::atan2(self.m21(), self.m11())
}
/// Returns the scale factor of this matrix.
///
/// This decomposition assumes that scale, rotation, and translation are applied in that order.
#[inline]
pub fn scale_factor(&self) -> f32 {
Point2DF32(self.matrix.0.zwxy()).length()
}
}
/// Transforms a path with a SIMD 2D transform.