Allow the canvas to be dragged in 2D mode

This commit is contained in:
Patrick Walton 2019-02-12 14:49:24 -08:00
parent 398718a3c8
commit d7f6d9eb3d
4 changed files with 131 additions and 62 deletions

View File

@ -71,11 +71,7 @@ struct DemoApp {
scale_factor: f32, scale_factor: f32,
camera_position: Point3DF32, camera: Camera,
camera_velocity: Point3DF32,
camera_yaw: f32,
camera_pitch: f32,
frame_counter: u32, frame_counter: u32,
events: Vec<Event>, events: Vec<Event>,
exit: bool, exit: bool,
@ -119,6 +115,8 @@ impl DemoApp {
let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone()); let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone());
update_drawable_size(&window, &scene_thread_proxy); update_drawable_size(&window, &scene_thread_proxy);
let camera = if options.threed { Camera::three_d() } else { Camera::two_d() };
DemoApp { DemoApp {
window, window,
sdl_context, sdl_context,
@ -128,11 +126,7 @@ impl DemoApp {
scale_factor: drawable_width as f32 / window_width as f32, scale_factor: drawable_width as f32 / window_width as f32,
camera_position: Point3DF32::new(500.0, 500.0, 3000.0, 1.0), camera,
camera_velocity: Point3DF32::new(0.0, 0.0, 0.0, 1.0),
camera_yaw: 0.0,
camera_pitch: 0.0,
frame_counter: 0, frame_counter: 0,
events: vec![], events: vec![],
exit: false, exit: false,
@ -164,35 +158,35 @@ impl DemoApp {
let (drawable_width, drawable_height) = self.window.drawable_size(); let (drawable_width, drawable_height) = self.window.drawable_size();
let drawable_size = Size2D::new(drawable_width, drawable_height); let drawable_size = Size2D::new(drawable_width, drawable_height);
let render_transform = if self.ui.threed_enabled { let render_transform = match self.camera {
let rotation = Transform3DF32::from_rotation(-self.camera_yaw, Camera::ThreeD { ref mut position, velocity, yaw, pitch } => {
-self.camera_pitch, let rotation = Transform3DF32::from_rotation(-yaw, -pitch, 0.0);
0.0);
if !self.camera_velocity.is_zero() { if !velocity.is_zero() {
self.camera_position = self.camera_position + *position = *position + rotation.transform_point(velocity);
rotation.transform_point(self.camera_velocity); self.dirty = true;
self.dirty = true; }
let aspect = drawable_size.width as f32 / drawable_size.height as f32;
let mut transform =
Transform3DF32::from_perspective(FRAC_PI_4, aspect, 0.025, 100.0);
transform = transform.post_mul(&Transform3DF32::from_scale(WORLD_SCALE,
WORLD_SCALE,
WORLD_SCALE));
transform = transform.post_mul(&Transform3DF32::from_rotation(yaw, pitch, 0.0));
let translation = position.scale(-1.0);
transform = transform.post_mul(&Transform3DF32::from_translation(translation.x(),
translation.y(),
translation.z()));
RenderTransform::Perspective(Perspective::new(&transform, &drawable_size))
}
Camera::TwoD { ref position } => {
let mut transform = Transform2DF32::from_rotation(self.ui.rotation());
transform = transform.post_mul(&Transform2DF32::from_translation(position));
RenderTransform::Transform2D(transform)
} }
let aspect = drawable_size.width as f32 / drawable_size.height as f32;
let mut transform = Transform3DF32::from_perspective(FRAC_PI_4, aspect, 0.025, 100.0);
transform = transform.post_mul(&Transform3DF32::from_scale(WORLD_SCALE,
WORLD_SCALE,
WORLD_SCALE));
transform = transform.post_mul(&Transform3DF32::from_rotation(self.camera_yaw,
self.camera_pitch,
0.0));
let translation = self.camera_position.scale(-1.0);
transform = transform.post_mul(&Transform3DF32::from_translation(translation.x(),
translation.y(),
translation.z()));
RenderTransform::Perspective(Perspective::new(&transform, &drawable_size))
} else {
let transform = Transform2DF32::from_rotation(self.ui.rotation());
RenderTransform::Transform2D(transform)
}; };
let count = if self.frame_counter == 0 { 2 } else { 1 }; let count = if self.frame_counter == 0 { 2 } else { 1 };
@ -243,40 +237,57 @@ impl DemoApp {
ui_event = UIEvent::MouseDown(point); ui_event = UIEvent::MouseDown(point);
} }
Event::MouseMotion { xrel, yrel, .. } if self.mouselook_enabled => { Event::MouseMotion { xrel, yrel, .. } if self.mouselook_enabled => {
self.camera_yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED; if let Camera::ThreeD { ref mut yaw, ref mut pitch, .. } =
self.camera_pitch -= yrel as f32 * MOUSELOOK_ROTATION_SPEED; self.camera {
self.dirty = true; *yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED;
*pitch -= yrel as f32 * MOUSELOOK_ROTATION_SPEED;
self.dirty = true;
}
} }
Event::MouseMotion { x, y, mousestate, .. } if mousestate.left() => { Event::MouseMotion { x, y, xrel, yrel, mousestate, .. } if mousestate.left() => {
let point = Point2DI32::new(x, y).scale(self.scale_factor as i32); let absolute_position = Point2DI32::new(x, y).scale(self.scale_factor as i32);
ui_event = UIEvent::MouseDragged(point); let relative_position =
Point2DI32::new(xrel, yrel).scale(self.scale_factor as i32);
ui_event = UIEvent::MouseDragged { absolute_position, relative_position };
self.dirty = true; self.dirty = true;
} }
Event::KeyDown { keycode: Some(Keycode::W), .. } => { Event::KeyDown { keycode: Some(Keycode::W), .. } => {
self.camera_velocity.set_z(-CAMERA_VELOCITY); if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
self.dirty = true; velocity.set_z(-CAMERA_VELOCITY);
self.dirty = true;
}
} }
Event::KeyDown { keycode: Some(Keycode::S), .. } => { Event::KeyDown { keycode: Some(Keycode::S), .. } => {
self.camera_velocity.set_z(CAMERA_VELOCITY); if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
self.dirty = true; velocity.set_z(CAMERA_VELOCITY);
self.dirty = true;
}
} }
Event::KeyDown { keycode: Some(Keycode::A), .. } => { Event::KeyDown { keycode: Some(Keycode::A), .. } => {
self.camera_velocity.set_x(-CAMERA_VELOCITY); if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
self.dirty = true; velocity.set_x(-CAMERA_VELOCITY);
self.dirty = true;
}
} }
Event::KeyDown { keycode: Some(Keycode::D), .. } => { Event::KeyDown { keycode: Some(Keycode::D), .. } => {
self.camera_velocity.set_x(CAMERA_VELOCITY); if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
self.dirty = true; velocity.set_x(CAMERA_VELOCITY);
self.dirty = true;
}
} }
Event::KeyUp { keycode: Some(Keycode::W), .. } | Event::KeyUp { keycode: Some(Keycode::W), .. } |
Event::KeyUp { keycode: Some(Keycode::S), .. } => { Event::KeyUp { keycode: Some(Keycode::S), .. } => {
self.camera_velocity.set_z(0.0); if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
self.dirty = true; velocity.set_z(0.0);
self.dirty = true;
}
} }
Event::KeyUp { keycode: Some(Keycode::A), .. } | Event::KeyUp { keycode: Some(Keycode::A), .. } |
Event::KeyUp { keycode: Some(Keycode::D), .. } => { Event::KeyUp { keycode: Some(Keycode::D), .. } => {
self.camera_velocity.set_x(0.0); if let Camera::ThreeD { ref mut velocity, .. } = self.camera {
self.dirty = true; velocity.set_x(0.0);
self.dirty = true;
}
} }
_ => continue, _ => continue,
} }
@ -328,9 +339,26 @@ impl DemoApp {
self.dirty = true; self.dirty = true;
} }
// If nothing handled the mouse-down event, toggle mouselook. // Switch camera mode (2D/3D) if requested.
if let UIEvent::MouseDown(_) = ui_event { //
self.mouselook_enabled = !self.mouselook_enabled; // FIXME(pcwalton): This mess should really be an MVC setup.
match (&self.camera, self.ui.threed_enabled) {
(&Camera::TwoD { .. }, true) => self.camera = Camera::three_d(),
(&Camera::ThreeD { .. }, false) => self.camera = Camera::two_d(),
_ => {}
}
match ui_event {
UIEvent::MouseDown(_) if self.camera.is_3d() => {
// If nothing handled the mouse-down event, toggle mouselook.
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();
}
}
_ => {}
} }
} }
@ -515,3 +543,30 @@ fn update_drawable_size(window: &Window, scene_thread_proxy: &SceneThreadProxy)
scene_thread_proxy.set_drawable_size(&drawable_size); scene_thread_proxy.set_drawable_size(&drawable_size);
drawable_size drawable_size
} }
enum Camera {
TwoD { position: Point2DF32 },
ThreeD { position: Point3DF32, velocity: Point3DF32, yaw: f32, pitch: f32 },
}
impl Camera {
fn two_d() -> Camera {
Camera::TwoD { position: Point2DF32::new(0.0, 0.0) }
}
fn three_d() -> Camera {
Camera::ThreeD {
position: Point3DF32::new(500.0, 500.0, 3000.0, 1.0),
velocity: Point3DF32::new(0.0, 0.0, 0.0, 1.0),
yaw: 0.0,
pitch: 0.0,
}
}
fn is_3d(&self) -> bool {
match *self {
Camera::ThreeD { .. } => true,
Camera::TwoD { .. } => false,
}
}
}

View File

@ -66,7 +66,7 @@ impl DemoUI {
rotate_texture, rotate_texture,
threed_enabled: options.threed, threed_enabled: options.threed,
effects_panel_visible: false, effects_panel_visible: false,
rotate_panel_visible: true, rotate_panel_visible: false,
gamma_correction_effect_enabled: false, gamma_correction_effect_enabled: false,
stem_darkening_effect_enabled: false, stem_darkening_effect_enabled: false,
subpixel_aa_effect_enabled: false, subpixel_aa_effect_enabled: false,
@ -267,7 +267,10 @@ impl DemoUI {
pub enum UIEvent { pub enum UIEvent {
None, None,
MouseDown(Point2DI32), MouseDown(Point2DI32),
MouseDragged(Point2DI32), MouseDragged {
absolute_position: Point2DI32,
relative_position: Point2DI32,
}
} }
impl UIEvent { impl UIEvent {
@ -287,8 +290,8 @@ impl UIEvent {
fn handle_mouse_down_or_dragged_in_rect(&mut self, rect: RectI32) -> Option<Point2DI32> { fn handle_mouse_down_or_dragged_in_rect(&mut self, rect: RectI32) -> Option<Point2DI32> {
match *self { match *self {
UIEvent::MouseDown(point) | UIEvent::MouseDown(point) | UIEvent::MouseDragged { absolute_position: point, .. }
UIEvent::MouseDragged(point) if rect.contains_point(point) => { if rect.contains_point(point) => {
*self = UIEvent::None; *self = UIEvent::None;
Some(point - rect.origin()) Some(point - rect.origin())
} }

View File

@ -200,6 +200,11 @@ impl Point2DI32 {
pub fn scale(&self, factor: i32) -> Point2DI32 { pub fn scale(&self, factor: i32) -> Point2DI32 {
Point2DI32(self.0 * I32x4::splat(factor)) Point2DI32(self.0 * I32x4::splat(factor))
} }
#[inline]
pub fn to_f32(&self) -> Point2DF32 {
Point2DF32(self.0.to_f32x4())
}
} }
impl Add<Point2DI32> for Point2DI32 { impl Add<Point2DI32> for Point2DI32 {

View File

@ -1563,6 +1563,12 @@ impl I32x4 {
U8x16(self.0) U8x16(self.0)
} }
/// Converts these packed integers to floats.
#[inline]
pub fn to_f32x4(self) -> F32x4 {
unsafe { F32x4(x86_64::_mm_cvtepi32_ps(self.0)) }
}
// Basic operations // Basic operations
#[inline] #[inline]