Rotate and scale around the appropriate points in the demo
This commit is contained in:
parent
4053b7dd0c
commit
0983812b90
|
@ -191,13 +191,7 @@ impl DemoApp {
|
||||||
|
|
||||||
RenderTransform::Perspective(Perspective::new(&transform, &drawable_size))
|
RenderTransform::Perspective(Perspective::new(&transform, &drawable_size))
|
||||||
}
|
}
|
||||||
Camera::TwoD { ref position, scale } => {
|
Camera::TwoD(transform) => RenderTransform::Transform2D(transform),
|
||||||
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)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let count = if self.frame_counter == 0 { 2 } else { 1 };
|
let count = if self.frame_counter == 0 { 2 } else { 1 };
|
||||||
|
@ -263,8 +257,14 @@ impl DemoApp {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
Event::MultiGesture { d_dist, .. } => {
|
Event::MultiGesture { d_dist, .. } => {
|
||||||
if let Camera::TwoD { ref mut scale, .. } = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
*scale *= 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
|
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), .. } => {
|
Event::KeyDown { keycode: Some(Keycode::W), .. } => {
|
||||||
|
@ -358,17 +358,34 @@ impl DemoApp {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
UIAction::ZoomIn => {
|
UIAction::ZoomIn => {
|
||||||
if let Camera::TwoD { ref mut scale, .. } = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
*scale *= 1.0 + CAMERA_ZOOM_AMOUNT_2D;
|
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;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UIAction::ZoomOut => {
|
UIAction::ZoomOut => {
|
||||||
if let Camera::TwoD { ref mut scale, .. } = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
*scale *= 1.0 - CAMERA_ZOOM_AMOUNT_2D;
|
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;
|
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.
|
// Switch camera mode (2D/3D) if requested.
|
||||||
|
@ -386,8 +403,8 @@ impl DemoApp {
|
||||||
self.mouselook_enabled = !self.mouselook_enabled;
|
self.mouselook_enabled = !self.mouselook_enabled;
|
||||||
}
|
}
|
||||||
UIEvent::MouseDragged { relative_position, .. } => {
|
UIEvent::MouseDragged { relative_position, .. } => {
|
||||||
if let Camera::TwoD { ref mut position, .. } = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
*position = *position + relative_position.to_f32();
|
*transform = transform.post_translate(relative_position.to_f32());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -574,14 +591,19 @@ fn update_drawable_size(window: &Window, scene_thread_proxy: &SceneThreadProxy)
|
||||||
drawable_size
|
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 {
|
enum Camera {
|
||||||
TwoD { position: Point2DF32, scale: f32 },
|
TwoD(Transform2DF32),
|
||||||
ThreeD { position: Point3DF32, velocity: Point3DF32, yaw: f32, pitch: f32 },
|
ThreeD { position: Point3DF32, velocity: Point3DF32, yaw: f32, pitch: f32 },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Camera {
|
impl Camera {
|
||||||
fn two_d() -> 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 {
|
fn three_d() -> Camera {
|
||||||
|
|
|
@ -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
|
(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);
|
self.draw_effects_panel(debug_ui, event);
|
||||||
|
|
||||||
// Draw rotate panel, if necessary.
|
// 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) {
|
fn draw_effects_panel(&mut self, debug_ui: &mut DebugUI, event: &mut UIEvent) {
|
||||||
|
@ -156,8 +156,8 @@ impl DemoUI {
|
||||||
let bottom = debug_ui.framebuffer_size().height as i32 - PADDING;
|
let bottom = debug_ui.framebuffer_size().height as i32 - PADDING;
|
||||||
let effects_panel_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_PANEL_HEIGHT);
|
let effects_panel_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_PANEL_HEIGHT);
|
||||||
debug_ui.draw_solid_rect(RectI32::new(Point2DI32::new(PADDING, effects_panel_y),
|
debug_ui.draw_solid_rect(RectI32::new(Point2DI32::new(PADDING, effects_panel_y),
|
||||||
Point2DI32::new(EFFECTS_PANEL_WIDTH,
|
Point2DI32::new(EFFECTS_PANEL_WIDTH,
|
||||||
EFFECTS_PANEL_HEIGHT)),
|
EFFECTS_PANEL_HEIGHT)),
|
||||||
WINDOW_COLOR);
|
WINDOW_COLOR);
|
||||||
|
|
||||||
self.gamma_correction_effect_enabled =
|
self.gamma_correction_effect_enabled =
|
||||||
|
@ -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 {
|
if !self.rotate_panel_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -201,6 +204,7 @@ impl DemoUI {
|
||||||
Point2DI32::new(SLIDER_WIDTH, SLIDER_KNOB_HEIGHT));
|
Point2DI32::new(SLIDER_WIDTH, SLIDER_KNOB_HEIGHT));
|
||||||
if let Some(position) = event.handle_mouse_down_or_dragged_in_rect(widget_rect) {
|
if let Some(position) = event.handle_mouse_down_or_dragged_in_rect(widget_rect) {
|
||||||
self.rotation = position.x();
|
self.rotation = position.x();
|
||||||
|
*action = UIAction::Rotate(self.rotation());
|
||||||
}
|
}
|
||||||
|
|
||||||
let slider_track_y = rotate_panel_y + PADDING + SLIDER_KNOB_HEIGHT / 2 -
|
let slider_track_y = rotate_panel_y + PADDING + SLIDER_KNOB_HEIGHT / 2 -
|
||||||
|
@ -291,6 +295,7 @@ pub enum UIAction {
|
||||||
OpenFile(PathBuf),
|
OpenFile(PathBuf),
|
||||||
ZoomIn,
|
ZoomIn,
|
||||||
ZoomOut,
|
ZoomOut,
|
||||||
|
Rotate(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum UIEvent {
|
pub enum UIEvent {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use pathfinder_simd::default::{F32x4, I32x4};
|
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.
|
/// 2D points with 32-bit floating point coordinates.
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[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.
|
/// 2D points with 32-bit signed integer coordinates.
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct Point2DI32(pub I32x4);
|
pub struct Point2DI32(pub I32x4);
|
||||||
|
|
|
@ -82,6 +82,15 @@ impl Matrix2x2F32 {
|
||||||
pub fn inverse(&self) -> Matrix2x2F32 {
|
pub fn inverse(&self) -> Matrix2x2F32 {
|
||||||
Matrix2x2F32(F32x4::splat(1.0 / self.det()) * self.adjugate().0)
|
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 {
|
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]
|
#[inline]
|
||||||
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 {
|
||||||
|
@ -182,6 +199,54 @@ impl Transform2DF32 {
|
||||||
pub fn is_identity(&self) -> bool {
|
pub fn is_identity(&self) -> bool {
|
||||||
*self == Transform2DF32::default()
|
*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.
|
/// Transforms a path with a SIMD 2D transform.
|
||||||
|
|
Loading…
Reference in New Issue