Add basic barrel distortion support for VR
This commit is contained in:
parent
2819a88060
commit
6ca5dc5f62
|
@ -63,6 +63,8 @@ public class PathfinderDemoActivity extends Activity {
|
||||||
void setVRMode(boolean enabled) {
|
void setVRMode(boolean enabled) {
|
||||||
try {
|
try {
|
||||||
setVrModeEnabled(false, mVRListenerComponentName);
|
setVrModeEnabled(false, mVRListenerComponentName);
|
||||||
|
mContentView.setStereoModeEnabled(enabled);
|
||||||
|
mContentView.setDistortionCorrectionEnabled(false);
|
||||||
} catch (PackageManager.NameNotFoundException exception) {
|
} catch (PackageManager.NameNotFoundException exception) {
|
||||||
startActivity(new Intent(Settings.ACTION_VR_LISTENER_SETTINGS));
|
startActivity(new Intent(Settings.ACTION_VR_LISTENER_SETTINGS));
|
||||||
}
|
}
|
||||||
|
@ -77,7 +79,6 @@ public class PathfinderDemoActivity extends Activity {
|
||||||
setContentView(R.layout.activity_pathfinder);
|
setContentView(R.layout.activity_pathfinder);
|
||||||
|
|
||||||
mContentView = findViewById(R.id.fullscreen_content);
|
mContentView = findViewById(R.id.fullscreen_content);
|
||||||
mContentView.setStereoModeEnabled(false);
|
|
||||||
setVRMode(false);
|
setVRMode(false);
|
||||||
|
|
||||||
mContentView.setEGLContextClientVersion(3);
|
mContentView.setEGLContextClientVersion(3);
|
||||||
|
|
|
@ -21,6 +21,7 @@ use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
||||||
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
||||||
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
|
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
|
||||||
use pathfinder_geometry::color::ColorU;
|
use pathfinder_geometry::color::ColorU;
|
||||||
|
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
|
||||||
use pathfinder_gl::GLDevice;
|
use pathfinder_gl::GLDevice;
|
||||||
use pathfinder_gpu::resources::ResourceLoader;
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc};
|
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc};
|
||||||
|
@ -213,6 +214,11 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
|
|
||||||
let is_first_frame = self.frame_counter == 0;
|
let is_first_frame = self.frame_counter == 0;
|
||||||
let frame_count = if is_first_frame { 2 } else { 1 };
|
let frame_count = if is_first_frame { 2 } else { 1 };
|
||||||
|
let barrel_distortion = match self.ui.mode {
|
||||||
|
Mode::VR => Some(self.window.barrel_distortion_coefficients()),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
for _ in 0..frame_count {
|
for _ in 0..frame_count {
|
||||||
let viewport_count = self.ui.mode.viewport_count();
|
let viewport_count = self.ui.mode.viewport_count();
|
||||||
let render_transforms = iter::repeat(render_transform.clone()).take(viewport_count)
|
let render_transforms = iter::repeat(render_transform.clone()).take(viewport_count)
|
||||||
|
@ -224,6 +230,7 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
barrel_distortion,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,6 +693,7 @@ enum MainToSceneMsg {
|
||||||
struct BuildOptions {
|
struct BuildOptions {
|
||||||
render_transforms: Vec<RenderTransform>,
|
render_transforms: Vec<RenderTransform>,
|
||||||
stem_darkening_font_size: Option<f32>,
|
stem_darkening_font_size: Option<f32>,
|
||||||
|
barrel_distortion: Option<BarrelDistortionCoefficients>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SceneToMainMsg {
|
struct SceneToMainMsg {
|
||||||
|
@ -798,6 +806,7 @@ fn build_scene(scene: &Scene,
|
||||||
Point2DF32::new(x, y).scale(font_size)
|
Point2DF32::new(x, y).scale(font_size)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
barrel_distortion: build_options.barrel_distortion,
|
||||||
};
|
};
|
||||||
|
|
||||||
let built_options = render_options.prepare(scene.bounds);
|
let built_options = render_options.prepare(scene.bounds);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
//! A minimal cross-platform windowing layer.
|
//! A minimal cross-platform windowing layer.
|
||||||
|
|
||||||
use pathfinder_geometry::basic::point::Point2DI32;
|
use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
|
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
use pathfinder_gpu::resources::ResourceLoader;
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -24,6 +25,11 @@ pub trait Window {
|
||||||
fn push_user_event(message_type: u32, message_data: u32);
|
fn push_user_event(message_type: u32, message_data: u32);
|
||||||
fn present_open_svg_dialog(&mut self);
|
fn present_open_svg_dialog(&mut self);
|
||||||
fn run_save_dialog(&self, extension: &str) -> Result<PathBuf, ()>;
|
fn run_save_dialog(&self, extension: &str) -> Result<PathBuf, ()>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn barrel_distortion_coefficients(&self) -> BarrelDistortionCoefficients {
|
||||||
|
BarrelDistortionCoefficients::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
// pathfinder/geometry/src/distortion.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use crate::basic::point::{Point2DF32, Point2DI32};
|
||||||
|
use crate::outline::{self, Contour};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct BarrelDistortionCoefficients {
|
||||||
|
pub k0: f32,
|
||||||
|
pub k1: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BarrelDistortionCoefficients {
|
||||||
|
// Matches Google Daydream (Cardboard v2.2).
|
||||||
|
#[inline]
|
||||||
|
fn default() -> BarrelDistortionCoefficients {
|
||||||
|
BarrelDistortionCoefficients { k0: 0.34, k1: 0.55 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ContourBarrelDistorter<'a> {
|
||||||
|
contour: &'a mut Contour,
|
||||||
|
window_size: Point2DI32,
|
||||||
|
coefficients: BarrelDistortionCoefficients,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ContourBarrelDistorter<'a> {
|
||||||
|
pub fn new(contour: &'a mut Contour,
|
||||||
|
coefficients: BarrelDistortionCoefficients,
|
||||||
|
window_size: Point2DI32)
|
||||||
|
-> ContourBarrelDistorter<'a> {
|
||||||
|
ContourBarrelDistorter { contour, window_size, coefficients }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn distort(&mut self) {
|
||||||
|
let one = Point2DF32::splat(1.0);
|
||||||
|
let window_size = self.window_size.to_f32();
|
||||||
|
let inv_window_size = Point2DF32(window_size.0.approx_recip());
|
||||||
|
let BarrelDistortionCoefficients { k0, k1 } = self.coefficients;
|
||||||
|
|
||||||
|
let point_count = self.contour.len();
|
||||||
|
for point_index in 0..point_count {
|
||||||
|
// Convert from window coordinates to NDC.
|
||||||
|
let mut position = self.contour.position_of(point_index);
|
||||||
|
position = position.scale_xy(inv_window_size).scale(2.0) - one;
|
||||||
|
|
||||||
|
// Apply distortion.
|
||||||
|
let r2 = position.square_length();
|
||||||
|
let scaling = 1.0 + k0 * r2 + k1 * r2 * r2;
|
||||||
|
position = position.scale(1.0 / scaling);
|
||||||
|
|
||||||
|
// Convert back to window coordinates.
|
||||||
|
position = (position + one).scale(0.5).scale_xy(window_size);
|
||||||
|
|
||||||
|
// Store resulting point.
|
||||||
|
self.contour.points[point_index as usize] = position;
|
||||||
|
outline::union_rect(&mut self.contour.bounds, position, point_index == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ extern crate bitflags;
|
||||||
pub mod basic;
|
pub mod basic;
|
||||||
pub mod clip;
|
pub mod clip;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
pub mod distortion;
|
||||||
pub mod monotonic;
|
pub mod monotonic;
|
||||||
pub mod orientation;
|
pub mod orientation;
|
||||||
pub mod outline;
|
pub mod outline;
|
||||||
|
|
|
@ -11,12 +11,13 @@
|
||||||
//! A compressed in-memory representation of paths.
|
//! A compressed in-memory representation of paths.
|
||||||
|
|
||||||
use crate::basic::line_segment::LineSegmentF32;
|
use crate::basic::line_segment::LineSegmentF32;
|
||||||
use crate::basic::point::Point2DF32;
|
use crate::basic::point::{Point2DF32, Point2DI32};
|
||||||
use crate::basic::rect::RectF32;
|
use crate::basic::rect::RectF32;
|
||||||
use crate::basic::transform2d::Transform2DF32;
|
use crate::basic::transform2d::Transform2DF32;
|
||||||
use crate::basic::transform3d::Perspective;
|
use crate::basic::transform3d::Perspective;
|
||||||
use crate::clip::{self, ContourPolygonClipper, ContourRectClipper};
|
use crate::clip::{self, ContourPolygonClipper, ContourRectClipper};
|
||||||
use crate::dilation::ContourDilator;
|
use crate::dilation::ContourDilator;
|
||||||
|
use crate::distortion::{BarrelDistortionCoefficients, ContourBarrelDistorter};
|
||||||
use crate::orientation::Orientation;
|
use crate::orientation::Orientation;
|
||||||
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
@ -135,6 +136,17 @@ impl Outline {
|
||||||
self.bounds = self.bounds.dilate(amount);
|
self.bounds = self.bounds.dilate(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn barrel_distort(&mut self,
|
||||||
|
coefficients: BarrelDistortionCoefficients,
|
||||||
|
window_size: Point2DI32) {
|
||||||
|
let mut new_bounds = None;
|
||||||
|
for contour in &mut self.contours {
|
||||||
|
contour.barrel_distort(coefficients, window_size);
|
||||||
|
contour.update_bounds(&mut new_bounds);
|
||||||
|
}
|
||||||
|
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn prepare_for_tiling(&mut self, view_box: RectF32) {
|
pub fn prepare_for_tiling(&mut self, view_box: RectF32) {
|
||||||
self.contours.iter_mut().for_each(|contour| contour.prepare_for_tiling(view_box));
|
self.contours.iter_mut().for_each(|contour| contour.prepare_for_tiling(view_box));
|
||||||
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
|
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
|
||||||
|
@ -419,6 +431,12 @@ impl Contour {
|
||||||
self.bounds = self.bounds.dilate(amount);
|
self.bounds = self.bounds.dilate(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn barrel_distort(&mut self,
|
||||||
|
coefficients: BarrelDistortionCoefficients,
|
||||||
|
window_size: Point2DI32) {
|
||||||
|
ContourBarrelDistorter::new(self, coefficients, window_size).distort();
|
||||||
|
}
|
||||||
|
|
||||||
fn prepare_for_tiling(&mut self, view_box: RectF32) {
|
fn prepare_for_tiling(&mut self, view_box: RectF32) {
|
||||||
// Snap points to the view box bounds. This mops up floating point error from the clipping
|
// Snap points to the view box bounds. This mops up floating point error from the clipping
|
||||||
// process.
|
// process.
|
||||||
|
@ -667,7 +685,7 @@ impl<'a> Iterator for ContourIter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn union_rect(bounds: &mut RectF32, new_point: Point2DF32, first: bool) {
|
pub(crate) fn union_rect(bounds: &mut RectF32, new_point: Point2DF32, first: bool) {
|
||||||
if first {
|
if first {
|
||||||
*bounds = RectF32::from_points(new_point, new_point);
|
*bounds = RectF32::from_points(new_point, new_point);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,6 +20,7 @@ use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
||||||
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
||||||
use pathfinder_geometry::basic::transform3d::Perspective;
|
use pathfinder_geometry::basic::transform3d::Perspective;
|
||||||
use pathfinder_geometry::clip::PolygonClipper3D;
|
use pathfinder_geometry::clip::PolygonClipper3D;
|
||||||
|
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
|
|
||||||
|
@ -126,6 +127,7 @@ impl SceneBuilder {
|
||||||
pub struct RenderOptions {
|
pub struct RenderOptions {
|
||||||
pub transform: RenderTransform,
|
pub transform: RenderTransform,
|
||||||
pub dilation: Point2DF32,
|
pub dilation: Point2DF32,
|
||||||
|
pub barrel_distortion: Option<BarrelDistortionCoefficients>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderOptions {
|
impl RenderOptions {
|
||||||
|
@ -133,6 +135,7 @@ impl RenderOptions {
|
||||||
PreparedRenderOptions {
|
PreparedRenderOptions {
|
||||||
transform: self.transform.prepare(bounds),
|
transform: self.transform.prepare(bounds),
|
||||||
dilation: self.dilation,
|
dilation: self.dilation,
|
||||||
|
barrel_distortion: self.barrel_distortion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,6 +204,7 @@ impl RenderTransform {
|
||||||
pub struct PreparedRenderOptions {
|
pub struct PreparedRenderOptions {
|
||||||
pub transform: PreparedRenderTransform,
|
pub transform: PreparedRenderTransform,
|
||||||
pub dilation: Point2DF32,
|
pub dilation: Point2DF32,
|
||||||
|
pub barrel_distortion: Option<BarrelDistortionCoefficients>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreparedRenderOptions {
|
impl PreparedRenderOptions {
|
||||||
|
@ -218,4 +222,3 @@ pub enum PreparedRenderTransform {
|
||||||
Transform2D(Transform2DF32),
|
Transform2D(Transform2DF32),
|
||||||
Perspective { perspective: Perspective, clip_polygon: Vec<Point2DF32>, quad: [Point3DF32; 4] }
|
Perspective { perspective: Perspective, clip_polygon: Vec<Point2DF32>, quad: [Point3DF32; 4] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,11 @@ impl Scene {
|
||||||
outline = (*original_outline).clone();
|
outline = (*original_outline).clone();
|
||||||
outline.clip_against_polygon(clip_polygon);
|
outline.clip_against_polygon(clip_polygon);
|
||||||
outline.apply_perspective(perspective);
|
outline.apply_perspective(perspective);
|
||||||
|
|
||||||
|
// TODO(pcwalton): Support this in 2D too.
|
||||||
|
if let Some(barrel_distortion) = options.barrel_distortion {
|
||||||
|
outline.barrel_distort(barrel_distortion, perspective.window_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PreparedRenderTransform::Transform2D(ref transform) => {
|
PreparedRenderTransform::Transform2D(ref transform) => {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 192 KiB |
|
@ -31,6 +31,11 @@ impl F32x4 {
|
||||||
|
|
||||||
// Basic operations
|
// Basic operations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn approx_recip(self) -> F32x4 {
|
||||||
|
F32x4([1.0 / self[0], 1.0 / self[1], 1.0 / self[2], 1.0 / self[3]])
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min(self, other: F32x4) -> F32x4 {
|
pub fn min(self, other: F32x4) -> F32x4 {
|
||||||
F32x4([
|
F32x4([
|
||||||
|
|
|
@ -37,6 +37,11 @@ impl F32x4 {
|
||||||
|
|
||||||
// Basic operations
|
// Basic operations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn approx_recip(self) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_rcp_ps(self.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min(self, other: F32x4) -> F32x4 {
|
pub fn min(self, other: F32x4) -> F32x4 {
|
||||||
unsafe { F32x4(x86_64::_mm_min_ps(self.0, other.0)) }
|
unsafe { F32x4(x86_64::_mm_min_ps(self.0, other.0)) }
|
||||||
|
|
Loading…
Reference in New Issue