Merge branch 'master' of https://github.com/servo/pathfinder
This commit is contained in:
commit
6acab74fae
|
@ -8,6 +8,7 @@ node_modules
|
||||||
/examples/c_canvas_minimal/build
|
/examples/c_canvas_minimal/build
|
||||||
/shaders/build
|
/shaders/build
|
||||||
/c/build
|
/c/build
|
||||||
|
/examples/macos_app/Pathfinder\ Example.xcodeproj/project.xcworkspace/xcuserdata/*
|
||||||
|
|
||||||
# Editors
|
# Editors
|
||||||
*.swp
|
*.swp
|
||||||
|
|
|
@ -357,6 +357,15 @@ name = "constant_time_eq"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"pathfinder_export 0.1.0",
|
||||||
|
"pathfinder_svg 0.1.0",
|
||||||
|
"usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
|
@ -1446,6 +1455,7 @@ dependencies = [
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pathfinder_content 0.1.0",
|
"pathfinder_content 0.1.0",
|
||||||
|
"pathfinder_export 0.1.0",
|
||||||
"pathfinder_geometry 0.3.0",
|
"pathfinder_geometry 0.3.0",
|
||||||
"pathfinder_gl 0.1.0",
|
"pathfinder_gl 0.1.0",
|
||||||
"pathfinder_gpu 0.1.0",
|
"pathfinder_gpu 0.1.0",
|
||||||
|
@ -1458,6 +1468,16 @@ dependencies = [
|
||||||
"usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathfinder_export"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pathfinder_content 0.1.0",
|
||||||
|
"pathfinder_geometry 0.3.0",
|
||||||
|
"pathfinder_renderer 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathfinder_geometry"
|
name = "pathfinder_geometry"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -1537,16 +1557,6 @@ dependencies = [
|
||||||
"pathfinder_simd 0.3.0",
|
"pathfinder_simd 0.3.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pathfinder_pdf"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"pathfinder_content 0.1.0",
|
|
||||||
"pathfinder_geometry 0.3.0",
|
|
||||||
"pathfinder_renderer 0.1.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathfinder_renderer"
|
name = "pathfinder_renderer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -2127,15 +2137,6 @@ dependencies = [
|
||||||
"usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "svg2pdf"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"pathfinder_pdf 0.1.0",
|
|
||||||
"pathfinder_svg 0.1.0",
|
|
||||||
"usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "svgdom"
|
name = "svgdom"
|
||||||
version = "0.17.0"
|
version = "0.17.0"
|
||||||
|
|
|
@ -13,13 +13,12 @@ members = [
|
||||||
"examples/canvas_moire",
|
"examples/canvas_moire",
|
||||||
"examples/canvas_text",
|
"examples/canvas_text",
|
||||||
"examples/lottie_basic",
|
"examples/lottie_basic",
|
||||||
"examples/svg2pdf",
|
|
||||||
"examples/swf_basic",
|
"examples/swf_basic",
|
||||||
"geometry",
|
"geometry",
|
||||||
"gl",
|
"gl",
|
||||||
"gpu",
|
"gpu",
|
||||||
"lottie",
|
"lottie",
|
||||||
"pdf",
|
"export",
|
||||||
"metal",
|
"metal",
|
||||||
"renderer",
|
"renderer",
|
||||||
"simd",
|
"simd",
|
||||||
|
@ -29,5 +28,6 @@ members = [
|
||||||
"ui",
|
"ui",
|
||||||
"utils/area-lut",
|
"utils/area-lut",
|
||||||
"utils/gamma-lut",
|
"utils/gamma-lut",
|
||||||
"utils/svg-to-skia"
|
"utils/svg-to-skia",
|
||||||
|
"utils/convert",
|
||||||
]
|
]
|
||||||
|
|
10
README.md
10
README.md
|
@ -3,7 +3,7 @@
|
||||||
# Pathfinder 3
|
# Pathfinder 3
|
||||||
|
|
||||||
Pathfinder 3 is a fast, practical, GPU-based rasterizer for fonts and vector graphics using OpenGL
|
Pathfinder 3 is a fast, practical, GPU-based rasterizer for fonts and vector graphics using OpenGL
|
||||||
and OpenGL ES 3.0+.
|
3.0+, OpenGL ES 3.0+, or Metal.
|
||||||
|
|
||||||
Please note that Pathfinder is under heavy development and is incomplete in various areas.
|
Please note that Pathfinder is under heavy development and is incomplete in various areas.
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ The project features:
|
||||||
|
|
||||||
* Fast GPU rendering, even at small pixel sizes. Even on lower-end GPUs, Pathfinder typically
|
* Fast GPU rendering, even at small pixel sizes. Even on lower-end GPUs, Pathfinder typically
|
||||||
matches or exceeds the performance of the best CPU rasterizers. The difference is particularly
|
matches or exceeds the performance of the best CPU rasterizers. The difference is particularly
|
||||||
pronouced at large sizes, where Pathfinder regularly achieves multi-factor speedups. All shaders
|
pronounced at large sizes, where Pathfinder regularly achieves multi-factor speedups. All shaders
|
||||||
have no loops and minimal branching.
|
have no loops and minimal branching.
|
||||||
|
|
||||||
* Advanced font rendering. Pathfinder can render fonts with slight hinting and can perform subpixel
|
* Advanced font rendering. Pathfinder can render fonts with slight hinting and can perform subpixel
|
||||||
|
@ -75,12 +75,6 @@ The SDL 2 library requires some additional manual installation steps. Follow the
|
||||||
[`rust-sdl2` installation instructions](https://github.com/Rust-SDL2/rust-sdl2#sdl20-development-libraries) to make sure the libraries are installed. Note that SDL2 is
|
[`rust-sdl2` installation instructions](https://github.com/Rust-SDL2/rust-sdl2#sdl20-development-libraries) to make sure the libraries are installed. Note that SDL2 is
|
||||||
only required to run the demo; Pathfinder itself has no dependency on the library.
|
only required to run the demo; Pathfinder itself has no dependency on the library.
|
||||||
|
|
||||||
On macOS, it is recommended that you force the use of the integrated GPU, as issues with Apple's
|
|
||||||
OpenGL drivers may limit performance on discrete GPUs. You can use
|
|
||||||
[gfxCardStatus.app](https://gfx.io/) for this. See the
|
|
||||||
[wiki](https://github.com/pcwalton/pathfinder/wiki/GPU-driver-compatibility) for more information
|
|
||||||
on GPU compatibility issues.
|
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
The primary author is Patrick Walton (@pcwalton), with contributions from the Servo development
|
The primary author is Patrick Walton (@pcwalton), with contributions from the Servo development
|
||||||
|
|
|
@ -2,18 +2,53 @@ language = "C"
|
||||||
header = """\
|
header = """\
|
||||||
/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */
|
/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */
|
||||||
|
|
||||||
|
#ifndef PF_PATHFINDER_H
|
||||||
|
#define PF_PATHFINDER_H
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <QuartzCore/QuartzCore.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
extern \"C\" {
|
extern \"C\" {
|
||||||
|
#endif
|
||||||
|
"""
|
||||||
|
trailer = """\
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
"""
|
"""
|
||||||
trailer = "}"
|
|
||||||
include_guard = "PF_PATHFINDER_H"
|
|
||||||
include_version = true
|
include_version = true
|
||||||
|
|
||||||
[parse]
|
[parse]
|
||||||
parse_deps = true
|
parse_deps = true
|
||||||
include = [
|
include = [
|
||||||
|
"font-kit",
|
||||||
"pathfinder_canvas",
|
"pathfinder_canvas",
|
||||||
"pathfinder_content",
|
"pathfinder_content",
|
||||||
"pathfinder_geometry",
|
"pathfinder_geometry",
|
||||||
"pathfinder_gl",
|
"pathfinder_gl",
|
||||||
|
"pathfinder_gpu",
|
||||||
|
"pathfinder_metal",
|
||||||
"pathfinder_renderer",
|
"pathfinder_renderer",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[export.rename]
|
||||||
|
"BuildOptions" = "PFBuildOptionsPrivate"
|
||||||
|
"CanvasFontContext" = "PFCanvasFontContextPrivate"
|
||||||
|
"CanvasRenderingContext2D" = "PFCanvasRenderingContext2DPrivate"
|
||||||
|
"DestFramebuffer_GLDevice" = "PFDestFramebufferGLDevicePrivate"
|
||||||
|
"DestFramebuffer_MetalDevice" = "PFDestFramebufferMetalDevicePrivate"
|
||||||
|
"FillStyle" = "PFFillStylePrivate"
|
||||||
|
"GLDevice" = "PFGLDevicePrivate"
|
||||||
|
"Handle" = "FKHandlePrivate"
|
||||||
|
"MetalDevice" = "PFMetalDevicePrivate"
|
||||||
|
"Path2D" = "PFPath2DPrivate"
|
||||||
|
"RenderTransform" = "PFRenderTransformPrivate"
|
||||||
|
"Renderer_GLDevice" = "PFRendererGLDevicePrivate"
|
||||||
|
"Renderer_MetalDevice" = "PFRendererMetalDevicePrivate"
|
||||||
|
"ResourceLoaderWrapper" = "PFResourceLoaderWrapperPrivate"
|
||||||
|
"Scene" = "PFScenePrivate"
|
||||||
|
"SceneProxy" = "PFSceneProxyPrivate"
|
||||||
|
|
197
c/src/lib.rs
197
c/src/lib.rs
|
@ -19,6 +19,8 @@ use pathfinder_content::color::{ColorF, ColorU};
|
||||||
use pathfinder_content::outline::ArcDirection;
|
use pathfinder_content::outline::ArcDirection;
|
||||||
use pathfinder_content::stroke::LineCap;
|
use pathfinder_content::stroke::LineCap;
|
||||||
use pathfinder_geometry::rect::{RectF, RectI};
|
use pathfinder_geometry::rect::{RectF, RectI};
|
||||||
|
use pathfinder_geometry::transform2d::{Matrix2x2F, Transform2F};
|
||||||
|
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader};
|
use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader};
|
||||||
|
@ -26,7 +28,7 @@ use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
|
||||||
use pathfinder_renderer::scene::Scene;
|
use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
@ -60,6 +62,11 @@ pub const PF_TEXT_ALIGN_RIGHT: u8 = 2;
|
||||||
pub const PF_ARC_DIRECTION_CW: u8 = 0;
|
pub const PF_ARC_DIRECTION_CW: u8 = 0;
|
||||||
pub const PF_ARC_DIRECTION_CCW: u8 = 1;
|
pub const PF_ARC_DIRECTION_CCW: u8 = 1;
|
||||||
|
|
||||||
|
// `gl`
|
||||||
|
|
||||||
|
pub const PF_GL_VERSION_GL3: u8 = 0;
|
||||||
|
pub const PF_GL_VERSION_GLES3: u8 = 1;
|
||||||
|
|
||||||
// `renderer`
|
// `renderer`
|
||||||
|
|
||||||
pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1;
|
pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1;
|
||||||
|
@ -120,10 +127,35 @@ pub struct PFRectI {
|
||||||
pub origin: PFVector2I,
|
pub origin: PFVector2I,
|
||||||
pub lower_right: PFVector2I,
|
pub lower_right: PFVector2I,
|
||||||
}
|
}
|
||||||
|
/// Row-major order.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PFMatrix2x2F {
|
||||||
|
pub m00: f32, pub m01: f32,
|
||||||
|
pub m10: f32, pub m11: f32,
|
||||||
|
}
|
||||||
|
/// Row-major order.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PFTransform2F {
|
||||||
|
pub matrix: PFMatrix2x2F,
|
||||||
|
pub vector: PFVector2F,
|
||||||
|
}
|
||||||
|
/// Row-major order.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PFTransform4F {
|
||||||
|
pub m00: f32, pub m01: f32, pub m02: f32, pub m03: f32,
|
||||||
|
pub m10: f32, pub m11: f32, pub m12: f32, pub m13: f32,
|
||||||
|
pub m20: f32, pub m21: f32, pub m22: f32, pub m23: f32,
|
||||||
|
pub m30: f32, pub m31: f32, pub m32: f32, pub m33: f32,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PFPerspective {
|
||||||
|
pub transform: PFTransform4F,
|
||||||
|
pub window_size: PFVector2I,
|
||||||
|
}
|
||||||
|
|
||||||
// `gl`
|
// `gl`
|
||||||
pub type PFGLDeviceRef = *mut GLDevice;
|
pub type PFGLDeviceRef = *mut GLDevice;
|
||||||
pub type PFGLVersion = GLVersion;
|
pub type PFGLVersion = u8;
|
||||||
pub type PFGLFunctionLoader = extern "C" fn(name: *const c_char, userdata: *mut c_void)
|
pub type PFGLFunctionLoader = extern "C" fn(name: *const c_char, userdata: *mut c_void)
|
||||||
-> *const c_void;
|
-> *const c_void;
|
||||||
// `gpu`
|
// `gpu`
|
||||||
|
@ -135,7 +167,8 @@ pub type PFMetalDestFramebufferRef = *mut DestFramebuffer<MetalDevice>;
|
||||||
pub type PFMetalRendererRef = *mut Renderer<MetalDevice>;
|
pub type PFMetalRendererRef = *mut Renderer<MetalDevice>;
|
||||||
// FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is
|
// FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is
|
||||||
// stable?
|
// stable?
|
||||||
pub type PFResourceLoaderRef = *mut Box<dyn ResourceLoader>;
|
pub type PFResourceLoaderRef = *mut ResourceLoaderWrapper;
|
||||||
|
pub struct ResourceLoaderWrapper(Box<dyn ResourceLoader>);
|
||||||
|
|
||||||
// `metal`
|
// `metal`
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
|
@ -150,20 +183,18 @@ pub struct PFRendererOptions {
|
||||||
pub flags: PFRendererOptionsFlags,
|
pub flags: PFRendererOptionsFlags,
|
||||||
}
|
}
|
||||||
pub type PFRendererOptionsFlags = u8;
|
pub type PFRendererOptionsFlags = u8;
|
||||||
// TODO(pcwalton)
|
pub type PFBuildOptionsRef = *mut BuildOptions;
|
||||||
#[repr(C)]
|
pub type PFRenderTransformRef = *mut RenderTransform;
|
||||||
pub struct PFBuildOptions {
|
|
||||||
pub placeholder: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
// `canvas`
|
// `canvas`
|
||||||
|
|
||||||
/// Consumes the font context.
|
/// This function internally adds a reference to the font context. Therefore, if you created the
|
||||||
|
/// font context, you must release it yourself to avoid a leak.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFCanvasCreate(font_context: PFCanvasFontContextRef,
|
pub unsafe extern "C" fn PFCanvasCreate(font_context: PFCanvasFontContextRef,
|
||||||
size: *const PFVector2F)
|
size: *const PFVector2F)
|
||||||
-> PFCanvasRef {
|
-> PFCanvasRef {
|
||||||
Box::into_raw(Box::new(CanvasRenderingContext2D::new(*Box::from_raw(font_context),
|
Box::into_raw(Box::new(CanvasRenderingContext2D::new((*font_context).clone(),
|
||||||
(*size).to_rust())))
|
(*size).to_rust())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,17 +219,18 @@ pub unsafe extern "C" fn PFCanvasFontContextCreateWithFonts(fonts: *const FKHand
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFCanvasFontContextDestroy(font_context: PFCanvasFontContextRef) {
|
pub unsafe extern "C" fn PFCanvasFontContextAddRef(font_context: PFCanvasFontContextRef)
|
||||||
drop(Box::from_raw(font_context))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn PFCanvasFontContextClone(font_context: PFCanvasFontContextRef)
|
|
||||||
-> PFCanvasFontContextRef {
|
-> PFCanvasFontContextRef {
|
||||||
Box::into_raw(Box::new((*font_context).clone()))
|
Box::into_raw(Box::new((*font_context).clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the canvas.
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFCanvasFontContextRelease(font_context: PFCanvasFontContextRef) {
|
||||||
|
drop(Box::from_raw(font_context))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function takes ownership of the supplied canvas and will automatically destroy it when
|
||||||
|
/// the scene is destroyed.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef {
|
pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef {
|
||||||
Box::into_raw(Box::new(Box::from_raw(canvas).into_scene()))
|
Box::into_raw(Box::new(Box::from_raw(canvas).into_scene()))
|
||||||
|
@ -315,13 +347,15 @@ pub unsafe extern "C" fn PFCanvasSetStrokeStyle(canvas: PFCanvasRef,
|
||||||
(*canvas).set_stroke_style(*stroke_style)
|
(*canvas).set_stroke_style(*stroke_style)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the path.
|
/// This function automatically destroys the path. If you wish to use the path again, clone it
|
||||||
|
/// first.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) {
|
pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) {
|
||||||
(*canvas).fill_path(*Box::from_raw(path))
|
(*canvas).fill_path(*Box::from_raw(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the path.
|
/// This function automatically destroys the path. If you wish to use the path again, clone it
|
||||||
|
/// first.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFCanvasStrokePath(canvas: PFCanvasRef, path: PFPathRef) {
|
pub unsafe extern "C" fn PFCanvasStrokePath(canvas: PFCanvasRef, path: PFPathRef) {
|
||||||
(*canvas).stroke_path(*Box::from_raw(path))
|
(*canvas).stroke_path(*Box::from_raw(path))
|
||||||
|
@ -421,7 +455,7 @@ pub unsafe extern "C" fn PFFillStyleDestroy(fill_style: PFFillStyleRef) {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFFilesystemResourceLoaderLocate() -> PFResourceLoaderRef {
|
pub unsafe extern "C" fn PFFilesystemResourceLoaderLocate() -> PFResourceLoaderRef {
|
||||||
let loader = Box::new(FilesystemResourceLoader::locate());
|
let loader = Box::new(FilesystemResourceLoader::locate());
|
||||||
Box::into_raw(Box::new(loader as Box<dyn ResourceLoader>))
|
Box::into_raw(Box::new(ResourceLoaderWrapper(loader as Box<dyn ResourceLoader>)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -435,6 +469,7 @@ pub unsafe extern "C" fn PFGLLoadWith(loader: PFGLFunctionLoader, userdata: *mut
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFGLDeviceCreate(version: PFGLVersion, default_framebuffer: u32)
|
pub unsafe extern "C" fn PFGLDeviceCreate(version: PFGLVersion, default_framebuffer: u32)
|
||||||
-> PFGLDeviceRef {
|
-> PFGLDeviceRef {
|
||||||
|
let version = match version { PF_GL_VERSION_GLES3 => GLVersion::GLES3, _ => GLVersion::GL3 };
|
||||||
Box::into_raw(Box::new(GLDevice::new(version, default_framebuffer)))
|
Box::into_raw(Box::new(GLDevice::new(version, default_framebuffer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +496,9 @@ pub unsafe extern "C" fn PFGLDestFramebufferDestroy(dest_framebuffer: PFGLDestFr
|
||||||
drop(Box::from_raw(dest_framebuffer))
|
drop(Box::from_raw(dest_framebuffer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes ownership of `device` and `dest_framebuffer`, but not `resources`.
|
/// This function takes ownership of and automatically takes responsibility for destroying `device`
|
||||||
|
/// and `dest_framebuffer`. However, it does not take ownership of `resources`; therefore, if you
|
||||||
|
/// created the resource loader, you must destroy it yourself to avoid a memory leak.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef,
|
pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef,
|
||||||
resources: PFResourceLoaderRef,
|
resources: PFResourceLoaderRef,
|
||||||
|
@ -469,7 +506,7 @@ pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef,
|
||||||
options: *const PFRendererOptions)
|
options: *const PFRendererOptions)
|
||||||
-> PFGLRendererRef {
|
-> PFGLRendererRef {
|
||||||
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
|
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
|
||||||
&**resources,
|
&*((*resources).0),
|
||||||
*Box::from_raw(dest_framebuffer),
|
*Box::from_raw(dest_framebuffer),
|
||||||
(*options).to_rust())))
|
(*options).to_rust())))
|
||||||
}
|
}
|
||||||
|
@ -498,7 +535,9 @@ pub unsafe extern "C" fn PFMetalDestFramebufferDestroy(dest_framebuffer:
|
||||||
drop(Box::from_raw(dest_framebuffer))
|
drop(Box::from_raw(dest_framebuffer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes ownership of `device` and `dest_framebuffer`, but not `resources`.
|
/// This function takes ownership of and automatically takes responsibility for destroying `device`
|
||||||
|
/// and `dest_framebuffer`. However, it does not take ownership of `resources`; therefore, if you
|
||||||
|
/// created the resource loader, you must destroy it yourself to avoid a memory leak.
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef,
|
pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef,
|
||||||
|
@ -507,7 +546,7 @@ pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef,
|
||||||
options: *const PFRendererOptions)
|
options: *const PFRendererOptions)
|
||||||
-> PFMetalRendererRef {
|
-> PFMetalRendererRef {
|
||||||
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
|
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
|
||||||
&**resources,
|
&*((*resources).0),
|
||||||
*Box::from_raw(dest_framebuffer),
|
*Box::from_raw(dest_framebuffer),
|
||||||
(*options).to_rust())))
|
(*options).to_rust())))
|
||||||
}
|
}
|
||||||
|
@ -518,25 +557,33 @@ pub unsafe extern "C" fn PFMetalRendererDestroy(renderer: PFMetalRendererRef) {
|
||||||
drop(Box::from_raw(renderer))
|
drop(Box::from_raw(renderer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the Metal device in the renderer.
|
||||||
|
///
|
||||||
|
/// This reference remains valid as long as the device is alive.
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFMetalRendererGetDevice(renderer: PFMetalRendererRef) -> PFMetalDeviceRef {
|
pub unsafe extern "C" fn PFMetalRendererGetDevice(renderer: PFMetalRendererRef)
|
||||||
|
-> PFMetalDeviceRef {
|
||||||
&mut (*renderer).device
|
&mut (*renderer).device
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function does not take ownership of `renderer` or `build_options`. Therefore, if you
|
||||||
|
/// created the renderer and/or options, you must destroy them yourself to avoid a leak.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef,
|
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef,
|
||||||
renderer: PFGLRendererRef,
|
renderer: PFGLRendererRef,
|
||||||
build_options: *const PFBuildOptions) {
|
build_options: PFBuildOptionsRef) {
|
||||||
(*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust())
|
(*scene_proxy).build_and_render(&mut *renderer, (*build_options).clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function does not take ownership of `renderer` or `build_options`. Therefore, if you
|
||||||
|
/// created the renderer and/or options, you must destroy them yourself to avoid a leak.
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderMetal(scene_proxy: PFSceneProxyRef,
|
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderMetal(scene_proxy: PFSceneProxyRef,
|
||||||
renderer: PFMetalRendererRef,
|
renderer: PFMetalRendererRef,
|
||||||
build_options: *const PFBuildOptions) {
|
build_options: PFBuildOptionsRef) {
|
||||||
(*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust())
|
(*scene_proxy).build_and_render(&mut *renderer, (*build_options).clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
// `metal`
|
// `metal`
|
||||||
|
@ -554,8 +601,60 @@ pub unsafe extern "C" fn PFMetalDeviceDestroy(device: PFMetalDeviceRef) {
|
||||||
drop(Box::from_raw(device))
|
drop(Box::from_raw(device))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFMetalDevicePresentDrawable(device: PFMetalDeviceRef) {
|
||||||
|
(*device).present_drawable()
|
||||||
|
}
|
||||||
|
|
||||||
// `renderer`
|
// `renderer`
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFRenderTransformCreate2D(transform: *const PFTransform2F)
|
||||||
|
-> PFRenderTransformRef {
|
||||||
|
Box::into_raw(Box::new(RenderTransform::Transform2D((*transform).to_rust())))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFRenderTransformCreatePerspective(perspective: *const PFPerspective)
|
||||||
|
-> PFRenderTransformRef {
|
||||||
|
Box::into_raw(Box::new(RenderTransform::Perspective((*perspective).to_rust())))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFRenderTransformDestroy(transform: PFRenderTransformRef) {
|
||||||
|
drop(Box::from_raw(transform))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFBuildOptionsCreate() -> PFBuildOptionsRef {
|
||||||
|
Box::into_raw(Box::new(BuildOptions::default()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFBuildOptionsDestroy(options: PFBuildOptionsRef) {
|
||||||
|
drop(Box::from_raw(options))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes the transform.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFBuildOptionsSetTransform(options: PFBuildOptionsRef,
|
||||||
|
transform: PFRenderTransformRef) {
|
||||||
|
(*options).transform = *Box::from_raw(transform)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFBuildOptionsSetDilation(options: PFBuildOptionsRef,
|
||||||
|
dilation: *const PFVector2F) {
|
||||||
|
(*options).dilation = (*dilation).to_rust()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn PFBuildOptionsSetSubpixelAAEnabled(options: PFBuildOptionsRef,
|
||||||
|
subpixel_aa_enabled: bool) {
|
||||||
|
(*options).subpixel_aa_enabled = subpixel_aa_enabled
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
|
pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
|
||||||
drop(Box::from_raw(scene))
|
drop(Box::from_raw(scene))
|
||||||
|
@ -637,6 +736,40 @@ impl PFVector2I {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PFMatrix2x2F {
|
||||||
|
#[inline]
|
||||||
|
pub fn to_rust(&self) -> Matrix2x2F {
|
||||||
|
Matrix2x2F::row_major(self.m00, self.m01, self.m10, self.m11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PFTransform2F {
|
||||||
|
#[inline]
|
||||||
|
pub fn to_rust(&self) -> Transform2F {
|
||||||
|
Transform2F { matrix: self.matrix.to_rust(), vector: self.vector.to_rust() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PFTransform4F {
|
||||||
|
#[inline]
|
||||||
|
pub fn to_rust(&self) -> Transform4F {
|
||||||
|
Transform4F::row_major(self.m00, self.m01, self.m02, self.m03,
|
||||||
|
self.m10, self.m11, self.m12, self.m13,
|
||||||
|
self.m20, self.m21, self.m22, self.m23,
|
||||||
|
self.m30, self.m31, self.m32, self.m33)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PFPerspective {
|
||||||
|
#[inline]
|
||||||
|
pub fn to_rust(&self) -> Perspective {
|
||||||
|
Perspective {
|
||||||
|
transform: self.transform.to_rust(),
|
||||||
|
window_size: self.window_size.to_rust(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helpers for `renderer`
|
// Helpers for `renderer`
|
||||||
|
|
||||||
impl PFRendererOptions {
|
impl PFRendererOptions {
|
||||||
|
@ -651,9 +784,3 @@ impl PFRendererOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PFBuildOptions {
|
|
||||||
pub fn to_rust(&self) -> BuildOptions {
|
|
||||||
BuildOptions::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_renderer::paint::{Paint, PaintId};
|
use pathfinder_renderer::paint::{Paint, PaintId};
|
||||||
use pathfinder_renderer::scene::{PathObject, Scene};
|
use pathfinder_renderer::scene::{PathObject, Scene};
|
||||||
use pathfinder_text::{SceneExt, TextRenderMode};
|
use pathfinder_text::{SceneExt, TextRenderMode};
|
||||||
|
@ -125,8 +125,7 @@ impl CanvasRenderingContext2D {
|
||||||
TextAlign::Center => position.set_x(position.x() - layout.width() * 0.5),
|
TextAlign::Center => position.set_x(position.x() - layout.width() * 0.5),
|
||||||
}
|
}
|
||||||
|
|
||||||
let transform = Transform2DF::from_translation(position).post_mul(&self.current_state
|
let transform = self.current_state.transform * Transform2F::from_translation(position);
|
||||||
.transform);
|
|
||||||
|
|
||||||
// TODO(pcwalton): Report errors.
|
// TODO(pcwalton): Report errors.
|
||||||
drop(self.scene.push_layout(&layout,
|
drop(self.scene.push_layout(&layout,
|
||||||
|
@ -296,7 +295,7 @@ impl CanvasRenderingContext2D {
|
||||||
let paint_id = self.scene.push_paint(&paint);
|
let paint_id = self.scene.push_paint(&paint);
|
||||||
|
|
||||||
let mut outline = outline.clone();
|
let mut outline = outline.clone();
|
||||||
outline.transform(&Transform2DF::from_translation(self.current_state.shadow_offset));
|
outline.transform(&Transform2F::from_translation(self.current_state.shadow_offset));
|
||||||
self.scene.push_path(PathObject::new(outline, paint_id, String::new()))
|
self.scene.push_path(PathObject::new(outline, paint_id, String::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,18 +305,18 @@ impl CanvasRenderingContext2D {
|
||||||
// Transformations
|
// Transformations
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_transform(&self) -> Transform2DF {
|
pub fn current_transform(&self) -> Transform2F {
|
||||||
self.current_state.transform
|
self.current_state.transform
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_current_transform(&mut self, new_transform: &Transform2DF) {
|
pub fn set_current_transform(&mut self, new_transform: &Transform2F) {
|
||||||
self.current_state.transform = *new_transform;
|
self.current_state.transform = *new_transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset_transform(&mut self) {
|
pub fn reset_transform(&mut self) {
|
||||||
self.current_state.transform = Transform2DF::default();
|
self.current_state.transform = Transform2F::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compositing
|
// Compositing
|
||||||
|
@ -349,7 +348,7 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct State {
|
struct State {
|
||||||
transform: Transform2DF,
|
transform: Transform2F,
|
||||||
font_collection: Arc<FontCollection>,
|
font_collection: Arc<FontCollection>,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
line_width: f32,
|
line_width: f32,
|
||||||
|
@ -369,7 +368,7 @@ struct State {
|
||||||
impl State {
|
impl State {
|
||||||
fn default(default_font_collection: Arc<FontCollection>) -> State {
|
fn default(default_font_collection: Arc<FontCollection>) -> State {
|
||||||
State {
|
State {
|
||||||
transform: Transform2DF::default(),
|
transform: Transform2F::default(),
|
||||||
font_collection: default_font_collection,
|
font_collection: default_font_collection,
|
||||||
font_size: DEFAULT_FONT_SIZE,
|
font_size: DEFAULT_FONT_SIZE,
|
||||||
line_width: 1.0,
|
line_width: 1.0,
|
||||||
|
@ -452,8 +451,7 @@ impl Path2D {
|
||||||
start_angle: f32,
|
start_angle: f32,
|
||||||
end_angle: f32,
|
end_angle: f32,
|
||||||
direction: ArcDirection) {
|
direction: ArcDirection) {
|
||||||
let mut transform = Transform2DF::from_scale(Vector2F::splat(radius));
|
let transform = Transform2F::from_scale(Vector2F::splat(radius)).translate(center);
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(center));
|
|
||||||
self.current_contour.push_arc(&transform, start_angle, end_angle, direction);
|
self.current_contour.push_arc(&transform, start_angle, end_angle, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,8 +465,7 @@ impl Path2D {
|
||||||
let bisector = vu0 + vu1;
|
let bisector = vu0 + vu1;
|
||||||
let center = ctrl + bisector.scale(hypot / bisector.length());
|
let center = ctrl + bisector.scale(hypot / bisector.length());
|
||||||
|
|
||||||
let mut transform = Transform2DF::from_scale(Vector2F::splat(radius));
|
let transform = Transform2F::from_scale(Vector2F::splat(radius)).translate(center);
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(center));
|
|
||||||
|
|
||||||
let chord = LineSegment2F::new(vu0.yx().scale_xy(Vector2F::new(-1.0, 1.0)),
|
let chord = LineSegment2F::new(vu0.yx().scale_xy(Vector2F::new(-1.0, 1.0)),
|
||||||
vu1.yx().scale_xy(Vector2F::new(1.0, -1.0)));
|
vu1.yx().scale_xy(Vector2F::new(1.0, -1.0)));
|
||||||
|
@ -494,9 +491,7 @@ impl Path2D {
|
||||||
end_angle: f32) {
|
end_angle: f32) {
|
||||||
self.flush_current_contour();
|
self.flush_current_contour();
|
||||||
|
|
||||||
let mut transform = Transform2DF::from_rotation(rotation);
|
let transform = Transform2F::from_scale(axes).rotate(rotation).translate(center);
|
||||||
transform = transform.post_mul(&Transform2DF::from_scale(axes));
|
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(center));
|
|
||||||
self.current_contour.push_arc(&transform, start_angle, end_angle, ArcDirection::CW);
|
self.current_contour.push_arc(&transform, start_angle, end_angle, ArcDirection::CW);
|
||||||
|
|
||||||
if end_angle - start_angle >= 2.0 * PI {
|
if end_angle - start_angle >= 2.0 * PI {
|
||||||
|
|
|
@ -24,15 +24,15 @@ struct Edge(LineSegment2F);
|
||||||
|
|
||||||
impl TEdge for Edge {
|
impl TEdge for Edge {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn point_is_inside(&self, point: &Vector2F) -> bool {
|
fn point_is_inside(&self, point: Vector2F) -> bool {
|
||||||
let area = (self.0.to() - self.0.from()).det(*point - self.0.from());
|
let area = (self.0.to() - self.0.from()).det(point - self.0.from());
|
||||||
debug!("point_is_inside({:?}, {:?}), area={}", self, point, area);
|
debug!("point_is_inside({:?}, {:?}), area={}", self, point, area);
|
||||||
area >= 0.0
|
area >= 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intersect_line_segment(&self, segment: &LineSegment2F) -> ArrayVec<[f32; 3]> {
|
fn intersect_line_segment(&self, segment: LineSegment2F) -> ArrayVec<[f32; 3]> {
|
||||||
let mut results = ArrayVec::new();
|
let mut results = ArrayVec::new();
|
||||||
if let Some(t) = segment.intersection_t(&self.0) {
|
if let Some(t) = segment.intersection_t(self.0) {
|
||||||
if t >= 0.0 && t <= 1.0 {
|
if t >= 0.0 && t <= 1.0 {
|
||||||
results.push(t);
|
results.push(t);
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ enum AxisAlignedEdge {
|
||||||
|
|
||||||
impl TEdge for AxisAlignedEdge {
|
impl TEdge for AxisAlignedEdge {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn point_is_inside(&self, point: &Vector2F) -> bool {
|
fn point_is_inside(&self, point: Vector2F) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
AxisAlignedEdge::Left(x) => point.x() >= x,
|
AxisAlignedEdge::Left(x) => point.x() >= x,
|
||||||
AxisAlignedEdge::Top(y) => point.y() >= y,
|
AxisAlignedEdge::Top(y) => point.y() >= y,
|
||||||
|
@ -60,7 +60,7 @@ impl TEdge for AxisAlignedEdge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intersect_line_segment(&self, segment: &LineSegment2F) -> ArrayVec<[f32; 3]> {
|
fn intersect_line_segment(&self, segment: LineSegment2F) -> ArrayVec<[f32; 3]> {
|
||||||
let mut results = ArrayVec::new();
|
let mut results = ArrayVec::new();
|
||||||
let t = match *self {
|
let t = match *self {
|
||||||
AxisAlignedEdge::Left(x) | AxisAlignedEdge::Right(x) => segment.solve_t_for_x(x),
|
AxisAlignedEdge::Left(x) | AxisAlignedEdge::Right(x) => segment.solve_t_for_x(x),
|
||||||
|
@ -74,26 +74,26 @@ impl TEdge for AxisAlignedEdge {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait TEdge: Debug {
|
trait TEdge: Debug {
|
||||||
fn point_is_inside(&self, point: &Vector2F) -> bool;
|
fn point_is_inside(&self, point: Vector2F) -> bool;
|
||||||
fn intersect_line_segment(&self, segment: &LineSegment2F) -> ArrayVec<[f32; 3]>;
|
fn intersect_line_segment(&self, segment: LineSegment2F) -> ArrayVec<[f32; 3]>;
|
||||||
|
|
||||||
fn trivially_test_segment(&self, segment: &Segment) -> EdgeRelativeLocation {
|
fn trivially_test_segment(&self, segment: &Segment) -> EdgeRelativeLocation {
|
||||||
let from_inside = self.point_is_inside(&segment.baseline.from());
|
let from_inside = self.point_is_inside(segment.baseline.from());
|
||||||
debug!(
|
debug!(
|
||||||
"point {:?} inside {:?}: {:?}",
|
"point {:?} inside {:?}: {:?}",
|
||||||
segment.baseline.from(),
|
segment.baseline.from(),
|
||||||
self,
|
self,
|
||||||
from_inside
|
from_inside
|
||||||
);
|
);
|
||||||
if from_inside != self.point_is_inside(&segment.baseline.to()) {
|
if from_inside != self.point_is_inside(segment.baseline.to()) {
|
||||||
return EdgeRelativeLocation::Intersecting;
|
return EdgeRelativeLocation::Intersecting;
|
||||||
}
|
}
|
||||||
if !segment.is_line() {
|
if !segment.is_line() {
|
||||||
if from_inside != self.point_is_inside(&segment.ctrl.from()) {
|
if from_inside != self.point_is_inside(segment.ctrl.from()) {
|
||||||
return EdgeRelativeLocation::Intersecting;
|
return EdgeRelativeLocation::Intersecting;
|
||||||
}
|
}
|
||||||
if !segment.is_quadratic() {
|
if !segment.is_quadratic() {
|
||||||
if from_inside != self.point_is_inside(&segment.ctrl.to()) {
|
if from_inside != self.point_is_inside(segment.ctrl.to()) {
|
||||||
return EdgeRelativeLocation::Intersecting;
|
return EdgeRelativeLocation::Intersecting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ trait TEdge: Debug {
|
||||||
|
|
||||||
fn intersect_segment(&self, segment: &Segment) -> ArrayVec<[f32; 3]> {
|
fn intersect_segment(&self, segment: &Segment) -> ArrayVec<[f32; 3]> {
|
||||||
if segment.is_line() {
|
if segment.is_line() {
|
||||||
return self.intersect_line_segment(&segment.baseline);
|
return self.intersect_line_segment(segment.baseline);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut segment = *segment;
|
let mut segment = *segment;
|
||||||
|
@ -173,10 +173,10 @@ trait TEdge: Debug {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intersects_cubic_segment_hull(&self, cubic_segment: CubicSegment) -> bool {
|
fn intersects_cubic_segment_hull(&self, cubic_segment: CubicSegment) -> bool {
|
||||||
let inside = self.point_is_inside(&cubic_segment.0.baseline.from());
|
let inside = self.point_is_inside(cubic_segment.0.baseline.from());
|
||||||
inside != self.point_is_inside(&cubic_segment.0.ctrl.from())
|
inside != self.point_is_inside(cubic_segment.0.ctrl.from())
|
||||||
|| inside != self.point_is_inside(&cubic_segment.0.ctrl.to())
|
|| inside != self.point_is_inside(cubic_segment.0.ctrl.to())
|
||||||
|| inside != self.point_is_inside(&cubic_segment.0.baseline.to())
|
|| inside != self.point_is_inside(cubic_segment.0.baseline.to())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ where
|
||||||
|
|
||||||
// We have a potential intersection.
|
// We have a potential intersection.
|
||||||
debug!("potential intersection: {:?} edge: {:?}", segment, edge);
|
debug!("potential intersection: {:?} edge: {:?}", segment, edge);
|
||||||
let mut starts_inside = edge.point_is_inside(&segment.baseline.from());
|
let mut starts_inside = edge.point_is_inside(segment.baseline.from());
|
||||||
let intersection_ts = edge.intersect_segment(&segment);
|
let intersection_ts = edge.intersect_segment(&segment);
|
||||||
let mut last_t = 0.0;
|
let mut last_t = 0.0;
|
||||||
debug!("... intersections: {:?}", intersection_ts);
|
debug!("... intersections: {:?}", intersection_ts);
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::orientation::Orientation;
|
||||||
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::unit_vector::UnitVector;
|
use pathfinder_geometry::unit_vector::UnitVector;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
|
@ -134,7 +134,7 @@ impl Outline {
|
||||||
self.contours.push(contour);
|
self.contours.push(contour);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform(&mut self, transform: &Transform2DF) {
|
pub fn transform(&mut self, transform: &Transform2F) {
|
||||||
if transform.is_identity() {
|
if transform.is_identity() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -353,7 +353,7 @@ impl Contour {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_arc(&mut self,
|
pub fn push_arc(&mut self,
|
||||||
transform: &Transform2DF,
|
transform: &Transform2F,
|
||||||
start_angle: f32,
|
start_angle: f32,
|
||||||
end_angle: f32,
|
end_angle: f32,
|
||||||
direction: ArcDirection) {
|
direction: ArcDirection) {
|
||||||
|
@ -367,13 +367,13 @@ impl Contour {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_arc_from_unit_chord(&mut self,
|
pub fn push_arc_from_unit_chord(&mut self,
|
||||||
transform: &Transform2DF,
|
transform: &Transform2F,
|
||||||
mut chord: LineSegment2F,
|
mut chord: LineSegment2F,
|
||||||
direction: ArcDirection) {
|
direction: ArcDirection) {
|
||||||
let mut direction_transform = Transform2DF::default();
|
let mut direction_transform = Transform2F::default();
|
||||||
if direction == ArcDirection::CCW {
|
if direction == ArcDirection::CCW {
|
||||||
chord = chord.scale_xy(Vector2F::new(-1.0, 1.0));
|
chord = chord.scale_xy(Vector2F::new(-1.0, 1.0));
|
||||||
direction_transform = Transform2DF::from_scale(Vector2F::new(-1.0, 1.0));
|
direction_transform = Transform2F::from_scale(Vector2F::new(-1.0, 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut vector, end_vector) = (UnitVector(chord.from()), UnitVector(chord.to()));
|
let (mut vector, end_vector) = (UnitVector(chord.from()), UnitVector(chord.to()));
|
||||||
|
@ -392,9 +392,8 @@ impl Contour {
|
||||||
}
|
}
|
||||||
|
|
||||||
let half_sweep_vector = sweep_vector.halve_angle();
|
let half_sweep_vector = sweep_vector.halve_angle();
|
||||||
let rotation = Transform2DF::from_rotation_vector(half_sweep_vector.rotate_by(vector));
|
let rotation = Transform2F::from_rotation_vector(half_sweep_vector.rotate_by(vector));
|
||||||
segment = segment.transform(&direction_transform.post_mul(&rotation)
|
segment = segment.transform(&(*transform * rotation * direction_transform));
|
||||||
.post_mul(&transform));
|
|
||||||
|
|
||||||
let mut push_segment_flags = PushSegmentFlags::UPDATE_BOUNDS;
|
let mut push_segment_flags = PushSegmentFlags::UPDATE_BOUNDS;
|
||||||
if first_segment {
|
if first_segment {
|
||||||
|
@ -413,19 +412,19 @@ impl Contour {
|
||||||
const EPSILON: f32 = 0.001;
|
const EPSILON: f32 = 0.001;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_ellipse(&mut self, transform: &Transform2DF) {
|
pub fn push_ellipse(&mut self, transform: &Transform2F) {
|
||||||
let segment = Segment::quarter_circle_arc();
|
let segment = Segment::quarter_circle_arc();
|
||||||
let mut rotation;
|
let mut rotation;
|
||||||
self.push_segment(&segment.transform(transform),
|
self.push_segment(&segment.transform(transform),
|
||||||
PushSegmentFlags::UPDATE_BOUNDS | PushSegmentFlags::INCLUDE_FROM_POINT);
|
PushSegmentFlags::UPDATE_BOUNDS | PushSegmentFlags::INCLUDE_FROM_POINT);
|
||||||
rotation = Transform2DF::from_rotation_vector(UnitVector(Vector2F::new( 0.0, 1.0)));
|
rotation = Transform2F::from_rotation_vector(UnitVector(Vector2F::new( 0.0, 1.0)));
|
||||||
self.push_segment(&segment.transform(&rotation.post_mul(&transform)),
|
self.push_segment(&segment.transform(&(*transform * rotation)),
|
||||||
PushSegmentFlags::UPDATE_BOUNDS);
|
PushSegmentFlags::UPDATE_BOUNDS);
|
||||||
rotation = Transform2DF::from_rotation_vector(UnitVector(Vector2F::new(-1.0, 0.0)));
|
rotation = Transform2F::from_rotation_vector(UnitVector(Vector2F::new(-1.0, 0.0)));
|
||||||
self.push_segment(&segment.transform(&rotation.post_mul(&transform)),
|
self.push_segment(&segment.transform(&(*transform * rotation)),
|
||||||
PushSegmentFlags::UPDATE_BOUNDS);
|
PushSegmentFlags::UPDATE_BOUNDS);
|
||||||
rotation = Transform2DF::from_rotation_vector(UnitVector(Vector2F::new( 0.0, -1.0)));
|
rotation = Transform2F::from_rotation_vector(UnitVector(Vector2F::new( 0.0, -1.0)));
|
||||||
self.push_segment(&segment.transform(&rotation.post_mul(&transform)),
|
self.push_segment(&segment.transform(&(*transform * rotation)),
|
||||||
PushSegmentFlags::UPDATE_BOUNDS);
|
PushSegmentFlags::UPDATE_BOUNDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,25 +433,25 @@ impl Contour {
|
||||||
debug_assert!(self.point_is_endpoint(point_index));
|
debug_assert!(self.point_is_endpoint(point_index));
|
||||||
|
|
||||||
let mut segment = Segment::none();
|
let mut segment = Segment::none();
|
||||||
segment.baseline.set_from(&self.position_of(point_index));
|
segment.baseline.set_from(self.position_of(point_index));
|
||||||
|
|
||||||
let point1_index = self.add_to_point_index(point_index, 1);
|
let point1_index = self.add_to_point_index(point_index, 1);
|
||||||
if self.point_is_endpoint(point1_index) {
|
if self.point_is_endpoint(point1_index) {
|
||||||
segment.baseline.set_to(&self.position_of(point1_index));
|
segment.baseline.set_to(self.position_of(point1_index));
|
||||||
segment.kind = SegmentKind::Line;
|
segment.kind = SegmentKind::Line;
|
||||||
} else {
|
} else {
|
||||||
segment.ctrl.set_from(&self.position_of(point1_index));
|
segment.ctrl.set_from(self.position_of(point1_index));
|
||||||
|
|
||||||
let point2_index = self.add_to_point_index(point_index, 2);
|
let point2_index = self.add_to_point_index(point_index, 2);
|
||||||
if self.point_is_endpoint(point2_index) {
|
if self.point_is_endpoint(point2_index) {
|
||||||
segment.baseline.set_to(&self.position_of(point2_index));
|
segment.baseline.set_to(self.position_of(point2_index));
|
||||||
segment.kind = SegmentKind::Quadratic;
|
segment.kind = SegmentKind::Quadratic;
|
||||||
} else {
|
} else {
|
||||||
segment.ctrl.set_to(&self.position_of(point2_index));
|
segment.ctrl.set_to(self.position_of(point2_index));
|
||||||
segment.kind = SegmentKind::Cubic;
|
segment.kind = SegmentKind::Cubic;
|
||||||
|
|
||||||
let point3_index = self.add_to_point_index(point_index, 3);
|
let point3_index = self.add_to_point_index(point_index, 3);
|
||||||
segment.baseline.set_to(&self.position_of(point3_index));
|
segment.baseline.set_to(self.position_of(point3_index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,20 +527,20 @@ impl Contour {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform(&mut self, transform: &Transform2DF) {
|
pub fn transform(&mut self, transform: &Transform2F) {
|
||||||
if transform.is_identity() {
|
if transform.is_identity() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (point_index, point) in self.points.iter_mut().enumerate() {
|
for (point_index, point) in self.points.iter_mut().enumerate() {
|
||||||
*point = transform.transform_point(*point);
|
*point = *transform * *point;
|
||||||
union_rect(&mut self.bounds, *point, point_index == 0);
|
union_rect(&mut self.bounds, *point, point_index == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_perspective(&mut self, perspective: &Perspective) {
|
pub fn apply_perspective(&mut self, perspective: &Perspective) {
|
||||||
for (point_index, point) in self.points.iter_mut().enumerate() {
|
for (point_index, point) in self.points.iter_mut().enumerate() {
|
||||||
*point = perspective.transform_point_2d(point);
|
*point = *perspective * *point;
|
||||||
union_rect(&mut self.bounds, *point, point_index == 0);
|
union_rect(&mut self.bounds, *point, point_index == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,14 +609,14 @@ impl Contour {
|
||||||
let ctrl_position = &contour.points[ctrl_point_index];
|
let ctrl_position = &contour.points[ctrl_point_index];
|
||||||
handle_cubic(
|
handle_cubic(
|
||||||
self,
|
self,
|
||||||
&Segment::quadratic(&baseline, *ctrl_position).to_cubic(),
|
&Segment::quadratic(baseline, *ctrl_position).to_cubic(),
|
||||||
);
|
);
|
||||||
} else if point_count == 4 {
|
} else if point_count == 4 {
|
||||||
let first_ctrl_point_index = last_endpoint_index as usize + 1;
|
let first_ctrl_point_index = last_endpoint_index as usize + 1;
|
||||||
let ctrl_position_0 = &contour.points[first_ctrl_point_index + 0];
|
let ctrl_position_0 = &contour.points[first_ctrl_point_index + 0];
|
||||||
let ctrl_position_1 = &contour.points[first_ctrl_point_index + 1];
|
let ctrl_position_1 = &contour.points[first_ctrl_point_index + 1];
|
||||||
let ctrl = LineSegment2F::new(*ctrl_position_0, *ctrl_position_1);
|
let ctrl = LineSegment2F::new(*ctrl_position_0, *ctrl_position_1);
|
||||||
handle_cubic(self, &Segment::cubic(&baseline, &ctrl));
|
handle_cubic(self, &Segment::cubic(baseline, ctrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push_point(
|
self.push_point(
|
||||||
|
@ -802,21 +801,21 @@ impl<'a> Iterator for ContourIter<'a> {
|
||||||
if self.index == contour.len() {
|
if self.index == contour.len() {
|
||||||
let point1 = contour.position_of(0);
|
let point1 = contour.position_of(0);
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
return Some(Segment::line(&LineSegment2F::new(point0, point1)));
|
return Some(Segment::line(LineSegment2F::new(point0, point1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let point1_index = self.index;
|
let point1_index = self.index;
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
let point1 = contour.position_of(point1_index);
|
let point1 = contour.position_of(point1_index);
|
||||||
if contour.point_is_endpoint(point1_index) {
|
if contour.point_is_endpoint(point1_index) {
|
||||||
return Some(Segment::line(&LineSegment2F::new(point0, point1)));
|
return Some(Segment::line(LineSegment2F::new(point0, point1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let point2_index = self.index;
|
let point2_index = self.index;
|
||||||
let point2 = contour.position_of(point2_index);
|
let point2 = contour.position_of(point2_index);
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
if contour.point_is_endpoint(point2_index) {
|
if contour.point_is_endpoint(point2_index) {
|
||||||
return Some(Segment::quadratic(&LineSegment2F::new(point0, point2), point1));
|
return Some(Segment::quadratic(LineSegment2F::new(point0, point2), point1));
|
||||||
}
|
}
|
||||||
|
|
||||||
let point3_index = self.index;
|
let point3_index = self.index;
|
||||||
|
@ -824,8 +823,8 @@ impl<'a> Iterator for ContourIter<'a> {
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
debug_assert!(contour.point_is_endpoint(point3_index));
|
debug_assert!(contour.point_is_endpoint(point3_index));
|
||||||
return Some(Segment::cubic(
|
return Some(Segment::cubic(
|
||||||
&LineSegment2F::new(point0, point3),
|
LineSegment2F::new(point0, point3),
|
||||||
&LineSegment2F::new(point1, point2),
|
LineSegment2F::new(point1, point2),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
//! Line or curve segments, optimized with SIMD.
|
//! Line or curve segments, optimized with SIMD.
|
||||||
|
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::util::{self, EPSILON};
|
use pathfinder_geometry::util::{self, EPSILON};
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
|
@ -39,9 +39,9 @@ impl Segment {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn line(line: &LineSegment2F) -> Segment {
|
pub fn line(line: LineSegment2F) -> Segment {
|
||||||
Segment {
|
Segment {
|
||||||
baseline: *line,
|
baseline: line,
|
||||||
ctrl: LineSegment2F::default(),
|
ctrl: LineSegment2F::default(),
|
||||||
kind: SegmentKind::Line,
|
kind: SegmentKind::Line,
|
||||||
flags: SegmentFlags::empty(),
|
flags: SegmentFlags::empty(),
|
||||||
|
@ -49,9 +49,9 @@ impl Segment {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn quadratic(baseline: &LineSegment2F, ctrl: Vector2F) -> Segment {
|
pub fn quadratic(baseline: LineSegment2F, ctrl: Vector2F) -> Segment {
|
||||||
Segment {
|
Segment {
|
||||||
baseline: *baseline,
|
baseline,
|
||||||
ctrl: LineSegment2F::new(ctrl, Vector2F::default()),
|
ctrl: LineSegment2F::new(ctrl, Vector2F::default()),
|
||||||
kind: SegmentKind::Quadratic,
|
kind: SegmentKind::Quadratic,
|
||||||
flags: SegmentFlags::empty(),
|
flags: SegmentFlags::empty(),
|
||||||
|
@ -59,10 +59,10 @@ impl Segment {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cubic(baseline: &LineSegment2F, ctrl: &LineSegment2F) -> Segment {
|
pub fn cubic(baseline: LineSegment2F, ctrl: LineSegment2F) -> Segment {
|
||||||
Segment {
|
Segment {
|
||||||
baseline: *baseline,
|
baseline,
|
||||||
ctrl: *ctrl,
|
ctrl,
|
||||||
kind: SegmentKind::Cubic,
|
kind: SegmentKind::Cubic,
|
||||||
flags: SegmentFlags::empty(),
|
flags: SegmentFlags::empty(),
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ impl Segment {
|
||||||
let (p0x, p0y) = (p3p0.z(), p3p0.w());
|
let (p0x, p0y) = (p3p0.z(), p3p0.w());
|
||||||
let (p1x, p1y) = (4.0 - p0x, (1.0 - p0x) * (3.0 - p0x) / p0y);
|
let (p1x, p1y) = (4.0 - p0x, (1.0 - p0x) * (3.0 - p0x) / p0y);
|
||||||
let p2p1 = F32x4::new(p1x, -p1y, p1x, p1y) * F32x4::splat(1.0 / 3.0);
|
let p2p1 = F32x4::new(p1x, -p1y, p1x, p1y) * F32x4::splat(1.0 / 3.0);
|
||||||
return Segment::cubic(&LineSegment2F(p3p0), &LineSegment2F(p2p1));
|
return Segment::cubic(LineSegment2F(p3p0), LineSegment2F(p2p1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -100,7 +100,7 @@ impl Segment {
|
||||||
let p1 = Vector2F::new(-SQRT_2 / 6.0 + 4.0 / 3.0, 7.0 * SQRT_2 / 6.0 - 4.0 / 3.0);
|
let p1 = Vector2F::new(-SQRT_2 / 6.0 + 4.0 / 3.0, 7.0 * SQRT_2 / 6.0 - 4.0 / 3.0);
|
||||||
let flip = Vector2F::new(1.0, -1.0);
|
let flip = Vector2F::new(1.0, -1.0);
|
||||||
let (p2, p3) = (p1.scale_xy(flip), p0.scale_xy(flip));
|
let (p2, p3) = (p1.scale_xy(flip), p0.scale_xy(flip));
|
||||||
Segment::cubic(&LineSegment2F::new(p3, p0), &LineSegment2F::new(p2, p1))
|
Segment::cubic(LineSegment2F::new(p3, p0), LineSegment2F::new(p2, p1))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -198,7 +198,7 @@ impl Segment {
|
||||||
// FIXME(pcwalton): Don't degree elevate!
|
// FIXME(pcwalton): Don't degree elevate!
|
||||||
if self.is_line() {
|
if self.is_line() {
|
||||||
let (before, after) = self.as_line_segment().split(t);
|
let (before, after) = self.as_line_segment().split(t);
|
||||||
(Segment::line(&before), Segment::line(&after))
|
(Segment::line(before), Segment::line(after))
|
||||||
} else {
|
} else {
|
||||||
self.to_cubic().as_cubic_segment().split(t)
|
self.to_cubic().as_cubic_segment().split(t)
|
||||||
}
|
}
|
||||||
|
@ -215,10 +215,10 @@ impl Segment {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform(self, transform: &Transform2DF) -> Segment {
|
pub fn transform(self, transform: &Transform2F) -> Segment {
|
||||||
Segment {
|
Segment {
|
||||||
baseline: transform.transform_line_segment(&self.baseline),
|
baseline: *transform * self.baseline,
|
||||||
ctrl: transform.transform_line_segment(&self.ctrl),
|
ctrl: *transform * self.ctrl,
|
||||||
kind: self.kind,
|
kind: self.kind,
|
||||||
flags: self.flags,
|
flags: self.flags,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::outline::{ArcDirection, Contour, Outline, PushSegmentFlags};
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ impl<'a> OutlineStrokeToFill<'a> {
|
||||||
stroker.output.add_join(self.style.line_width * 0.5,
|
stroker.output.add_join(self.style.line_width * 0.5,
|
||||||
self.style.line_join,
|
self.style.line_join,
|
||||||
stroker.input.position_of(0),
|
stroker.input.position_of(0),
|
||||||
&final_segment);
|
final_segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
stroker.output.closed = true;
|
stroker.output.closed = true;
|
||||||
|
@ -138,9 +138,8 @@ impl<'a> OutlineStrokeToFill<'a> {
|
||||||
LineCap::Round => {
|
LineCap::Round => {
|
||||||
let scale = Vector2F::splat(width * 0.5);
|
let scale = Vector2F::splat(width * 0.5);
|
||||||
let offset = gradient.yx().scale_xy(Vector2F::new(-1.0, 1.0));
|
let offset = gradient.yx().scale_xy(Vector2F::new(-1.0, 1.0));
|
||||||
let mut transform = Transform2DF::from_scale(scale);
|
|
||||||
let translation = p1 + offset.scale(width * 0.5);
|
let translation = p1 + offset.scale(width * 0.5);
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(translation));
|
let transform = Transform2F::from_scale(scale).translate(translation);
|
||||||
let chord = LineSegment2F::new(-offset, offset);
|
let chord = LineSegment2F::new(-offset, offset);
|
||||||
contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW);
|
contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW);
|
||||||
}
|
}
|
||||||
|
@ -235,7 +234,7 @@ impl Offset for Segment {
|
||||||
self.ctrl.from()
|
self.ctrl.from()
|
||||||
};
|
};
|
||||||
|
|
||||||
contour.add_join(distance, join, join_point, &LineSegment2F::new(p4, p3));
|
contour.add_join(distance, join, join_point, LineSegment2F::new(p4, p3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push segment.
|
// Push segment.
|
||||||
|
@ -245,7 +244,7 @@ impl Offset for Segment {
|
||||||
|
|
||||||
fn offset_once(&self, distance: f32) -> Segment {
|
fn offset_once(&self, distance: f32) -> Segment {
|
||||||
if self.is_line() {
|
if self.is_line() {
|
||||||
return Segment::line(&self.baseline.offset(distance));
|
return Segment::line(self.baseline.offset(distance));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_quadratic() {
|
if self.is_quadratic() {
|
||||||
|
@ -253,12 +252,12 @@ impl Offset for Segment {
|
||||||
let mut segment_1 = LineSegment2F::new(self.ctrl.from(), self.baseline.to());
|
let mut segment_1 = LineSegment2F::new(self.ctrl.from(), self.baseline.to());
|
||||||
segment_0 = segment_0.offset(distance);
|
segment_0 = segment_0.offset(distance);
|
||||||
segment_1 = segment_1.offset(distance);
|
segment_1 = segment_1.offset(distance);
|
||||||
let ctrl = match segment_0.intersection_t(&segment_1) {
|
let ctrl = match segment_0.intersection_t(segment_1) {
|
||||||
Some(t) => segment_0.sample(t),
|
Some(t) => segment_0.sample(t),
|
||||||
None => segment_0.to().lerp(segment_1.from(), 0.5),
|
None => segment_0.to().lerp(segment_1.from(), 0.5),
|
||||||
};
|
};
|
||||||
let baseline = LineSegment2F::new(segment_0.from(), segment_1.to());
|
let baseline = LineSegment2F::new(segment_0.from(), segment_1.to());
|
||||||
return Segment::quadratic(&baseline, ctrl);
|
return Segment::quadratic(baseline, ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(self.is_cubic());
|
debug_assert!(self.is_cubic());
|
||||||
|
@ -268,13 +267,13 @@ impl Offset for Segment {
|
||||||
let mut segment_1 = LineSegment2F::new(self.ctrl.to(), self.baseline.to());
|
let mut segment_1 = LineSegment2F::new(self.ctrl.to(), self.baseline.to());
|
||||||
segment_0 = segment_0.offset(distance);
|
segment_0 = segment_0.offset(distance);
|
||||||
segment_1 = segment_1.offset(distance);
|
segment_1 = segment_1.offset(distance);
|
||||||
let ctrl = match segment_0.intersection_t(&segment_1) {
|
let ctrl = match segment_0.intersection_t(segment_1) {
|
||||||
Some(t) => segment_0.sample(t),
|
Some(t) => segment_0.sample(t),
|
||||||
None => segment_0.to().lerp(segment_1.from(), 0.5),
|
None => segment_0.to().lerp(segment_1.from(), 0.5),
|
||||||
};
|
};
|
||||||
let baseline = LineSegment2F::new(segment_0.from(), segment_1.to());
|
let baseline = LineSegment2F::new(segment_0.from(), segment_1.to());
|
||||||
let ctrl = LineSegment2F::new(segment_0.from(), ctrl);
|
let ctrl = LineSegment2F::new(segment_0.from(), ctrl);
|
||||||
return Segment::cubic(&baseline, &ctrl);
|
return Segment::cubic(baseline, ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ctrl.to() == self.baseline.to() {
|
if self.ctrl.to() == self.baseline.to() {
|
||||||
|
@ -282,13 +281,13 @@ impl Offset for Segment {
|
||||||
let mut segment_1 = LineSegment2F::new(self.ctrl.from(), self.baseline.to());
|
let mut segment_1 = LineSegment2F::new(self.ctrl.from(), self.baseline.to());
|
||||||
segment_0 = segment_0.offset(distance);
|
segment_0 = segment_0.offset(distance);
|
||||||
segment_1 = segment_1.offset(distance);
|
segment_1 = segment_1.offset(distance);
|
||||||
let ctrl = match segment_0.intersection_t(&segment_1) {
|
let ctrl = match segment_0.intersection_t(segment_1) {
|
||||||
Some(t) => segment_0.sample(t),
|
Some(t) => segment_0.sample(t),
|
||||||
None => segment_0.to().lerp(segment_1.from(), 0.5),
|
None => segment_0.to().lerp(segment_1.from(), 0.5),
|
||||||
};
|
};
|
||||||
let baseline = LineSegment2F::new(segment_0.from(), segment_1.to());
|
let baseline = LineSegment2F::new(segment_0.from(), segment_1.to());
|
||||||
let ctrl = LineSegment2F::new(ctrl, segment_1.to());
|
let ctrl = LineSegment2F::new(ctrl, segment_1.to());
|
||||||
return Segment::cubic(&baseline, &ctrl);
|
return Segment::cubic(baseline, ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut segment_0 = LineSegment2F::new(self.baseline.from(), self.ctrl.from());
|
let mut segment_0 = LineSegment2F::new(self.baseline.from(), self.ctrl.from());
|
||||||
|
@ -298,8 +297,8 @@ impl Offset for Segment {
|
||||||
segment_1 = segment_1.offset(distance);
|
segment_1 = segment_1.offset(distance);
|
||||||
segment_2 = segment_2.offset(distance);
|
segment_2 = segment_2.offset(distance);
|
||||||
let (ctrl_0, ctrl_1) = match (
|
let (ctrl_0, ctrl_1) = match (
|
||||||
segment_0.intersection_t(&segment_1),
|
segment_0.intersection_t(segment_1),
|
||||||
segment_1.intersection_t(&segment_2),
|
segment_1.intersection_t(segment_2),
|
||||||
) {
|
) {
|
||||||
(Some(t0), Some(t1)) => (segment_0.sample(t0), segment_1.sample(t1)),
|
(Some(t0), Some(t1)) => (segment_0.sample(t0), segment_1.sample(t1)),
|
||||||
_ => (
|
_ => (
|
||||||
|
@ -309,7 +308,7 @@ impl Offset for Segment {
|
||||||
};
|
};
|
||||||
let baseline = LineSegment2F::new(segment_0.from(), segment_2.to());
|
let baseline = LineSegment2F::new(segment_0.from(), segment_2.to());
|
||||||
let ctrl = LineSegment2F::new(ctrl_0, ctrl_1);
|
let ctrl = LineSegment2F::new(ctrl_0, ctrl_1);
|
||||||
Segment::cubic(&baseline, &ctrl)
|
Segment::cubic(baseline, ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_is_within_tolerance(&self, other: &Segment, distance: f32) -> bool {
|
fn error_is_within_tolerance(&self, other: &Segment, distance: f32) -> bool {
|
||||||
|
@ -357,14 +356,14 @@ impl Contour {
|
||||||
distance: f32,
|
distance: f32,
|
||||||
join: LineJoin,
|
join: LineJoin,
|
||||||
join_point: Vector2F,
|
join_point: Vector2F,
|
||||||
next_tangent: &LineSegment2F) {
|
next_tangent: LineSegment2F) {
|
||||||
let (p0, p1) = (self.position_of_last(2), self.position_of_last(1));
|
let (p0, p1) = (self.position_of_last(2), self.position_of_last(1));
|
||||||
let prev_tangent = LineSegment2F::new(p0, p1);
|
let prev_tangent = LineSegment2F::new(p0, p1);
|
||||||
|
|
||||||
match join {
|
match join {
|
||||||
LineJoin::Bevel => {}
|
LineJoin::Bevel => {}
|
||||||
LineJoin::Miter(miter_limit) => {
|
LineJoin::Miter(miter_limit) => {
|
||||||
if let Some(prev_tangent_t) = prev_tangent.intersection_t(&next_tangent) {
|
if let Some(prev_tangent_t) = prev_tangent.intersection_t(next_tangent) {
|
||||||
let miter_endpoint = prev_tangent.sample(prev_tangent_t);
|
let miter_endpoint = prev_tangent.sample(prev_tangent_t);
|
||||||
let threshold = miter_limit * distance;
|
let threshold = miter_limit * distance;
|
||||||
if (miter_endpoint - join_point).square_length() <= threshold * threshold {
|
if (miter_endpoint - join_point).square_length() <= threshold * threshold {
|
||||||
|
@ -374,8 +373,7 @@ impl Contour {
|
||||||
}
|
}
|
||||||
LineJoin::Round => {
|
LineJoin::Round => {
|
||||||
let scale = Vector2F::splat(distance.abs());
|
let scale = Vector2F::splat(distance.abs());
|
||||||
let mut transform = Transform2DF::from_scale(scale);
|
let transform = Transform2F::from_scale(scale).translate(join_point);
|
||||||
transform = transform.post_mul(&Transform2DF::from_translation(join_point));
|
|
||||||
let chord_from = (prev_tangent.to() - join_point).normalize();
|
let chord_from = (prev_tangent.to() - join_point).normalize();
|
||||||
let chord_to = (next_tangent.to() - join_point).normalize();
|
let chord_to = (next_tangent.to() - join_point).normalize();
|
||||||
let chord = LineSegment2F::new(chord_from, chord_to);
|
let chord = LineSegment2F::new(chord_from, chord_to);
|
||||||
|
|
|
@ -11,19 +11,19 @@
|
||||||
//! Utilities for transforming paths.
|
//! Utilities for transforming paths.
|
||||||
|
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
|
|
||||||
/// Transforms a path with a SIMD 2D transform.
|
/// Transforms a path with a SIMD 2D transform.
|
||||||
pub struct Transform2DFPathIter<I>
|
pub struct Transform2FPathIter<I>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = Segment>,
|
I: Iterator<Item = Segment>,
|
||||||
{
|
{
|
||||||
iter: I,
|
iter: I,
|
||||||
transform: Transform2DF,
|
transform: Transform2F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Iterator for Transform2DFPathIter<I>
|
impl<I> Iterator for Transform2FPathIter<I>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = Segment>,
|
I: Iterator<Item = Segment>,
|
||||||
{
|
{
|
||||||
|
@ -34,20 +34,12 @@ where
|
||||||
// TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD?
|
// TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD?
|
||||||
let mut segment = self.iter.next()?;
|
let mut segment = self.iter.next()?;
|
||||||
if !segment.is_none() {
|
if !segment.is_none() {
|
||||||
segment
|
segment.baseline.set_from(self.transform * segment.baseline.from());
|
||||||
.baseline
|
segment.baseline.set_to(self.transform * segment.baseline.to());
|
||||||
.set_from(&self.transform.transform_point(segment.baseline.from()));
|
|
||||||
segment
|
|
||||||
.baseline
|
|
||||||
.set_to(&self.transform.transform_point(segment.baseline.to()));
|
|
||||||
if !segment.is_line() {
|
if !segment.is_line() {
|
||||||
segment
|
segment.ctrl.set_from(self.transform * segment.ctrl.from());
|
||||||
.ctrl
|
|
||||||
.set_from(&self.transform.transform_point(segment.ctrl.from()));
|
|
||||||
if !segment.is_quadratic() {
|
if !segment.is_quadratic() {
|
||||||
segment
|
segment.ctrl.set_to(self.transform * segment.ctrl.to());
|
||||||
.ctrl
|
|
||||||
.set_to(&self.transform.transform_point(segment.ctrl.to()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,13 +47,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Transform2DFPathIter<I>
|
impl<I> Transform2FPathIter<I>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = Segment>,
|
I: Iterator<Item = Segment>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(iter: I, transform: &Transform2DF) -> Transform2DFPathIter<I> {
|
pub fn new(iter: I, transform: &Transform2F) -> Transform2FPathIter<I> {
|
||||||
Transform2DFPathIter {
|
Transform2FPathIter {
|
||||||
iter,
|
iter,
|
||||||
transform: *transform,
|
transform: *transform,
|
||||||
}
|
}
|
||||||
|
@ -87,22 +79,12 @@ where
|
||||||
fn next(&mut self) -> Option<Segment> {
|
fn next(&mut self) -> Option<Segment> {
|
||||||
let mut segment = self.iter.next()?;
|
let mut segment = self.iter.next()?;
|
||||||
if !segment.is_none() {
|
if !segment.is_none() {
|
||||||
segment.baseline.set_from(
|
segment.baseline.set_from(self.perspective * segment.baseline.from());
|
||||||
&self
|
segment.baseline.set_to(self.perspective * segment.baseline.to());
|
||||||
.perspective
|
|
||||||
.transform_point_2d(&segment.baseline.from()),
|
|
||||||
);
|
|
||||||
segment
|
|
||||||
.baseline
|
|
||||||
.set_to(&self.perspective.transform_point_2d(&segment.baseline.to()));
|
|
||||||
if !segment.is_line() {
|
if !segment.is_line() {
|
||||||
segment
|
segment.ctrl.set_from(self.perspective * segment.ctrl.from());
|
||||||
.ctrl
|
|
||||||
.set_from(&self.perspective.transform_point_2d(&segment.ctrl.from()));
|
|
||||||
if !segment.is_quadratic() {
|
if !segment.is_quadratic() {
|
||||||
segment
|
segment.ctrl.set_to(self.perspective * segment.ctrl.to());
|
||||||
.ctrl
|
|
||||||
.set_to(&self.perspective.transform_point_2d(&segment.ctrl.to()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,9 @@ features = ["release_max_level_warn"]
|
||||||
[dependencies.pathfinder_content]
|
[dependencies.pathfinder_content]
|
||||||
path = "../../content"
|
path = "../../content"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_export]
|
||||||
|
path = "../../export"
|
||||||
|
|
||||||
[dependencies.pathfinder_geometry]
|
[dependencies.pathfinder_geometry]
|
||||||
path = "../../geometry"
|
path = "../../geometry"
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
// proper.
|
// proper.
|
||||||
|
|
||||||
use crate::window::{OcularTransform, View};
|
use crate::window::{OcularTransform, View};
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F};
|
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::transform3d::{Perspective, Transform3DF};
|
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
|
||||||
use std::f32::consts::FRAC_PI_4;
|
use std::f32::consts::FRAC_PI_4;
|
||||||
|
|
||||||
const NEAR_CLIP_PLANE: f32 = 0.01;
|
const NEAR_CLIP_PLANE: f32 = 0.01;
|
||||||
|
@ -27,7 +27,7 @@ const FAR_CLIP_PLANE: f32 = 10.0;
|
||||||
const DEFAULT_EYE_OFFSET: f32 = 0.025;
|
const DEFAULT_EYE_OFFSET: f32 = 0.025;
|
||||||
|
|
||||||
pub enum Camera {
|
pub enum Camera {
|
||||||
TwoD(Transform2DF),
|
TwoD(Transform2F),
|
||||||
ThreeD {
|
ThreeD {
|
||||||
// The ocular transform used for rendering of the scene to the scene framebuffer. If we are
|
// The ocular transform used for rendering of the scene to the scene framebuffer. If we are
|
||||||
// performing stereoscopic rendering, this is then reprojected according to the eye
|
// performing stereoscopic rendering, this is then reprojected according to the eye
|
||||||
|
@ -56,7 +56,7 @@ impl Camera {
|
||||||
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32
|
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32
|
||||||
* scale_factor_for_view_box(view_box);
|
* scale_factor_for_view_box(view_box);
|
||||||
let origin = viewport_size.to_f32().scale(0.5) - view_box.size().scale(scale * 0.5);
|
let origin = viewport_size.to_f32().scale(0.5) - view_box.size().scale(scale * 0.5);
|
||||||
Camera::TwoD(Transform2DF::from_scale(Vector2F::splat(scale)).post_translate(origin))
|
Camera::TwoD(Transform2F::from_uniform_scale(scale).translate(origin))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_3d(mode: Mode, view_box: RectF, viewport_size: Vector2I) -> Camera {
|
fn new_3d(mode: Mode, view_box: RectF, viewport_size: Vector2I) -> Camera {
|
||||||
|
@ -65,15 +65,15 @@ impl Camera {
|
||||||
let fov_y = FRAC_PI_4;
|
let fov_y = FRAC_PI_4;
|
||||||
let aspect = viewport_size.x() as f32 / viewport_size.y() as f32;
|
let aspect = viewport_size.x() as f32 / viewport_size.y() as f32;
|
||||||
let projection =
|
let projection =
|
||||||
Transform3DF::from_perspective(fov_y, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
|
Transform4F::from_perspective(fov_y, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
|
||||||
let perspective = Perspective::new(&projection, viewport_size);
|
let perspective = Perspective::new(&projection, viewport_size);
|
||||||
|
|
||||||
// Create a scene transform by moving the camera back from the center of the eyes so that
|
// Create a scene transform by moving the camera back from the center of the eyes so that
|
||||||
// its field of view encompasses the field of view of both eyes.
|
// its field of view encompasses the field of view of both eyes.
|
||||||
let z_offset = -DEFAULT_EYE_OFFSET * projection.c0.x();
|
let z_offset = Vector4F::new(0.0, 0.0, -DEFAULT_EYE_OFFSET * projection.c0.x(), 1.0);
|
||||||
let scene_transform = OcularTransform {
|
let scene_transform = OcularTransform {
|
||||||
perspective,
|
perspective,
|
||||||
modelview_to_eye: Transform3DF::from_translation(0.0, 0.0, z_offset),
|
modelview_to_eye: Transform4F::from_translation(z_offset),
|
||||||
};
|
};
|
||||||
|
|
||||||
// For now, initialize the eye transforms as copies of the scene transform.
|
// For now, initialize the eye transforms as copies of the scene transform.
|
||||||
|
@ -85,9 +85,10 @@ impl Camera {
|
||||||
} else {
|
} else {
|
||||||
-eye_offset
|
-eye_offset
|
||||||
};
|
};
|
||||||
|
let this_eye_offset = Vector4F::new(this_eye_offset, 0.0, 0.0, 1.0);
|
||||||
OcularTransform {
|
OcularTransform {
|
||||||
perspective,
|
perspective,
|
||||||
modelview_to_eye: Transform3DF::from_translation(this_eye_offset, 0.0, 0.0),
|
modelview_to_eye: Transform4F::from_translation(this_eye_offset),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -145,25 +146,17 @@ impl CameraTransform3D {
|
||||||
pub fn offset(&mut self, vector: Vector4F) -> bool {
|
pub fn offset(&mut self, vector: Vector4F) -> bool {
|
||||||
let update = !vector.is_zero();
|
let update = !vector.is_zero();
|
||||||
if update {
|
if update {
|
||||||
let rotation = Transform3DF::from_rotation(-self.yaw, -self.pitch, 0.0);
|
let rotation = Transform4F::from_rotation(-self.yaw, -self.pitch, 0.0);
|
||||||
self.position = self.position + rotation.transform_point(vector);
|
self.position = self.position + rotation * vector;
|
||||||
}
|
}
|
||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_transform(&self) -> Transform3DF {
|
pub fn to_transform(&self) -> Transform4F {
|
||||||
let mut transform = Transform3DF::from_rotation(self.yaw, self.pitch, 0.0);
|
let flip = Vector4F::new(1.0, -1.0, 1.0, 1.0);
|
||||||
transform = transform.post_mul(&Transform3DF::from_uniform_scale(2.0 * self.scale));
|
Transform4F::from_scale(flip).translate(-self.position)
|
||||||
transform = transform.post_mul(&Transform3DF::from_translation(
|
.uniform_scale(2.0 * self.scale)
|
||||||
-self.position.x(),
|
.rotate(self.yaw, self.pitch, 0.0)
|
||||||
-self.position.y(),
|
|
||||||
-self.position.z(),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Flip Y.
|
|
||||||
transform = transform.post_mul(&Transform3DF::from_scale(1.0, -1.0, 1.0));
|
|
||||||
|
|
||||||
transform
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,12 @@ use crate::device::{GroundProgram, GroundVertexArray};
|
||||||
use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction};
|
use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction};
|
||||||
use crate::window::{Event, Keycode, SVGPath, Window, WindowSize};
|
use crate::window::{Event, Keycode, SVGPath, Window, WindowSize};
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
|
||||||
use pathfinder_geometry::rect::RectF;
|
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
|
||||||
use pathfinder_geometry::transform3d::Transform3DF;
|
|
||||||
use pathfinder_content::color::ColorU;
|
use pathfinder_content::color::ColorU;
|
||||||
|
use pathfinder_export::{Export, FileFormat};
|
||||||
|
use pathfinder_geometry::rect::RectF;
|
||||||
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
|
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F};
|
||||||
use pathfinder_gpu::resources::ResourceLoader;
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::Device;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy};
|
use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy};
|
||||||
|
@ -38,7 +39,7 @@ use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_svg::BuiltSVG;
|
use pathfinder_svg::BuiltSVG;
|
||||||
use pathfinder_ui::{MousePosition, UIEvent};
|
use pathfinder_ui::{MousePosition, UIEvent};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{BufWriter, Read};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -255,10 +256,9 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
if modelview_transform.offset(*velocity) {
|
if modelview_transform.offset(*velocity) {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
let perspective = scene_transform
|
let perspective = scene_transform.perspective *
|
||||||
.perspective
|
scene_transform.modelview_to_eye *
|
||||||
.post_mul(&scene_transform.modelview_to_eye)
|
modelview_transform.to_transform();
|
||||||
.post_mul(&modelview_transform.to_transform());
|
|
||||||
Some(RenderTransform::Perspective(perspective))
|
Some(RenderTransform::Perspective(perspective))
|
||||||
}
|
}
|
||||||
Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)),
|
Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)),
|
||||||
|
@ -327,10 +327,10 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
let backing_scale_factor = self.window_size.backing_scale_factor;
|
let backing_scale_factor = self.window_size.backing_scale_factor;
|
||||||
let position = position.to_f32().scale(backing_scale_factor);
|
let position = position.to_f32().scale(backing_scale_factor);
|
||||||
*transform = transform.post_translate(-position);
|
|
||||||
let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
|
let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
|
||||||
*transform = transform.post_scale(Vector2F::splat(scale_delta));
|
*transform = transform.translate(-position)
|
||||||
*transform = transform.post_translate(position);
|
.uniform_scale(scale_delta)
|
||||||
|
.translate(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Look { pitch, yaw } => {
|
Event::Look { pitch, yaw } => {
|
||||||
|
@ -355,13 +355,21 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
*scene_transform = eye_transforms[0];
|
*scene_transform = eye_transforms[0];
|
||||||
for (index, eye_transform) in eye_transforms.iter().enumerate().skip(1) {
|
for (index, eye_transform) in eye_transforms.iter().enumerate().skip(1) {
|
||||||
let weight = 1.0 / (index + 1) as f32;
|
let weight = 1.0 / (index + 1) as f32;
|
||||||
scene_transform.perspective.transform = scene_transform.perspective.transform.lerp(weight, &eye_transform.perspective.transform);
|
scene_transform.perspective.transform =
|
||||||
scene_transform.modelview_to_eye = scene_transform.modelview_to_eye.lerp(weight, &eye_transform.modelview_to_eye);
|
scene_transform.perspective
|
||||||
|
.transform
|
||||||
|
.lerp(weight, &eye_transform.perspective.transform);
|
||||||
|
scene_transform.modelview_to_eye =
|
||||||
|
scene_transform.modelview_to_eye
|
||||||
|
.lerp(weight, &eye_transform.modelview_to_eye);
|
||||||
}
|
}
|
||||||
// TODO: calculate the eye offset from the eye transforms?
|
// TODO: calculate the eye offset from the eye transforms?
|
||||||
let z_offset = -DEFAULT_EYE_OFFSET * scene_transform.perspective.transform.c0.x();
|
let z_offset = -DEFAULT_EYE_OFFSET *
|
||||||
scene_transform.modelview_to_eye = scene_transform.modelview_to_eye
|
scene_transform.perspective.transform.c0.x();
|
||||||
.pre_mul(&Transform3DF::from_translation(0.0, 0.0, z_offset));
|
let z_offset = Vector4F::new(0.0, 0.0, z_offset, 1.0);
|
||||||
|
scene_transform.modelview_to_eye =
|
||||||
|
Transform4F::from_translation(z_offset) *
|
||||||
|
scene_transform.modelview_to_eye;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
|
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
|
||||||
|
@ -550,7 +558,8 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
}
|
}
|
||||||
Some(ScreenshotInfo { kind: ScreenshotType::SVG, path }) => {
|
Some(ScreenshotInfo { kind: ScreenshotType::SVG, path }) => {
|
||||||
// FIXME(pcwalton): This won't work on Android.
|
// FIXME(pcwalton): This won't work on Android.
|
||||||
File::create(path).unwrap().write_all(&mut self.scene_proxy.as_svg()).unwrap();
|
let mut writer = BufWriter::new(File::create(path).unwrap());
|
||||||
|
self.scene_proxy.copy_scene().export(&mut writer, FileFormat::SVG).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,7 +587,7 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
}
|
}
|
||||||
UIEvent::MouseDragged(position) => {
|
UIEvent::MouseDragged(position) => {
|
||||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
*transform = transform.post_translate(position.relative.to_f32());
|
*transform = transform.translate(position.relative.to_f32());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -598,10 +607,7 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
let scale = Vector2F::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D);
|
let scale = Vector2F::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D);
|
||||||
let center = center_of_window(&self.window_size);
|
let center = center_of_window(&self.window_size);
|
||||||
*transform = transform
|
*transform = transform.translate(-center).scale(scale).translate(center);
|
||||||
.post_translate(-center)
|
|
||||||
.post_scale(scale)
|
|
||||||
.post_translate(center);
|
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -609,16 +615,13 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
let scale = Vector2F::splat(1.0 - CAMERA_ZOOM_AMOUNT_2D);
|
let scale = Vector2F::splat(1.0 - CAMERA_ZOOM_AMOUNT_2D);
|
||||||
let center = center_of_window(&self.window_size);
|
let center = center_of_window(&self.window_size);
|
||||||
*transform = transform
|
*transform = transform.translate(-center).scale(scale).translate(center);
|
||||||
.post_translate(-center)
|
|
||||||
.post_scale(scale)
|
|
||||||
.post_translate(center);
|
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UIAction::ZoomActualSize => {
|
UIAction::ZoomActualSize => {
|
||||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
*transform = Transform2DF::default();
|
*transform = Transform2F::default();
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -626,10 +629,9 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
let old_rotation = transform.rotation();
|
let old_rotation = transform.rotation();
|
||||||
let center = center_of_window(&self.window_size);
|
let center = center_of_window(&self.window_size);
|
||||||
*transform = transform
|
*transform = transform.translate(-center)
|
||||||
.post_translate(-center)
|
.rotate(*theta - old_rotation)
|
||||||
.post_rotate(*theta - old_rotation)
|
.translate(center);
|
||||||
.post_translate(center);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ use pathfinder_content::color::{ColorF, ColorU};
|
||||||
use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions};
|
use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions};
|
||||||
use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData};
|
use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::Transform3DF;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
||||||
use pathfinder_renderer::gpu::renderer::RenderMode;
|
use pathfinder_renderer::gpu::renderer::RenderMode;
|
||||||
use pathfinder_renderer::gpu_data::RenderCommand;
|
use pathfinder_renderer::gpu_data::RenderCommand;
|
||||||
|
@ -163,24 +163,20 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
||||||
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
|
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
|
||||||
|
|
||||||
let quad_scale_transform = Transform3DF::from_scale(
|
let mut quad_scale = self.scene_metadata.view_box.size().to_3d();
|
||||||
self.scene_metadata.view_box.size().x(),
|
quad_scale.set_z(1.0);
|
||||||
self.scene_metadata.view_box.size().y(),
|
let quad_scale_transform = Transform4F::from_scale(quad_scale);
|
||||||
1.0,
|
|
||||||
);
|
|
||||||
|
|
||||||
let scene_transform_matrix = scene_transform
|
let scene_transform_matrix = scene_transform.perspective *
|
||||||
.perspective
|
scene_transform.modelview_to_eye *
|
||||||
.post_mul(&scene_transform.modelview_to_eye)
|
modelview_transform.to_transform() *
|
||||||
.post_mul(&modelview_transform.to_transform())
|
quad_scale_transform;
|
||||||
.post_mul(&quad_scale_transform);
|
|
||||||
|
|
||||||
let eye_transform = &eye_transforms[render_scene_index as usize];
|
let eye_transform = &eye_transforms[render_scene_index as usize];
|
||||||
let eye_transform_matrix = eye_transform
|
let eye_transform_matrix = eye_transform.perspective *
|
||||||
.perspective
|
eye_transform.modelview_to_eye *
|
||||||
.post_mul(&eye_transform.modelview_to_eye)
|
modelview_transform.to_transform() *
|
||||||
.post_mul(&modelview_transform.to_transform())
|
quad_scale_transform;
|
||||||
.post_mul(&quad_scale_transform);
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"eye transform({}).modelview_to_eye={:?}",
|
"eye transform({}).modelview_to_eye={:?}",
|
||||||
|
@ -214,17 +210,14 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
|
|
||||||
let ground_scale = self.scene_metadata.view_box.max_x() * 2.0;
|
let ground_scale = self.scene_metadata.view_box.max_x() * 2.0;
|
||||||
|
|
||||||
let mut base_transform = perspective.transform;
|
let mut offset = self.scene_metadata.view_box.lower_right().to_3d();
|
||||||
base_transform = base_transform.post_mul(&Transform3DF::from_translation(
|
offset.set_z(ground_scale);
|
||||||
-0.5 * self.scene_metadata.view_box.max_x(),
|
offset = offset * Vector4F::new(-0.5, 1.0, -0.5, 1.0);
|
||||||
self.scene_metadata.view_box.max_y(),
|
let base_transform = perspective.transform * Transform4F::from_translation(offset);
|
||||||
-0.5 * ground_scale,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Fill ground.
|
// Fill ground.
|
||||||
let mut transform = base_transform;
|
let transform = base_transform *
|
||||||
transform =
|
Transform4F::from_scale(Vector4F::new(ground_scale, 1.0, ground_scale, 1.0));
|
||||||
transform.post_mul(&Transform3DF::from_scale(ground_scale, 1.0, ground_scale));
|
|
||||||
|
|
||||||
// Don't clear the first scene after drawing it.
|
// Don't clear the first scene after drawing it.
|
||||||
let clear_color = if render_scene_index == 0 {
|
let clear_color = if render_scene_index == 0 {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::{Perspective, Transform3DF};
|
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
|
||||||
use pathfinder_gpu::resources::ResourceLoader;
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
use rayon::ThreadPoolBuilder;
|
use rayon::ThreadPoolBuilder;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -109,7 +109,7 @@ pub struct OcularTransform {
|
||||||
pub perspective: Perspective,
|
pub perspective: Perspective,
|
||||||
|
|
||||||
// The view transform which converts from world coordinates to camera coordinates
|
// The view transform which converts from world coordinates to camera coordinates
|
||||||
pub modelview_to_eye: Transform3DF,
|
pub modelview_to_eye: Transform4F,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::io;
|
||||||
use pathfinder_geometry::point::Point2DI32;
|
use pathfinder_geometry::point::Point2DI32;
|
||||||
use pathfinder_geometry::rect::RectI32;
|
use pathfinder_geometry::rect::RectI32;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::transform3d::Transform3DF32;
|
use pathfinder_geometry::transform3d::Transform4F32;
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
use pathfinder_gpu::resources::ResourceLoader;
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ pub trait DisplayCamera {
|
||||||
type Error: DisplayError;
|
type Error: DisplayError;
|
||||||
|
|
||||||
fn bounds(&self) -> RectI32;
|
fn bounds(&self) -> RectI32;
|
||||||
fn view(&self) -> Transform3DF32;
|
fn view(&self) -> Transform4F32;
|
||||||
fn perspective(&self) -> Perspective;
|
fn perspective(&self) -> Perspective;
|
||||||
|
|
||||||
fn make_current(&mut self) -> Result<(), Self::Error>;
|
fn make_current(&mut self) -> Result<(), Self::Error>;
|
||||||
|
|
|
@ -27,7 +27,7 @@ use crate::display::DisplayError;
|
||||||
|
|
||||||
use pathfinder_geometry::point::Point2DI32;
|
use pathfinder_geometry::point::Point2DI32;
|
||||||
use pathfinder_geometry::rect::RectI32;
|
use pathfinder_geometry::rect::RectI32;
|
||||||
use pathfinder_geometry::transform3d::Transform3DF32;
|
use pathfinder_geometry::transform3d::Transform4F32;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
use pathfinder_gpu::resources::FilesystemResourceLoader;
|
use pathfinder_gpu::resources::FilesystemResourceLoader;
|
||||||
|
@ -149,15 +149,15 @@ impl DisplayCamera for GlWindowCamera {
|
||||||
// TODO: add eye offsets
|
// TODO: add eye offsets
|
||||||
let bounds = self.bounds();
|
let bounds = self.bounds();
|
||||||
let aspect = bounds.size().x() as f32 / bounds.size().y() as f32;
|
let aspect = bounds.size().x() as f32 / bounds.size().y() as f32;
|
||||||
let transform = Transform3DF32::from_perspective(FRAC_PI_4, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
|
let transform = Transform4F32::from_perspective(FRAC_PI_4, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
|
||||||
Perspective::new(&transform, bounds.size())
|
Perspective::new(&transform, bounds.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Transform3DF32 {
|
fn view(&self) -> Transform4F32 {
|
||||||
let duration = Instant::now() - self.start;
|
let duration = Instant::now() - self.start;
|
||||||
let rotation = duration.as_millis() as f32 / 1000.0;
|
let rotation = duration.as_millis() as f32 / 1000.0;
|
||||||
Transform3DF32::from_rotation(rotation, 0.0, 0.0)
|
Transform4F32::from_rotation(rotation, 0.0, 0.0)
|
||||||
.pre_mul(&Transform3DF32::from_translation(0.0, 0.0, -CAMERA_DISTANCE))
|
.pre_mul(&Transform4F32::from_translation(0.0, 0.0, -CAMERA_DISTANCE))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ use pathfinder_geometry::point::Point2DI32;
|
||||||
use pathfinder_geometry::point::Point2DF32;
|
use pathfinder_geometry::point::Point2DF32;
|
||||||
use pathfinder_geometry::point::Point3DF32;
|
use pathfinder_geometry::point::Point3DF32;
|
||||||
use pathfinder_geometry::rect::RectI32;
|
use pathfinder_geometry::rect::RectI32;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF32;
|
use pathfinder_geometry::transform2d::Transform2F32;
|
||||||
use pathfinder_geometry::transform3d::Transform3DF32;
|
use pathfinder_geometry::transform3d::Transform4F32;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::Device;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
|
@ -41,7 +41,7 @@ pub struct ImmersiveDemo<D> {
|
||||||
renderer: Renderer<GLDevice>,
|
renderer: Renderer<GLDevice>,
|
||||||
scene_thread_proxy: SceneThreadProxy,
|
scene_thread_proxy: SceneThreadProxy,
|
||||||
svg_size: Point2DF32,
|
svg_size: Point2DF32,
|
||||||
svg_to_world: Option<Transform3DF32>,
|
svg_to_world: Option<Transform4F32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg";
|
static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg";
|
||||||
|
@ -87,13 +87,13 @@ impl<D: Display> ImmersiveDemo<D> {
|
||||||
|
|
||||||
let svg_size = self.svg_size;
|
let svg_size = self.svg_size;
|
||||||
let svg_to_world = self.svg_to_world.get_or_insert_with(|| {
|
let svg_to_world = self.svg_to_world.get_or_insert_with(|| {
|
||||||
let view: Transform3DF32 = cameras[0].view();
|
let view: Transform4F32 = cameras[0].view();
|
||||||
let svg_to_world_scale = f32::max(MAX_SVG_WIDTH / svg_size.x(), MAX_SVG_HEIGHT / svg_size.y());
|
let svg_to_world_scale = f32::max(MAX_SVG_WIDTH / svg_size.x(), MAX_SVG_HEIGHT / svg_size.y());
|
||||||
let svg_width = svg_size.x() * svg_to_world_scale;
|
let svg_width = svg_size.x() * svg_to_world_scale;
|
||||||
let svg_height = svg_size.y() * svg_to_world_scale;
|
let svg_height = svg_size.y() * svg_to_world_scale;
|
||||||
Transform3DF32::from_uniform_scale(svg_to_world_scale)
|
Transform4F32::from_uniform_scale(svg_to_world_scale)
|
||||||
.pre_mul(&Transform3DF32::from_translation(-svg_width / 2.0, -svg_height / 2.0, -DEFAULT_SVG_DISTANCE))
|
.pre_mul(&Transform4F32::from_translation(-svg_width / 2.0, -svg_height / 2.0, -DEFAULT_SVG_DISTANCE))
|
||||||
.pre_mul(&Transform3DF32::from_scale(1.0, -1.0, 1.0))
|
.pre_mul(&Transform4F32::from_scale(1.0, -1.0, 1.0))
|
||||||
.pre_mul(&view.inverse())
|
.pre_mul(&view.inverse())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ use pathfinder_demo::window::SVGPath;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_content::color::ColorF;
|
use pathfinder_content::color::ColorF;
|
||||||
use pathfinder_gl::GLDevice;
|
use pathfinder_gl::GLDevice;
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
|
@ -216,9 +216,9 @@ pub unsafe extern "C" fn magicleap_pathfinder_render(pf: *mut c_void, options: *
|
||||||
|
|
||||||
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 /
|
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 /
|
||||||
f32::max(svg.scene.bounds().size().x(), svg.scene.bounds().size().y());
|
f32::max(svg.scene.bounds().size().x(), svg.scene.bounds().size().y());
|
||||||
let transform = Transform2DF::from_translation(svg.scene.bounds().size().scale(-0.5))
|
let transform = Transform2F::from_translation(svg.scene.bounds().size().scale(-0.5))
|
||||||
.post_mul(&Transform2DF::from_scale(Vector2F::splat(scale)))
|
.post_mul(&Transform2F::from_scale(Vector2F::splat(scale)))
|
||||||
.post_mul(&Transform2DF::from_translation(viewport_size.to_f32().scale(0.5)));
|
.post_mul(&Transform2F::from_translation(viewport_size.to_f32().scale(0.5)));
|
||||||
|
|
||||||
let render_options = RenderOptions {
|
let render_options = RenderOptions {
|
||||||
transform: RenderTransform::Transform2D(transform),
|
transform: RenderTransform::Transform2D(transform),
|
||||||
|
|
|
@ -53,7 +53,7 @@ use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::transform3d::Transform3DF;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::util;
|
use pathfinder_geometry::util;
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
use pathfinder_gpu::resources::FilesystemResourceLoader;
|
use pathfinder_gpu::resources::FilesystemResourceLoader;
|
||||||
|
@ -77,7 +77,7 @@ pub struct MagicLeapWindow {
|
||||||
graphics_client: MLHandle,
|
graphics_client: MLHandle,
|
||||||
size: Vector2I,
|
size: Vector2I,
|
||||||
virtual_camera_array: MLGraphicsVirtualCameraInfoArray,
|
virtual_camera_array: MLGraphicsVirtualCameraInfoArray,
|
||||||
initial_camera_transform: Option<Transform3DF>,
|
initial_camera_transform: Option<Transform4F>,
|
||||||
frame_handle: MLHandle,
|
frame_handle: MLHandle,
|
||||||
resource_loader: FilesystemResourceLoader,
|
resource_loader: FilesystemResourceLoader,
|
||||||
pose_event: Option<Vec<OcularTransform>>,
|
pose_event: Option<Vec<OcularTransform>>,
|
||||||
|
@ -234,21 +234,21 @@ impl MagicLeapWindow {
|
||||||
}
|
}
|
||||||
let virtual_camera_array = &self.virtual_camera_array;
|
let virtual_camera_array = &self.virtual_camera_array;
|
||||||
let initial_camera = self.initial_camera_transform.get_or_insert_with(|| {
|
let initial_camera = self.initial_camera_transform.get_or_insert_with(|| {
|
||||||
let initial_offset = Transform3DF::from_translation(0.0, 0.0, 1.0);
|
let initial_offset = Transform4F::from_translation(0.0, 0.0, 1.0);
|
||||||
let mut camera = virtual_camera_array.virtual_cameras[0].transform;
|
let mut camera = virtual_camera_array.virtual_cameras[0].transform;
|
||||||
for i in 1..virtual_camera_array.num_virtual_cameras {
|
for i in 1..virtual_camera_array.num_virtual_cameras {
|
||||||
let next = virtual_camera_array.virtual_cameras[i as usize].transform;
|
let next = virtual_camera_array.virtual_cameras[i as usize].transform;
|
||||||
camera = camera.lerp(next, 1.0 / (i as f32 + 1.0));
|
camera = camera.lerp(next, 1.0 / (i as f32 + 1.0));
|
||||||
}
|
}
|
||||||
Transform3DF::from(camera).post_mul(&initial_offset)
|
Transform4F::from(camera).post_mul(&initial_offset)
|
||||||
});
|
});
|
||||||
let camera_transforms = (0..virtual_camera_array.num_virtual_cameras)
|
let camera_transforms = (0..virtual_camera_array.num_virtual_cameras)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let camera = &virtual_camera_array.virtual_cameras[i as usize];
|
let camera = &virtual_camera_array.virtual_cameras[i as usize];
|
||||||
let projection = Transform3DF::from(camera.projection);
|
let projection = Transform4F::from(camera.projection);
|
||||||
let size = RectI::from(virtual_camera_array.viewport).size();
|
let size = RectI::from(virtual_camera_array.viewport).size();
|
||||||
let perspective = Perspective::new(&projection, size);
|
let perspective = Perspective::new(&projection, size);
|
||||||
let modelview_to_eye = Transform3DF::from(camera.transform).inverse().post_mul(initial_camera);
|
let modelview_to_eye = Transform4F::from(camera.transform).inverse().post_mul(initial_camera);
|
||||||
OcularTransform { perspective, modelview_to_eye }
|
OcularTransform { perspective, modelview_to_eye }
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -355,16 +355,16 @@ impl MLTransform {
|
||||||
|
|
||||||
// Impl pathfinder traits for c-api types
|
// Impl pathfinder traits for c-api types
|
||||||
|
|
||||||
impl From<MLTransform> for Transform3DF {
|
impl From<MLTransform> for Transform4F {
|
||||||
fn from(mat: MLTransform) -> Self {
|
fn from(mat: MLTransform) -> Self {
|
||||||
Transform3DF::from(mat.rotation)
|
Transform4F::from(mat.rotation)
|
||||||
.pre_mul(&Transform3DF::from(mat.position))
|
.pre_mul(&Transform4F::from(mat.position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MLVec3f> for Transform3DF {
|
impl From<MLVec3f> for Transform4F {
|
||||||
fn from(v: MLVec3f) -> Self {
|
fn from(v: MLVec3f) -> Self {
|
||||||
Transform3DF::from_translation(v.x, v.y, v.z)
|
Transform4F::from_translation(v.x, v.y, v.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,16 +380,16 @@ impl From<MLRectf> for RectI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MLQuaternionf> for Transform3DF {
|
impl From<MLQuaternionf> for Transform4F {
|
||||||
fn from(q: MLQuaternionf) -> Self {
|
fn from(q: MLQuaternionf) -> Self {
|
||||||
Transform3DF::from_rotation_quaternion(F32x4::new(q.x, q.y, q.z, q.w))
|
Transform4F::from_rotation_quaternion(F32x4::new(q.x, q.y, q.z, q.w))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MLMat4f> for Transform3DF {
|
impl From<MLMat4f> for Transform4F {
|
||||||
fn from(mat: MLMat4f) -> Self {
|
fn from(mat: MLMat4f) -> Self {
|
||||||
let a = mat.matrix_colmajor;
|
let a = mat.matrix_colmajor;
|
||||||
Transform3DF::row_major(a[0], a[4], a[8], a[12],
|
Transform4F::row_major(a[0], a[4], a[8], a[12],
|
||||||
a[1], a[5], a[9], a[13],
|
a[1], a[5], a[9], a[13],
|
||||||
a[2], a[6], a[10], a[14],
|
a[2], a[6], a[10], a[14],
|
||||||
a[3], a[7], a[11], a[15])
|
a[3], a[7], a[11], a[15])
|
||||||
|
|
|
@ -87,7 +87,7 @@ int main(int argc, const char **argv) {
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
PFSceneRef scene = PFCanvasCreateScene(canvas);
|
PFSceneRef scene = PFCanvasCreateScene(canvas);
|
||||||
PFSceneProxyRef scene_proxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene);
|
PFSceneProxyRef scene_proxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene);
|
||||||
PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFBuildOptions){0});
|
PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, PFBuildOptionsCreate());
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
|
|
||||||
// Wait for a keypress.
|
// Wait for a keypress.
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
|
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
|
||||||
use pathfinder_geometry::rect::RectF;
|
|
||||||
use pathfinder_content::color::ColorF;
|
use pathfinder_content::color::ColorF;
|
||||||
|
use pathfinder_geometry::rect::RectF;
|
||||||
|
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_gpu::resources::FilesystemResourceLoader;
|
use pathfinder_gpu::resources::FilesystemResourceLoader;
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
|
|
|
@ -0,0 +1,354 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 50;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
6A9A35B322C1E14700B86652 /* libpathfinder_c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A9A35B222C1E14700B86652 /* libpathfinder_c.a */; };
|
||||||
|
6AFD6FFA22BD780D00AC1ED3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AFD6FF922BD780D00AC1ED3 /* AppDelegate.m */; };
|
||||||
|
6AFD6FFC22BD781000AC1ED3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6AFD6FFB22BD781000AC1ED3 /* Assets.xcassets */; };
|
||||||
|
6AFD6FFF22BD781000AC1ED3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6AFD6FFD22BD781000AC1ED3 /* MainMenu.xib */; };
|
||||||
|
6AFD700222BD781000AC1ED3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AFD700122BD781000AC1ED3 /* main.m */; };
|
||||||
|
6AFD700B22BD7B7A00AC1ED3 /* PathfinderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AFD700A22BD7B7A00AC1ED3 /* PathfinderView.m */; };
|
||||||
|
6AFD700F22BD930500AC1ED3 /* libharfbuzz.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6AFD700E22BD930500AC1ED3 /* libharfbuzz.a */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
6A9A35B222C1E14700B86652 /* libpathfinder_c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpathfinder_c.a; path = ../../../target/release/libpathfinder_c.a; sourceTree = "<group>"; };
|
||||||
|
6AFD6FF522BD780D00AC1ED3 /* Pathfinder Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Pathfinder Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
6AFD6FF822BD780D00AC1ED3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||||
|
6AFD6FF922BD780D00AC1ED3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||||
|
6AFD6FFB22BD781000AC1ED3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
6AFD6FFE22BD781000AC1ED3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
|
6AFD700022BD781000AC1ED3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
6AFD700122BD781000AC1ED3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
6AFD700322BD781000AC1ED3 /* Pathfinder_Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Pathfinder_Example.entitlements; sourceTree = "<group>"; };
|
||||||
|
6AFD700922BD7B7A00AC1ED3 /* PathfinderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PathfinderView.h; sourceTree = "<group>"; };
|
||||||
|
6AFD700A22BD7B7A00AC1ED3 /* PathfinderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PathfinderView.m; sourceTree = "<group>"; };
|
||||||
|
6AFD700E22BD930500AC1ED3 /* libharfbuzz.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libharfbuzz.a; path = ../../../../../../../usr/local/lib/libharfbuzz.a; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
6AFD6FF222BD780D00AC1ED3 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
6A9A35B322C1E14700B86652 /* libpathfinder_c.a in Frameworks */,
|
||||||
|
6AFD700F22BD930500AC1ED3 /* libharfbuzz.a in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
6AFD6FEC22BD780D00AC1ED3 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6AFD6FF722BD780D00AC1ED3 /* Pathfinder Example */,
|
||||||
|
6AFD6FF622BD780D00AC1ED3 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
6AFD6FF622BD780D00AC1ED3 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6AFD6FF522BD780D00AC1ED3 /* Pathfinder Example.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
6AFD6FF722BD780D00AC1ED3 /* Pathfinder Example */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6AFD6FF822BD780D00AC1ED3 /* AppDelegate.h */,
|
||||||
|
6AFD6FF922BD780D00AC1ED3 /* AppDelegate.m */,
|
||||||
|
6AFD6FFB22BD781000AC1ED3 /* Assets.xcassets */,
|
||||||
|
6AFD6FFD22BD781000AC1ED3 /* MainMenu.xib */,
|
||||||
|
6AFD700022BD781000AC1ED3 /* Info.plist */,
|
||||||
|
6AFD700922BD7B7A00AC1ED3 /* PathfinderView.h */,
|
||||||
|
6AFD700A22BD7B7A00AC1ED3 /* PathfinderView.m */,
|
||||||
|
6AFD700122BD781000AC1ED3 /* main.m */,
|
||||||
|
6AFD700322BD781000AC1ED3 /* Pathfinder_Example.entitlements */,
|
||||||
|
6A9A35B222C1E14700B86652 /* libpathfinder_c.a */,
|
||||||
|
6AFD700E22BD930500AC1ED3 /* libharfbuzz.a */,
|
||||||
|
);
|
||||||
|
path = "Pathfinder Example";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
6AFD6FF422BD780D00AC1ED3 /* Pathfinder Example */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 6AFD700622BD781000AC1ED3 /* Build configuration list for PBXNativeTarget "Pathfinder Example" */;
|
||||||
|
buildPhases = (
|
||||||
|
6AFD6FF122BD780D00AC1ED3 /* Sources */,
|
||||||
|
6AFD6FF222BD780D00AC1ED3 /* Frameworks */,
|
||||||
|
6AFD6FF322BD780D00AC1ED3 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = "Pathfinder Example";
|
||||||
|
productName = "Pathfinder Example";
|
||||||
|
productReference = 6AFD6FF522BD780D00AC1ED3 /* Pathfinder Example.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
6AFD6FED22BD780D00AC1ED3 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 1020;
|
||||||
|
ORGANIZATIONNAME = "The Pathfinder Project Deelopers";
|
||||||
|
TargetAttributes = {
|
||||||
|
6AFD6FF422BD780D00AC1ED3 = {
|
||||||
|
CreatedOnToolsVersion = 10.2.1;
|
||||||
|
SystemCapabilities = {
|
||||||
|
com.apple.Sandbox = {
|
||||||
|
enabled = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 6AFD6FF022BD780D00AC1ED3 /* Build configuration list for PBXProject "Pathfinder Example" */;
|
||||||
|
compatibilityVersion = "Xcode 9.3";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 6AFD6FEC22BD780D00AC1ED3;
|
||||||
|
productRefGroup = 6AFD6FF622BD780D00AC1ED3 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
6AFD6FF422BD780D00AC1ED3 /* Pathfinder Example */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
6AFD6FF322BD780D00AC1ED3 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
6AFD6FFC22BD781000AC1ED3 /* Assets.xcassets in Resources */,
|
||||||
|
6AFD6FFF22BD781000AC1ED3 /* MainMenu.xib in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
6AFD6FF122BD780D00AC1ED3 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
6AFD700222BD781000AC1ED3 /* main.m in Sources */,
|
||||||
|
6AFD700B22BD7B7A00AC1ED3 /* PathfinderView.m in Sources */,
|
||||||
|
6AFD6FFA22BD780D00AC1ED3 /* AppDelegate.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
6AFD6FFD22BD781000AC1ED3 /* MainMenu.xib */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
6AFD6FFE22BD781000AC1ED3 /* Base */,
|
||||||
|
);
|
||||||
|
name = MainMenu.xib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
6AFD700422BD781000AC1ED3 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
6AFD700522BD781000AC1ED3 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
6AFD700722BD781000AC1ED3 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = "";
|
||||||
|
HEADER_SEARCH_PATHS = ../../c/build/include;
|
||||||
|
INFOPLIST_FILE = "Pathfinder Example/Info.plist";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/../Frameworks",
|
||||||
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
../../target/release,
|
||||||
|
/usr/local/lib,
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "graphics.pathfinder.Pathfinder-Example";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
6AFD700822BD781000AC1ED3 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = "";
|
||||||
|
HEADER_SEARCH_PATHS = ../../c/build/include;
|
||||||
|
INFOPLIST_FILE = "Pathfinder Example/Info.plist";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/../Frameworks",
|
||||||
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
../../target/release,
|
||||||
|
/usr/local/lib,
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "graphics.pathfinder.Pathfinder-Example";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
6AFD6FF022BD780D00AC1ED3 /* Build configuration list for PBXProject "Pathfinder Example" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
6AFD700422BD781000AC1ED3 /* Debug */,
|
||||||
|
6AFD700522BD781000AC1ED3 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
6AFD700622BD781000AC1ED3 /* Build configuration list for PBXNativeTarget "Pathfinder Example" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
6AFD700722BD781000AC1ED3 /* Debug */,
|
||||||
|
6AFD700822BD781000AC1ED3 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 6AFD6FED22BD780D00AC1ED3 /* Project object */;
|
||||||
|
}
|
7
examples/macos_app/Pathfinder Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
examples/macos_app/Pathfinder Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:Pathfinder Example.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1020"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "6AFD6FF422BD780D00AC1ED3"
|
||||||
|
BuildableName = "Pathfinder Example.app"
|
||||||
|
BlueprintName = "Pathfinder Example"
|
||||||
|
ReferencedContainer = "container:Pathfinder Example.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "6AFD6FF422BD780D00AC1ED3"
|
||||||
|
BuildableName = "Pathfinder Example.app"
|
||||||
|
BlueprintName = "Pathfinder Example"
|
||||||
|
ReferencedContainer = "container:Pathfinder Example.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "YES"
|
||||||
|
customWorkingDirectory = "/Users/pcwalton/Source/pathfinder/examples/macos_app"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "6AFD6FF422BD780D00AC1ED3"
|
||||||
|
BuildableName = "Pathfinder Example.app"
|
||||||
|
BlueprintName = "Pathfinder Example"
|
||||||
|
ReferencedContainer = "container:Pathfinder Example.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<AdditionalOptions>
|
||||||
|
<AdditionalOption
|
||||||
|
key = "NSZombieEnabled"
|
||||||
|
value = "YES"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</AdditionalOption>
|
||||||
|
<AdditionalOption
|
||||||
|
key = "MallocScribble"
|
||||||
|
value = ""
|
||||||
|
isEnabled = "YES">
|
||||||
|
</AdditionalOption>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "6AFD6FF422BD780D00AC1ED3"
|
||||||
|
BuildableName = "Pathfinder Example.app"
|
||||||
|
BlueprintName = "Pathfinder Example"
|
||||||
|
ReferencedContainer = "container:Pathfinder Example.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Bucket
|
||||||
|
type = "1"
|
||||||
|
version = "2.0">
|
||||||
|
<Breakpoints>
|
||||||
|
<BreakpointProxy
|
||||||
|
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
|
||||||
|
<BreakpointContent
|
||||||
|
shouldBeEnabled = "Yes"
|
||||||
|
ignoreCount = "0"
|
||||||
|
continueAfterRunningActions = "No"
|
||||||
|
scope = "0"
|
||||||
|
stopOnStyle = "0">
|
||||||
|
</BreakpointContent>
|
||||||
|
</BreakpointProxy>
|
||||||
|
</Breakpoints>
|
||||||
|
</Bucket>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>SchemeUserState</key>
|
||||||
|
<dict>
|
||||||
|
<key>Pathfinder Example.xcscheme_^#shared#^_</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
<dict>
|
||||||
|
<key>6AFD6FF422BD780D00AC1ED3</key>
|
||||||
|
<dict>
|
||||||
|
<key>primary</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// AppDelegate.h
|
||||||
|
// Pathfinder Example
|
||||||
|
//
|
||||||
|
// Created by Patrick Walton on 6/21/19.
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// AppDelegate.m
|
||||||
|
// Pathfinder Example
|
||||||
|
//
|
||||||
|
// Created by Patrick Walton on 6/21/19.
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AppDelegate.h"
|
||||||
|
|
||||||
|
@interface AppDelegate ()
|
||||||
|
|
||||||
|
@property (weak) IBOutlet NSWindow *window;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||||
|
// Insert code here to initialize your application
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
||||||
|
// Insert code here to tear down your application
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "16x16",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "16x16",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "32x32",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "32x32",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "128x128",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "128x128",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "256x256",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "256x256",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "512x512",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"size" : "512x512",
|
||||||
|
"scale" : "2x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,373 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
|
<customObject id="Voe-Tx-rLC" customClass="AppDelegate">
|
||||||
|
<connections>
|
||||||
|
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||||
|
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Pathfinder Example" id="1Xt-HY-uBw">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Pathfinder Example" systemMenu="apple" id="uQy-DD-JDr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="About Pathfinder Example" id="5kV-Vb-QxS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||||
|
<menuItem title="Preferences…" enabled="NO" keyEquivalent="," id="BOF-NM-1cW"/>
|
||||||
|
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
||||||
|
<menuItem title="Services" id="NMo-om-nkz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||||
|
<menuItem title="Hide Pathfinder Example" keyEquivalent="h" id="Olw-nP-bQN">
|
||||||
|
<connections>
|
||||||
|
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||||
|
<menuItem title="Quit Pathfinder Example" keyEquivalent="q" id="4sb-4s-VLi">
|
||||||
|
<connections>
|
||||||
|
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
|
||||||
|
<connections>
|
||||||
|
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
|
||||||
|
<connections>
|
||||||
|
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
|
||||||
|
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
|
||||||
|
<connections>
|
||||||
|
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
|
||||||
|
<connections>
|
||||||
|
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
|
||||||
|
<connections>
|
||||||
|
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Delete" id="pa3-QI-u2k">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
||||||
|
<connections>
|
||||||
|
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
|
||||||
|
<menuItem title="Find" id="4EN-yA-p0u">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Find" id="1b7-l0-nxx">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
|
||||||
|
<connections>
|
||||||
|
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
|
||||||
|
<connections>
|
||||||
|
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
|
||||||
|
<connections>
|
||||||
|
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
|
||||||
|
<connections>
|
||||||
|
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
|
||||||
|
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Substitutions" id="9ic-FL-obx">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
|
||||||
|
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Smart Links" id="cwL-P1-jid">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Data Detectors" id="tRr-pd-1PS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Transformations" id="2oI-Rn-ZJC">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Speech" id="xrE-MZ-jX0">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="View" id="H8h-7b-M4v">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="View" id="HyV-fh-RgO">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
|
||||||
|
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleSidebar:" target="-1" id="iwa-gc-5KM"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Window" id="aUF-d1-5bR">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
|
||||||
|
<connections>
|
||||||
|
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Zoom" id="R4o-n2-Eq4">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||||
|
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Help" id="wpr-3q-Mcd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Pathfinder Example Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||||
|
<connections>
|
||||||
|
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
<window title="Pathfinder Example" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
|
||||||
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||||
|
<rect key="contentRect" x="335" y="390" width="640" height="480"/>
|
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||||
|
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="640" height="480"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<customView id="naY-wz-xJX" customClass="PathfinderView">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="640" height="480"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
</customView>
|
||||||
|
</subviews>
|
||||||
|
</view>
|
||||||
|
</window>
|
||||||
|
</objects>
|
||||||
|
</document>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string></string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2019 The Pathfinder Project Developers. All rights reserved.</string>
|
||||||
|
<key>NSMainNibFile</key>
|
||||||
|
<string>MainMenu</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// PathfinderView.h
|
||||||
|
// Pathfinder Example
|
||||||
|
//
|
||||||
|
// Created by Patrick Walton on 6/21/19.
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
#include <pathfinder/pathfinder.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface PathfinderView : NSView {
|
||||||
|
id<MTLDevice> mDevice;
|
||||||
|
PFMetalRendererRef mRenderer;
|
||||||
|
PFCanvasFontContextRef mFontContext;
|
||||||
|
PFBuildOptionsRef mBuildOptions;
|
||||||
|
CVDisplayLinkRef mDisplayLink;
|
||||||
|
int32_t mFrameNumber;
|
||||||
|
CGSize mLayerSize;
|
||||||
|
NSLock *mRenderLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_render;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,194 @@
|
||||||
|
//
|
||||||
|
// PathfinderView.m
|
||||||
|
// Pathfinder Example
|
||||||
|
//
|
||||||
|
// Created by Patrick Walton on 6/21/19.
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
#import "PathfinderView.h"
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
static CVReturn outputCallback(CVDisplayLinkRef displayLink,
|
||||||
|
const CVTimeStamp *now,
|
||||||
|
const CVTimeStamp *outputTime,
|
||||||
|
CVOptionFlags flagsIn,
|
||||||
|
CVOptionFlags *flagsOut,
|
||||||
|
void *userData) {
|
||||||
|
[(__bridge PathfinderView *)userData _render];
|
||||||
|
return kCVReturnSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CATransform3D createPerspectiveMatrix(CGFloat fovY,
|
||||||
|
CGFloat aspect,
|
||||||
|
CGFloat zNear,
|
||||||
|
CGFloat zFar) {
|
||||||
|
CGFloat f = tan(1.0 / (fovY * 0.5));
|
||||||
|
CGFloat zDenom = 1.0 / (zNear - zFar);
|
||||||
|
|
||||||
|
CATransform3D transform = CATransform3DIdentity;
|
||||||
|
transform.m11 = f / aspect;
|
||||||
|
transform.m22 = f;
|
||||||
|
transform.m33 = (zFar + zNear) * zDenom;
|
||||||
|
transform.m34 = -1.0;
|
||||||
|
transform.m43 = 2.0 * zFar * zNear * zDenom;
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PFTransform3DF pfTransformFromCATransform(const CATransform3D *transform) {
|
||||||
|
// Core Animation matrices are in column-major order, while Pathfinder matrices are in
|
||||||
|
// row-major order (at least in the latter's C API). So transpose here.
|
||||||
|
PFTransform3DF pfTransform;
|
||||||
|
pfTransform.m00 = (float)transform->m11;
|
||||||
|
pfTransform.m01 = (float)transform->m21;
|
||||||
|
pfTransform.m02 = (float)transform->m31;
|
||||||
|
pfTransform.m03 = (float)transform->m41;
|
||||||
|
pfTransform.m10 = (float)transform->m12;
|
||||||
|
pfTransform.m11 = (float)transform->m22;
|
||||||
|
pfTransform.m12 = (float)transform->m32;
|
||||||
|
pfTransform.m13 = (float)transform->m42;
|
||||||
|
pfTransform.m20 = (float)transform->m13;
|
||||||
|
pfTransform.m21 = (float)transform->m23;
|
||||||
|
pfTransform.m22 = (float)transform->m33;
|
||||||
|
pfTransform.m23 = (float)transform->m43;
|
||||||
|
pfTransform.m30 = (float)transform->m14;
|
||||||
|
pfTransform.m31 = (float)transform->m24;
|
||||||
|
pfTransform.m32 = (float)transform->m34;
|
||||||
|
pfTransform.m33 = (float)transform->m44;
|
||||||
|
return pfTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation PathfinderView
|
||||||
|
|
||||||
|
#define FONT_SIZE 256.0f
|
||||||
|
|
||||||
|
- (void)_render {
|
||||||
|
[mRenderLock lock];
|
||||||
|
|
||||||
|
CGSize size = mLayerSize;
|
||||||
|
|
||||||
|
PFCanvasRef canvas = PFCanvasCreate(mFontContext, &(PFVector2F){size.width, size.height});
|
||||||
|
PFFillStyleRef fillStyle =
|
||||||
|
PFFillStyleCreateColor(&(PFColorU){0, 0, 0, 255});
|
||||||
|
PFCanvasSetFillStyle(canvas, fillStyle);
|
||||||
|
PFCanvasSetFontSize(canvas, FONT_SIZE);
|
||||||
|
PFCanvasSetTextAlign(canvas, PF_TEXT_ALIGN_CENTER);
|
||||||
|
PFVector2F textOrigin;
|
||||||
|
textOrigin.x = 0.0;
|
||||||
|
textOrigin.y = FONT_SIZE * 0.25;
|
||||||
|
PFCanvasFillText(canvas, "Pathfinder", 0, &textOrigin);
|
||||||
|
PFCanvasFillRect(canvas, &(const PFRectF){0.0, 0.0, 1.0, 1.0});
|
||||||
|
PFFillStyleDestroy(fillStyle);
|
||||||
|
|
||||||
|
PFSceneRef scene = PFCanvasCreateScene(canvas);
|
||||||
|
PFSceneProxyRef sceneProxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene);
|
||||||
|
|
||||||
|
int32_t frame = mFrameNumber;
|
||||||
|
int32_t nT = frame % 240;
|
||||||
|
if (nT > 120)
|
||||||
|
nT = 240 - nT;
|
||||||
|
|
||||||
|
CATransform3D transform =
|
||||||
|
CATransform3DMakeTranslation(0.0, 0.0, -8.0 + (CGFloat)nT / 120.0 * 8.0);
|
||||||
|
transform = CATransform3DRotate(transform,
|
||||||
|
frame / 120.0 * M_PI * 2.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
0.0);
|
||||||
|
transform = CATransform3DScale(transform, -2.0 / size.width, 2.0 / size.height, 1.0);
|
||||||
|
CGFloat aspect = size.width / size.height;
|
||||||
|
transform = CATransform3DConcat(transform,
|
||||||
|
createPerspectiveMatrix(M_PI * 0.25, aspect, 0.01, 10.0));
|
||||||
|
PFPerspective pfPerspective;
|
||||||
|
pfPerspective.transform = pfTransformFromCATransform(&transform);
|
||||||
|
pfPerspective.window_size.x = size.width;
|
||||||
|
pfPerspective.window_size.y = size.height;
|
||||||
|
|
||||||
|
PFBuildOptionsRef buildOptions = PFBuildOptionsCreate();
|
||||||
|
PFRenderTransformRef renderTransform = PFRenderTransformCreatePerspective(&pfPerspective);
|
||||||
|
PFBuildOptionsSetTransform(buildOptions, renderTransform);
|
||||||
|
PFSceneProxyBuildAndRenderMetal(sceneProxy, mRenderer, buildOptions);
|
||||||
|
|
||||||
|
PFMetalDevicePresentDrawable(PFMetalRendererGetDevice(mRenderer));
|
||||||
|
|
||||||
|
mFrameNumber++;
|
||||||
|
|
||||||
|
[mRenderLock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_checkCVResult:(CVReturn)result {
|
||||||
|
if (result != kCVReturnSuccess) {
|
||||||
|
@throw [NSException exceptionWithName:@"CoreVideoCallFailed"
|
||||||
|
reason:@"Core Video call failed"
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_initializeIfNecessary:(CAMetalLayer *)layer {
|
||||||
|
if (mDevice != nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mFrameNumber = 0;
|
||||||
|
|
||||||
|
mDevice = MTLCreateSystemDefaultDevice();
|
||||||
|
[layer setDevice:mDevice];
|
||||||
|
[layer setContentsScale:[[self window] backingScaleFactor]];
|
||||||
|
|
||||||
|
mRenderLock = [[NSLock alloc] init];
|
||||||
|
mLayerSize = [self convertSizeToBacking:[layer bounds].size];
|
||||||
|
|
||||||
|
PFMetalDeviceRef device = PFMetalDeviceCreate(layer);
|
||||||
|
PFResourceLoaderRef resourceLoader = PFFilesystemResourceLoaderLocate();
|
||||||
|
PFMetalDestFramebufferRef destFramebuffer =
|
||||||
|
PFMetalDestFramebufferCreateFullWindow(&(PFVector2I){mLayerSize.width, mLayerSize.height});
|
||||||
|
|
||||||
|
PFRendererOptions rendererOptions;
|
||||||
|
rendererOptions.background_color = (PFColorF){1.0, 1.0, 1.0, 1.0};
|
||||||
|
rendererOptions.flags = PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR;
|
||||||
|
mRenderer = PFMetalRendererCreate(device,
|
||||||
|
resourceLoader,
|
||||||
|
destFramebuffer,
|
||||||
|
&rendererOptions);
|
||||||
|
|
||||||
|
mFontContext = PFCanvasFontContextCreateWithSystemSource();
|
||||||
|
|
||||||
|
mBuildOptions = PFBuildOptionsCreate();
|
||||||
|
|
||||||
|
[self _checkCVResult:CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink)];
|
||||||
|
[self _checkCVResult:CVDisplayLinkSetOutputCallback(mDisplayLink,
|
||||||
|
outputCallback,
|
||||||
|
(__bridge void *_Nullable)(self))];
|
||||||
|
[self _checkCVResult:CVDisplayLinkStart(mDisplayLink)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CALayer *)makeBackingLayer {
|
||||||
|
return [[CAMetalLayer alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)wantsLayer {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)wantsUpdateLayer {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy {
|
||||||
|
return NSViewLayerContentsRedrawOnSetNeedsDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(NSRect)dirtyRect {
|
||||||
|
[self _initializeIfNecessary:(CAMetalLayer *)[self layer]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)displayLayer:(CALayer *)layer {
|
||||||
|
[self _initializeIfNecessary:(CAMetalLayer *)layer];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
[self _initializeIfNecessary:(CAMetalLayer *)[self layer]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict/>
|
||||||
|
</plist>
|
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// main.m
|
||||||
|
// Pathfinder Example
|
||||||
|
//
|
||||||
|
// Created by Patrick Walton on 6/21/19.
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[]) {
|
||||||
|
return NSApplicationMain(argc, argv);
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{Read, BufWriter};
|
|
||||||
use std::error::Error;
|
|
||||||
use pathfinder_svg::BuiltSVG;
|
|
||||||
use pathfinder_pdf::make_pdf;
|
|
||||||
use usvg::{Tree, Options};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
let mut args = std::env::args().skip(1);
|
|
||||||
let input = args.next().expect("no input given");
|
|
||||||
let output = args.next().expect("no output given");
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
|
||||||
File::open(input)?.read_to_end(&mut data)?;
|
|
||||||
let svg = BuiltSVG::from_tree(Tree::from_data(&data, &Options::default()).unwrap());
|
|
||||||
|
|
||||||
make_pdf(BufWriter::new(File::create(output)?), &svg.scene);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -24,7 +24,7 @@ use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_swf::{draw_paths_into_scene, process_swf_tags};
|
use pathfinder_swf::{draw_paths_into_scene, process_swf_tags};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::read;
|
use std::fs::read;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let resource_loader = FilesystemResourceLoader::locate();
|
let resource_loader = FilesystemResourceLoader::locate();
|
||||||
|
@ -118,7 +118,7 @@ fn main() {
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let scene = SceneProxy::from_scene(scene, RayonExecutor);
|
let scene = SceneProxy::from_scene(scene, RayonExecutor);
|
||||||
let mut build_options = BuildOptions::default();
|
let mut build_options = BuildOptions::default();
|
||||||
let scale_transform = Transform2DF::from_scale(
|
let scale_transform = Transform2F::from_scale(
|
||||||
Vector2F::new(device_pixel_ratio, device_pixel_ratio)
|
Vector2F::new(device_pixel_ratio, device_pixel_ratio)
|
||||||
);
|
);
|
||||||
build_options.transform = RenderTransform::Transform2D(scale_transform);
|
build_options.transform = RenderTransform::Transform2D(scale_transform);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pathfinder_pdf"
|
name = "pathfinder_export"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Sebastian Köln <sebk@rynx.org>"]
|
authors = ["Sebastian Köln <sebk@rynx.org>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
|
@ -0,0 +1,174 @@
|
||||||
|
use pathfinder_renderer::scene::Scene;
|
||||||
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
|
use pathfinder_content::segment::SegmentKind;
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
mod pdf;
|
||||||
|
use pdf::Pdf;
|
||||||
|
|
||||||
|
pub enum FileFormat {
|
||||||
|
/// Scalable Vector Graphics
|
||||||
|
SVG,
|
||||||
|
|
||||||
|
/// Portable Document Format
|
||||||
|
PDF,
|
||||||
|
|
||||||
|
/// PostScript
|
||||||
|
PS,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Export {
|
||||||
|
fn export<W: Write>(&self, writer: &mut W, format: FileFormat) -> io::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Export for Scene {
|
||||||
|
fn export<W: Write>(&self, writer: &mut W, format: FileFormat) -> io::Result<()> {
|
||||||
|
match format {
|
||||||
|
FileFormat::SVG => export_svg(self, writer),
|
||||||
|
FileFormat::PDF => export_pdf(self, writer),
|
||||||
|
FileFormat::PS => export_ps(self, writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn export_svg<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
|
let view_box = scene.view_box();
|
||||||
|
writeln!(
|
||||||
|
writer,
|
||||||
|
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"{} {} {} {}\">",
|
||||||
|
view_box.origin().x(),
|
||||||
|
view_box.origin().y(),
|
||||||
|
view_box.size().x(),
|
||||||
|
view_box.size().y()
|
||||||
|
)?;
|
||||||
|
for (paint, outline, name) in scene.paths() {
|
||||||
|
write!(writer, " <path")?;
|
||||||
|
if !name.is_empty() {
|
||||||
|
write!(writer, " id=\"{}\"", name)?;
|
||||||
|
}
|
||||||
|
writeln!(
|
||||||
|
writer,
|
||||||
|
" fill=\"{:?}\" d=\"{:?}\" />",
|
||||||
|
paint.color, outline
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
writeln!(writer, "</svg>")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn export_pdf<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
|
let mut pdf = Pdf::new();
|
||||||
|
let view_box = scene.view_box();
|
||||||
|
pdf.add_page(view_box.size());
|
||||||
|
|
||||||
|
let height = view_box.size().y();
|
||||||
|
let tr = |v: Vector2F| -> Vector2F {
|
||||||
|
let r = v - view_box.origin();
|
||||||
|
Vector2F::new(r.x(), height - r.y())
|
||||||
|
};
|
||||||
|
|
||||||
|
for (paint, outline, _) in scene.paths() {
|
||||||
|
pdf.set_fill_color(paint.color);
|
||||||
|
|
||||||
|
for contour in outline.contours() {
|
||||||
|
for (segment_index, segment) in contour.iter().enumerate() {
|
||||||
|
if segment_index == 0 {
|
||||||
|
pdf.move_to(tr(segment.baseline.from()));
|
||||||
|
}
|
||||||
|
|
||||||
|
match segment.kind {
|
||||||
|
SegmentKind::None => {}
|
||||||
|
SegmentKind::Line => pdf.line_to(tr(segment.baseline.to())),
|
||||||
|
SegmentKind::Quadratic => {
|
||||||
|
let current = segment.baseline.from();
|
||||||
|
let c = segment.ctrl.from();
|
||||||
|
let p = segment.baseline.to();
|
||||||
|
let c1 = Vector2F::splat(2./3.) * c + Vector2F::splat(1./3.) * current;
|
||||||
|
let c2 = Vector2F::splat(2./3.) * c + Vector2F::splat(1./3.) * p;
|
||||||
|
pdf.cubic_to(c1, c2, p);
|
||||||
|
}
|
||||||
|
SegmentKind::Cubic => pdf.cubic_to(tr(segment.ctrl.from()), tr(segment.ctrl.to()), tr(segment.baseline.to()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if contour.is_closed() {
|
||||||
|
pdf.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// closes implicitly
|
||||||
|
pdf.fill();
|
||||||
|
}
|
||||||
|
pdf.write_to(writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
|
struct P(Vector2F);
|
||||||
|
impl fmt::Display for P {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{} {}", self.0.x(), self.0.y())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let view_box = scene.view_box();
|
||||||
|
writeln!(writer, "%!PS-Adobe-3.0 EPSF-3.0")?;
|
||||||
|
writeln!(writer, "%%BoundingBox: {:.0} {:.0}",
|
||||||
|
P(view_box.origin()),
|
||||||
|
P(view_box.size()),
|
||||||
|
)?;
|
||||||
|
writeln!(writer, "%%HiResBoundingBox: {} {}",
|
||||||
|
P(view_box.origin()),
|
||||||
|
P(view_box.size()),
|
||||||
|
)?;
|
||||||
|
writeln!(writer, "0 {} translate", view_box.size().y())?;
|
||||||
|
writeln!(writer, "1 -1 scale")?;
|
||||||
|
|
||||||
|
for (paint, outline, name) in scene.paths() {
|
||||||
|
if !name.is_empty() {
|
||||||
|
writeln!(writer, "newpath % {}", name)?;
|
||||||
|
} else {
|
||||||
|
writeln!(writer, "newpath")?;
|
||||||
|
}
|
||||||
|
let color = paint.color.to_f32();
|
||||||
|
for contour in outline.contours() {
|
||||||
|
for (segment_index, segment) in contour.iter().enumerate() {
|
||||||
|
if segment_index == 0 {
|
||||||
|
writeln!(writer, "{} moveto", P(segment.baseline.from()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match segment.kind {
|
||||||
|
SegmentKind::None => {}
|
||||||
|
SegmentKind::Line => {
|
||||||
|
writeln!(writer, "{} lineto", P(segment.baseline.to()))?;
|
||||||
|
}
|
||||||
|
SegmentKind::Quadratic => {
|
||||||
|
let current = segment.baseline.from();
|
||||||
|
let c = segment.ctrl.from();
|
||||||
|
let p = segment.baseline.to();
|
||||||
|
let c1 = Vector2F::splat(2. / 3.) * c + Vector2F::splat(1. / 3.) * current;
|
||||||
|
let c2 = Vector2F::splat(2. / 3.) * c + Vector2F::splat(1. / 3.) * p;
|
||||||
|
writeln!(writer, "{} {} {} curveto", P(c1), P(c2), P(p))?;
|
||||||
|
}
|
||||||
|
SegmentKind::Cubic => {
|
||||||
|
writeln!(writer, "{} {} {} curveto",
|
||||||
|
P(segment.ctrl.from()),
|
||||||
|
P(segment.ctrl.to()),
|
||||||
|
P(segment.baseline.to())
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if contour.is_closed() {
|
||||||
|
writeln!(writer, "closepath")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(writer, "{} {} {} setrgbcolor", color.r(), color.g(), color.b())?;
|
||||||
|
writeln!(writer, "fill")?;
|
||||||
|
}
|
||||||
|
writeln!(writer, "showpage")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! This is a heavily modified version of the pdfpdf crate by Benjamin Kimock <kimockb@gmail.com> (aka. saethlin)
|
//! This is a heavily modified version of the pdfpdf crate by Benjamin Kimock <kimockb@gmail.com> (aka. saethlin)
|
||||||
|
|
||||||
use pathfinder_geometry::{vector::Vector2F, rect::RectF};
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_content::color::ColorU;
|
use pathfinder_content::color::ColorU;
|
||||||
use std::io::{self, Write, Cursor, Seek};
|
use std::io::{self, Write};
|
||||||
use deflate::Compression;
|
use deflate::Compression;
|
||||||
|
|
||||||
struct Counter<T> {
|
struct Counter<T> {
|
||||||
|
@ -19,9 +19,6 @@ impl<T> Counter<T> {
|
||||||
pub fn pos(&self) -> u64 {
|
pub fn pos(&self) -> u64 {
|
||||||
self.count
|
self.count
|
||||||
}
|
}
|
||||||
pub fn into_inner(self) -> T {
|
|
||||||
self.inner
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<W: Write> Write for Counter<W> {
|
impl<W: Write> Write for Counter<W> {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
@ -101,43 +98,6 @@ impl Pdf {
|
||||||
self.objects.len()
|
self.objects.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the compression level for this document
|
|
||||||
/// Calls to this method do not affect data produced by operations before the last .add_page
|
|
||||||
#[inline]
|
|
||||||
pub fn set_compression(&mut self, compression: Option<Compression>) {
|
|
||||||
self.compression = compression;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the PDF clipping box for the current page
|
|
||||||
#[inline]
|
|
||||||
pub fn set_clipping_box(&mut self, rect: RectF) {
|
|
||||||
let origin = rect.origin();
|
|
||||||
let size = rect.size();
|
|
||||||
writeln!(self.page_buffer, "{} {} {} {} re W n",
|
|
||||||
origin.x(),
|
|
||||||
origin.y(),
|
|
||||||
size.x(),
|
|
||||||
size.y()
|
|
||||||
).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the current line width
|
|
||||||
#[inline]
|
|
||||||
pub fn set_line_width(&mut self, width: f32) {
|
|
||||||
writeln!(self.page_buffer, "{} w", width).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the color for all subsequent drawing operations
|
|
||||||
#[inline]
|
|
||||||
pub fn set_stroke_color(&mut self, color: ColorU) {
|
|
||||||
let norm = |color| f32::from(color) / 255.0;
|
|
||||||
writeln!(self.page_buffer, "{} {} {} RG",
|
|
||||||
norm(color.r),
|
|
||||||
norm(color.g),
|
|
||||||
norm(color.b)
|
|
||||||
).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the color for all subsequent drawing operations
|
/// Set the color for all subsequent drawing operations
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fill_color(&mut self, color: ColorU) {
|
pub fn set_fill_color(&mut self, color: ColorU) {
|
||||||
|
@ -178,10 +138,6 @@ impl Pdf {
|
||||||
writeln!(self.page_buffer, "f").unwrap();
|
writeln!(self.page_buffer, "f").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stroke(&mut self) {
|
|
||||||
writeln!(self.page_buffer, "s").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close(&mut self) {
|
pub fn close(&mut self) {
|
||||||
writeln!(self.page_buffer, "h").unwrap();
|
writeln!(self.page_buffer, "h").unwrap();
|
||||||
}
|
}
|
||||||
|
@ -218,7 +174,7 @@ impl Pdf {
|
||||||
/Resources <<\n"
|
/Resources <<\n"
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
|
||||||
for (idx, obj) in self.objects.iter().enumerate().filter(|&(_, o)| o.is_xobject) {
|
for (idx, _obj) in self.objects.iter().enumerate().filter(|&(_, o)| o.is_xobject) {
|
||||||
write!(page_object, "/XObject {} 0 R ", idx+1).unwrap();
|
write!(page_object, "/XObject {} 0 R ", idx+1).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +214,7 @@ impl Pdf {
|
||||||
self.objects.iter().filter(|o| o.is_page).count()
|
self.objects.iter().filter(|o| o.is_page).count()
|
||||||
)?;
|
)?;
|
||||||
out.write_all(b"/Kids [")?;
|
out.write_all(b"/Kids [")?;
|
||||||
for (idx, obj) in self.objects.iter().enumerate().filter(|&(_, obj)| obj.is_page) {
|
for (idx, _obj) in self.objects.iter().enumerate().filter(|&(_, obj)| obj.is_page) {
|
||||||
write!(out, "{} 0 R ", idx + 1)?;
|
write!(out, "{} 0 R ", idx + 1)?;
|
||||||
}
|
}
|
||||||
out.write_all(b"] >>\nendobj\n")?;
|
out.write_all(b"] >>\nendobj\n")?;
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
//! Line segment types, optimized with SIMD.
|
//! Line segment types, optimized with SIMD.
|
||||||
|
|
||||||
use crate::vector::Vector2F;
|
|
||||||
use crate::transform2d::Matrix2x2F;
|
use crate::transform2d::Matrix2x2F;
|
||||||
|
use crate::vector::Vector2F;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::{Add, Sub};
|
use std::ops::{Add, Sub};
|
||||||
|
@ -26,44 +26,44 @@ impl LineSegment2F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from(&self) -> Vector2F {
|
pub fn from(self) -> Vector2F {
|
||||||
Vector2F(self.0)
|
Vector2F(self.0.xy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to(&self) -> Vector2F {
|
pub fn to(self) -> Vector2F {
|
||||||
Vector2F(self.0.zwxy())
|
Vector2F(self.0.zw())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_from(&mut self, point: &Vector2F) {
|
pub fn set_from(&mut self, point: Vector2F) {
|
||||||
self.0 = point.0.concat_xy_zw(self.0)
|
self.0 = point.0.to_f32x4().concat_xy_zw(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_to(&mut self, point: &Vector2F) {
|
pub fn set_to(&mut self, point: Vector2F) {
|
||||||
self.0 = self.0.concat_xy_xy(point.0)
|
self.0 = self.0.concat_xy_xy(point.0.to_f32x4())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_x(&self) -> f32 {
|
pub fn from_x(self) -> f32 {
|
||||||
self.0[0]
|
self.0[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_y(&self) -> f32 {
|
pub fn from_y(self) -> f32 {
|
||||||
self.0[1]
|
self.0[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_x(&self) -> f32 {
|
pub fn to_x(self) -> f32 {
|
||||||
self.0[2]
|
self.0[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_y(&self) -> f32 {
|
pub fn to_y(self) -> f32 {
|
||||||
self.0[3]
|
self.0[3]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,22 +88,22 @@ impl LineSegment2F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn translate(&self, offset: Vector2F) -> LineSegment2F {
|
pub fn translate(self, offset: Vector2F) -> LineSegment2F {
|
||||||
LineSegment2F(self.0 + offset.0.xyxy())
|
LineSegment2F(self.0 + offset.0.to_f32x4().xyxy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale(&self, factor: f32) -> LineSegment2F {
|
pub fn scale(self, factor: f32) -> LineSegment2F {
|
||||||
LineSegment2F(self.0 * F32x4::splat(factor))
|
LineSegment2F(self.0 * F32x4::splat(factor))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_xy(&self, factors: Vector2F) -> LineSegment2F {
|
pub fn scale_xy(self, factors: Vector2F) -> LineSegment2F {
|
||||||
LineSegment2F(self.0 * factors.0.xyxy())
|
LineSegment2F(self.0 * factors.0.to_f32x4().xyxy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn split(&self, t: f32) -> (LineSegment2F, LineSegment2F) {
|
pub fn split(self, t: f32) -> (LineSegment2F, LineSegment2F) {
|
||||||
debug_assert!(t >= 0.0 && t <= 1.0);
|
debug_assert!(t >= 0.0 && t <= 1.0);
|
||||||
let (from_from, to_to) = (self.0.xyxy(), self.0.zwzw());
|
let (from_from, to_to) = (self.0.xyxy(), self.0.zwzw());
|
||||||
let d_d = to_to - from_from;
|
let d_d = to_to - from_from;
|
||||||
|
@ -116,7 +116,7 @@ impl LineSegment2F {
|
||||||
|
|
||||||
// Returns the left segment first, followed by the right segment.
|
// Returns the left segment first, followed by the right segment.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn split_at_x(&self, x: f32) -> (LineSegment2F, LineSegment2F) {
|
pub fn split_at_x(self, x: f32) -> (LineSegment2F, LineSegment2F) {
|
||||||
let (min_part, max_part) = self.split(self.solve_t_for_x(x));
|
let (min_part, max_part) = self.split(self.solve_t_for_x(x));
|
||||||
if min_part.from_x() < max_part.from_x() {
|
if min_part.from_x() < max_part.from_x() {
|
||||||
(min_part, max_part)
|
(min_part, max_part)
|
||||||
|
@ -127,7 +127,7 @@ impl LineSegment2F {
|
||||||
|
|
||||||
// Returns the upper segment first, followed by the lower segment.
|
// Returns the upper segment first, followed by the lower segment.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn split_at_y(&self, y: f32) -> (LineSegment2F, LineSegment2F) {
|
pub fn split_at_y(self, y: f32) -> (LineSegment2F, LineSegment2F) {
|
||||||
let (min_part, max_part) = self.split(self.solve_t_for_y(y));
|
let (min_part, max_part) = self.split(self.solve_t_for_y(y));
|
||||||
|
|
||||||
// Make sure we compare `from_y` and `to_y` to properly handle the case in which one of the
|
// Make sure we compare `from_y` and `to_y` to properly handle the case in which one of the
|
||||||
|
@ -140,32 +140,32 @@ impl LineSegment2F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn solve_t_for_x(&self, x: f32) -> f32 {
|
pub fn solve_t_for_x(self, x: f32) -> f32 {
|
||||||
(x - self.from_x()) / (self.to_x() - self.from_x())
|
(x - self.from_x()) / (self.to_x() - self.from_x())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn solve_t_for_y(&self, y: f32) -> f32 {
|
pub fn solve_t_for_y(self, y: f32) -> f32 {
|
||||||
(y - self.from_y()) / (self.to_y() - self.from_y())
|
(y - self.from_y()) / (self.to_y() - self.from_y())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn solve_x_for_y(&self, y: f32) -> f32 {
|
pub fn solve_x_for_y(self, y: f32) -> f32 {
|
||||||
util::lerp(self.from_x(), self.to_x(), self.solve_t_for_y(y))
|
util::lerp(self.from_x(), self.to_x(), self.solve_t_for_y(y))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn solve_y_for_x(&self, x: f32) -> f32 {
|
pub fn solve_y_for_x(self, x: f32) -> f32 {
|
||||||
util::lerp(self.from_y(), self.to_y(), self.solve_t_for_x(x))
|
util::lerp(self.from_y(), self.to_y(), self.solve_t_for_x(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reversed(&self) -> LineSegment2F {
|
pub fn reversed(self) -> LineSegment2F {
|
||||||
LineSegment2F(self.0.zwxy())
|
LineSegment2F(self.0.zwxy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn upper_point(&self) -> Vector2F {
|
pub fn upper_point(self) -> Vector2F {
|
||||||
if self.from_y() < self.to_y() {
|
if self.from_y() < self.to_y() {
|
||||||
self.from()
|
self.from()
|
||||||
} else {
|
} else {
|
||||||
|
@ -174,27 +174,27 @@ impl LineSegment2F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min_x(&self) -> f32 {
|
pub fn min_x(self) -> f32 {
|
||||||
f32::min(self.from_x(), self.to_x())
|
f32::min(self.from_x(), self.to_x())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn max_x(&self) -> f32 {
|
pub fn max_x(self) -> f32 {
|
||||||
f32::max(self.from_x(), self.to_x())
|
f32::max(self.from_x(), self.to_x())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min_y(&self) -> f32 {
|
pub fn min_y(self) -> f32 {
|
||||||
f32::min(self.from_y(), self.to_y())
|
f32::min(self.from_y(), self.to_y())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn max_y(&self) -> f32 {
|
pub fn max_y(self) -> f32 {
|
||||||
f32::max(self.from_y(), self.to_y())
|
f32::max(self.from_y(), self.to_y())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn y_winding(&self) -> i32 {
|
pub fn y_winding(self) -> i32 {
|
||||||
if self.from_y() < self.to_y() {
|
if self.from_y() < self.to_y() {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
|
@ -205,9 +205,9 @@ impl LineSegment2F {
|
||||||
// Reverses if necessary so that the from point is above the to point. Calling this method
|
// Reverses if necessary so that the from point is above the to point. Calling this method
|
||||||
// again will undo the transformation.
|
// again will undo the transformation.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn orient(&self, y_winding: i32) -> LineSegment2F {
|
pub fn orient(self, y_winding: i32) -> LineSegment2F {
|
||||||
if y_winding >= 0 {
|
if y_winding >= 0 {
|
||||||
*self
|
self
|
||||||
} else {
|
} else {
|
||||||
self.reversed()
|
self.reversed()
|
||||||
}
|
}
|
||||||
|
@ -215,55 +215,50 @@ impl LineSegment2F {
|
||||||
|
|
||||||
// TODO(pcwalton): Optimize with SIMD.
|
// TODO(pcwalton): Optimize with SIMD.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn square_length(&self) -> f32 {
|
pub fn square_length(self) -> f32 {
|
||||||
let (dx, dy) = (self.to_x() - self.from_x(), self.to_y() - self.from_y());
|
let (dx, dy) = (self.to_x() - self.from_x(), self.to_y() - self.from_y());
|
||||||
dx * dx + dy * dy
|
dx * dx + dy * dy
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn vector(&self) -> Vector2F {
|
pub fn vector(self) -> Vector2F {
|
||||||
self.to() - self.from()
|
self.to() - self.from()
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://www.cs.swan.ac.uk/~cssimon/line_intersection.html
|
// http://www.cs.swan.ac.uk/~cssimon/line_intersection.html
|
||||||
pub fn intersection_t(&self, other: &LineSegment2F) -> Option<f32> {
|
pub fn intersection_t(self, other: LineSegment2F) -> Option<f32> {
|
||||||
let p0p1 = self.vector();
|
let p0p1 = self.vector();
|
||||||
let matrix = Matrix2x2F(other.vector().0.concat_xy_xy((-p0p1).0));
|
let matrix = Matrix2x2F(other.vector().0.concat_xy_xy((-p0p1).0));
|
||||||
if f32::abs(matrix.det()) < EPSILON {
|
if f32::abs(matrix.det()) < EPSILON {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
return Some(matrix.inverse().transform_point(self.from() - other.from()).y());
|
return Some((matrix.inverse() * (self.from() - other.from())).y());
|
||||||
|
|
||||||
const EPSILON: f32 = 0.0001;
|
const EPSILON: f32 = 0.0001;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sample(&self, t: f32) -> Vector2F {
|
pub fn sample(self, t: f32) -> Vector2F {
|
||||||
self.from() + self.vector().scale(t)
|
self.from() + self.vector().scale(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn midpoint(&self) -> Vector2F {
|
pub fn midpoint(self) -> Vector2F {
|
||||||
self.sample(0.5)
|
self.sample(0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn offset(&self, distance: f32) -> LineSegment2F {
|
pub fn offset(self, distance: f32) -> LineSegment2F {
|
||||||
if self.is_zero_length() {
|
if self.is_zero_length() {
|
||||||
*self
|
self
|
||||||
} else {
|
} else {
|
||||||
*self
|
self + self.vector().yx().normalize().scale_xy(Vector2F::new(-distance, distance))
|
||||||
+ self
|
|
||||||
.vector()
|
|
||||||
.yx()
|
|
||||||
.normalize()
|
|
||||||
.scale_xy(Vector2F::new(-distance, distance))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_zero_length(&self) -> bool {
|
pub fn is_zero_length(self) -> bool {
|
||||||
self.vector().is_zero()
|
self.vector().is_zero()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,7 +267,7 @@ impl Add<Vector2F> for LineSegment2F {
|
||||||
type Output = LineSegment2F;
|
type Output = LineSegment2F;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(self, point: Vector2F) -> LineSegment2F {
|
fn add(self, point: Vector2F) -> LineSegment2F {
|
||||||
LineSegment2F(self.0 + point.0.xyxy())
|
LineSegment2F(self.0 + point.0.to_f32x4().xyxy())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,14 +275,22 @@ impl Sub<Vector2F> for LineSegment2F {
|
||||||
type Output = LineSegment2F;
|
type Output = LineSegment2F;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sub(self, point: Vector2F) -> LineSegment2F {
|
fn sub(self, point: Vector2F) -> LineSegment2F {
|
||||||
LineSegment2F(self.0 - point.0.xyxy())
|
LineSegment2F(self.0 - point.0.to_f32x4().xyxy())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
pub struct LineSegmentU4(pub u16);
|
pub struct LineSegmentU4 {
|
||||||
|
pub from: u8,
|
||||||
|
pub to: u8,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
pub struct LineSegmentU8(pub u32);
|
pub struct LineSegmentU8 {
|
||||||
|
pub from_x: u8,
|
||||||
|
pub from_y: u8,
|
||||||
|
pub to_x: u8,
|
||||||
|
pub to_y: u8,
|
||||||
|
}
|
||||||
|
|
|
@ -29,36 +29,34 @@ impl RectF {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn origin(&self) -> Vector2F {
|
pub fn origin(&self) -> Vector2F {
|
||||||
Vector2F(self.0)
|
Vector2F(self.0.xy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> Vector2F {
|
pub fn size(&self) -> Vector2F {
|
||||||
Vector2F(self.0.zwxy() - self.0.xyxy())
|
Vector2F(self.0.zw() - self.0.xy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn upper_right(&self) -> Vector2F {
|
pub fn upper_right(&self) -> Vector2F {
|
||||||
Vector2F(self.0.zyxw())
|
Vector2F(self.0.zy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn lower_left(&self) -> Vector2F {
|
pub fn lower_left(&self) -> Vector2F {
|
||||||
Vector2F(self.0.xwzy())
|
Vector2F(self.0.xw())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn lower_right(&self) -> Vector2F {
|
pub fn lower_right(&self) -> Vector2F {
|
||||||
Vector2F(self.0.zwxy())
|
Vector2F(self.0.zw())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains_point(&self, point: Vector2F) -> bool {
|
pub fn contains_point(&self, point: Vector2F) -> bool {
|
||||||
// self.origin <= point && point <= self.lower_right
|
// self.origin <= point && point <= self.lower_right
|
||||||
self.0
|
let point = point.0.to_f32x4();
|
||||||
.concat_xy_xy(point.0)
|
self.0.concat_xy_xy(point).packed_le(point.concat_xy_zw(self.0)).is_all_ones()
|
||||||
.packed_le(point.0.concat_xy_zw(self.0))
|
|
||||||
.is_all_ones()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -166,27 +164,27 @@ impl RectI {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn origin(&self) -> Vector2I {
|
pub fn origin(&self) -> Vector2I {
|
||||||
Vector2I(self.0)
|
Vector2I(self.0.xy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> Vector2I {
|
pub fn size(&self) -> Vector2I {
|
||||||
Vector2I(self.0.zwxy() - self.0.xyxy())
|
Vector2I(self.0.zw() - self.0.xy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn upper_right(&self) -> Vector2I {
|
pub fn upper_right(&self) -> Vector2I {
|
||||||
Vector2I(self.0.zyxw())
|
Vector2I(self.0.zy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn lower_left(&self) -> Vector2I {
|
pub fn lower_left(&self) -> Vector2I {
|
||||||
Vector2I(self.0.xwzy())
|
Vector2I(self.0.xw())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn lower_right(&self) -> Vector2I {
|
pub fn lower_right(&self) -> Vector2I {
|
||||||
Vector2I(self.0.zwxy())
|
Vector2I(self.0.zw())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -213,7 +211,8 @@ impl RectI {
|
||||||
pub fn contains_point(&self, point: Vector2I) -> bool {
|
pub fn contains_point(&self, point: Vector2I) -> bool {
|
||||||
// self.origin <= point && point <= self.lower_right - 1
|
// self.origin <= point && point <= self.lower_right - 1
|
||||||
let lower_right = self.lower_right() - Vector2I::splat(1);
|
let lower_right = self.lower_right() - Vector2I::splat(1);
|
||||||
self.0
|
self.origin()
|
||||||
|
.0
|
||||||
.concat_xy_xy(point.0)
|
.concat_xy_xy(point.0)
|
||||||
.packed_le(point.0.concat_xy_xy(lower_right.0))
|
.packed_le(point.0.concat_xy_xy(lower_right.0))
|
||||||
.is_all_ones()
|
.is_all_ones()
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
use crate::line_segment::LineSegment2F;
|
use crate::line_segment::LineSegment2F;
|
||||||
use crate::vector::Vector2F;
|
use crate::vector::Vector2F;
|
||||||
use crate::rect::RectF;
|
use crate::rect::RectF;
|
||||||
use crate::transform3d::Transform3DF;
|
use crate::transform3d::Transform4F;
|
||||||
use crate::unit_vector::UnitVector;
|
use crate::unit_vector::UnitVector;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::Sub;
|
use std::ops::{Mul, MulAssign, Sub};
|
||||||
|
|
||||||
/// A 2x2 matrix, optimized with SIMD, in column-major order.
|
/// A 2x2 matrix, optimized with SIMD, in column-major order.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
@ -42,22 +42,12 @@ impl Matrix2x2F {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_rotation_vector(vector: UnitVector) -> Matrix2x2F {
|
pub fn from_rotation_vector(vector: UnitVector) -> Matrix2x2F {
|
||||||
Matrix2x2F((vector.0).0.xyyx() * F32x4::new(1.0, 1.0, -1.0, 1.0))
|
Matrix2x2F((vector.0).0.to_f32x4().xyyx() * F32x4::new(1.0, 1.0, -1.0, 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32) -> Matrix2x2F {
|
pub fn row_major(m00: f32, m01: f32, m10: f32, m11: f32) -> Matrix2x2F {
|
||||||
Matrix2x2F(F32x4::new(m11, m21, m12, m22))
|
Matrix2x2F(F32x4::new(m00, m10, m01, m11))
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn post_mul(&self, other: &Matrix2x2F) -> Matrix2x2F {
|
|
||||||
Matrix2x2F(self.0.xyxy() * other.0.xxzz() + self.0.zwzw() * other.0.yyww())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn pre_mul(&self, other: &Matrix2x2F) -> Matrix2x2F {
|
|
||||||
other.post_mul(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -70,12 +60,6 @@ impl Matrix2x2F {
|
||||||
Matrix2x2F(self.0.wyzx() * F32x4::new(1.0, -1.0, -1.0, 1.0))
|
Matrix2x2F(self.0.wyzx() * F32x4::new(1.0, -1.0, -1.0, 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn transform_point(&self, point: Vector2F) -> Vector2F {
|
|
||||||
let halves = self.0 * point.0.xxyy();
|
|
||||||
Vector2F(halves + halves.zwzw())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn det(&self) -> f32 {
|
pub fn det(&self) -> f32 {
|
||||||
self.0[0] * self.0[3] - self.0[2] * self.0[1]
|
self.0[0] * self.0[3] - self.0[2] * self.0[1]
|
||||||
|
@ -112,49 +96,71 @@ impl Sub<Matrix2x2F> for Matrix2x2F {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An affine transform, optimized with SIMD.
|
impl Mul<Matrix2x2F> for Matrix2x2F {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
type Output = Matrix2x2F;
|
||||||
pub struct Transform2DF {
|
#[inline]
|
||||||
// Row-major order.
|
fn mul(self, other: Matrix2x2F) -> Matrix2x2F {
|
||||||
matrix: Matrix2x2F,
|
Matrix2x2F(self.0.xyxy() * other.0.xxzz() + self.0.zwzw() * other.0.yyww())
|
||||||
vector: Vector2F,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Transform2DF {
|
impl Mul<Vector2F> for Matrix2x2F {
|
||||||
|
type Output = Vector2F;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Transform2DF {
|
fn mul(self, vector: Vector2F) -> Vector2F {
|
||||||
|
let halves = self.0 * vector.0.to_f32x4().xxyy();
|
||||||
|
Vector2F(halves.xy() + halves.zw())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An affine transform, optimized with SIMD.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Transform2F {
|
||||||
|
// Row-major order.
|
||||||
|
pub matrix: Matrix2x2F,
|
||||||
|
pub vector: Vector2F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Transform2F {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Transform2F {
|
||||||
Self::from_scale(Vector2F::splat(1.0))
|
Self::from_scale(Vector2F::splat(1.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transform2DF {
|
impl Transform2F {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_scale(scale: Vector2F) -> Transform2DF {
|
pub fn from_scale(scale: Vector2F) -> Transform2F {
|
||||||
Transform2DF {
|
Transform2F {
|
||||||
matrix: Matrix2x2F::from_scale(scale),
|
matrix: Matrix2x2F::from_scale(scale),
|
||||||
vector: Vector2F::default(),
|
vector: Vector2F::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_rotation(theta: f32) -> Transform2DF {
|
pub fn from_uniform_scale(scale: f32) -> Transform2F {
|
||||||
Transform2DF {
|
Transform2F::from_scale(Vector2F::splat(scale))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_rotation(theta: f32) -> Transform2F {
|
||||||
|
Transform2F {
|
||||||
matrix: Matrix2x2F::from_rotation(theta),
|
matrix: Matrix2x2F::from_rotation(theta),
|
||||||
vector: Vector2F::default(),
|
vector: Vector2F::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_rotation_vector(vector: UnitVector) -> Transform2DF {
|
pub fn from_rotation_vector(vector: UnitVector) -> Transform2F {
|
||||||
Transform2DF {
|
Transform2F {
|
||||||
matrix: Matrix2x2F::from_rotation_vector(vector),
|
matrix: Matrix2x2F::from_rotation_vector(vector),
|
||||||
vector: Vector2F::default(),
|
vector: Vector2F::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_translation(vector: Vector2F) -> Transform2DF {
|
pub fn from_translation(vector: Vector2F) -> Transform2F {
|
||||||
Transform2DF { matrix: Matrix2x2F::default(), vector }
|
Transform2F { matrix: Matrix2x2F::default(), vector }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -162,58 +168,24 @@ impl Transform2DF {
|
||||||
scale: Vector2F,
|
scale: Vector2F,
|
||||||
theta: f32,
|
theta: f32,
|
||||||
translation: Vector2F,
|
translation: Vector2F,
|
||||||
) -> Transform2DF {
|
) -> Transform2F {
|
||||||
let rotation = Transform2DF::from_rotation(theta);
|
let rotation = Transform2F::from_rotation(theta);
|
||||||
let translation = Transform2DF::from_translation(translation);
|
let translation = Transform2F::from_translation(translation);
|
||||||
Transform2DF::from_scale(scale).post_mul(&rotation).post_mul(&translation)
|
Transform2F::from_scale(scale) * rotation * translation
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) -> Transform2DF {
|
pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) -> Transform2F {
|
||||||
Transform2DF {
|
Transform2F {
|
||||||
matrix: Matrix2x2F::row_major(m11, m12, m21, m22),
|
matrix: Matrix2x2F::row_major(m11, m12, m21, m22),
|
||||||
vector: Vector2F::new(m31, m32),
|
vector: Vector2F::new(m31, m32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn transform_point(&self, point: Vector2F) -> Vector2F {
|
|
||||||
self.matrix.transform_point(point) + self.vector
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn transform_line_segment(&self, line_segment: &LineSegment2F) -> LineSegment2F {
|
|
||||||
LineSegment2F::new(self.transform_point(line_segment.from()),
|
|
||||||
self.transform_point(line_segment.to()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn transform_rect(&self, rect: &RectF) -> RectF {
|
|
||||||
let upper_left = self.transform_point(rect.origin());
|
|
||||||
let upper_right = self.transform_point(rect.upper_right());
|
|
||||||
let lower_left = self.transform_point(rect.lower_left());
|
|
||||||
let lower_right = self.transform_point(rect.lower_right());
|
|
||||||
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
|
|
||||||
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
|
|
||||||
RectF::from_points(min_point, max_point)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn post_mul(&self, other: &Transform2DF) -> Transform2DF {
|
|
||||||
let matrix = self.matrix.post_mul(&other.matrix);
|
|
||||||
let vector = other.transform_point(self.vector);
|
|
||||||
Transform2DF { matrix, vector }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn pre_mul(&self, other: &Transform2DF) -> Transform2DF {
|
|
||||||
other.post_mul(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(pcwalton): Optimize better with SIMD.
|
// TODO(pcwalton): Optimize better with SIMD.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_3d(&self) -> Transform3DF {
|
pub fn to_3d(&self) -> Transform4F {
|
||||||
Transform3DF::row_major(
|
Transform4F::row_major(
|
||||||
self.matrix.0[0],
|
self.matrix.0[0],
|
||||||
self.matrix.0[1],
|
self.matrix.0[1],
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -235,7 +207,7 @@ impl Transform2DF {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_identity(&self) -> bool {
|
pub fn is_identity(&self) -> bool {
|
||||||
*self == Transform2DF::default()
|
*self == Transform2F::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -256,18 +228,23 @@ impl Transform2DF {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn post_translate(&self, vector: Vector2F) -> Transform2DF {
|
pub fn translate(&self, vector: Vector2F) -> Transform2F {
|
||||||
self.post_mul(&Transform2DF::from_translation(vector))
|
Transform2F::from_translation(vector) * *self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn post_rotate(&self, theta: f32) -> Transform2DF {
|
pub fn rotate(&self, theta: f32) -> Transform2F {
|
||||||
self.post_mul(&Transform2DF::from_rotation(theta))
|
Transform2F::from_rotation(theta) * *self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn post_scale(&self, scale: Vector2F) -> Transform2DF {
|
pub fn scale(&self, scale: Vector2F) -> Transform2F {
|
||||||
self.post_mul(&Transform2DF::from_scale(scale))
|
Transform2F::from_scale(scale) * *self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn uniform_scale(&self, scale: f32) -> Transform2F {
|
||||||
|
self.scale(Vector2F::splat(scale))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the translation part of this matrix.
|
/// Returns the translation part of this matrix.
|
||||||
|
@ -291,6 +268,52 @@ impl Transform2DF {
|
||||||
/// This decomposition assumes that scale, rotation, and translation are applied in that order.
|
/// This decomposition assumes that scale, rotation, and translation are applied in that order.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_factor(&self) -> f32 {
|
pub fn scale_factor(&self) -> f32 {
|
||||||
Vector2F(self.matrix.0.zwxy()).length()
|
Vector2F(self.matrix.0.zw()).length()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Transform2F> for Transform2F {
|
||||||
|
type Output = Transform2F;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: Transform2F) -> Transform2F {
|
||||||
|
Transform2F {
|
||||||
|
matrix: self.matrix * other.matrix,
|
||||||
|
vector: self * other.vector,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Vector2F> for Transform2F {
|
||||||
|
type Output = Vector2F;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, vector: Vector2F) -> Vector2F {
|
||||||
|
self.matrix * vector + self.vector
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<LineSegment2F> for Transform2F {
|
||||||
|
type Output = LineSegment2F;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, line_segment: LineSegment2F) -> LineSegment2F {
|
||||||
|
LineSegment2F::new(self * line_segment.from(), self * line_segment.to())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<RectF> for Transform2F {
|
||||||
|
type Output = RectF;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rect: RectF) -> RectF {
|
||||||
|
let (upper_left, upper_right) = (self * rect.origin(), self * rect.upper_right());
|
||||||
|
let (lower_left, lower_right) = (self * rect.lower_left(), self * rect.lower_right());
|
||||||
|
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
|
||||||
|
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
|
||||||
|
RectF::from_points(min_point, max_point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign for Transform2F {
|
||||||
|
#[inline]
|
||||||
|
fn mul_assign(&mut self, other: Transform2F) {
|
||||||
|
*self = *self * other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,24 +14,24 @@ use crate::vector::{Vector2F, Vector2I, Vector4F};
|
||||||
use crate::rect::RectF;
|
use crate::rect::RectF;
|
||||||
use crate::transform2d::Matrix2x2F;
|
use crate::transform2d::Matrix2x2F;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::{Add, Neg};
|
use std::ops::{Add, Mul, MulAssign, Neg};
|
||||||
|
|
||||||
/// An transform, optimized with SIMD.
|
/// An transform, optimized with SIMD.
|
||||||
///
|
///
|
||||||
/// In column-major order.
|
/// In column-major order.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Transform3DF {
|
pub struct Transform4F {
|
||||||
pub c0: F32x4,
|
pub c0: F32x4,
|
||||||
pub c1: F32x4,
|
pub c1: F32x4,
|
||||||
pub c2: F32x4,
|
pub c2: F32x4,
|
||||||
pub c3: F32x4,
|
pub c3: F32x4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Transform3DF {
|
impl Default for Transform4F {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Transform3DF {
|
fn default() -> Transform4F {
|
||||||
Transform3DF {
|
Transform4F {
|
||||||
c0: F32x4::new(1.0, 0.0, 0.0, 0.0),
|
c0: F32x4::new(1.0, 0.0, 0.0, 0.0),
|
||||||
c1: F32x4::new(0.0, 1.0, 0.0, 0.0),
|
c1: F32x4::new(0.0, 1.0, 0.0, 0.0),
|
||||||
c2: F32x4::new(0.0, 0.0, 1.0, 0.0),
|
c2: F32x4::new(0.0, 0.0, 1.0, 0.0),
|
||||||
|
@ -40,7 +40,7 @@ impl Default for Transform3DF {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transform3DF {
|
impl Transform4F {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn row_major(
|
pub fn row_major(
|
||||||
m00: f32,
|
m00: f32,
|
||||||
|
@ -59,8 +59,8 @@ impl Transform3DF {
|
||||||
m31: f32,
|
m31: f32,
|
||||||
m32: f32,
|
m32: f32,
|
||||||
m33: f32,
|
m33: f32,
|
||||||
) -> Transform3DF {
|
) -> Transform4F {
|
||||||
Transform3DF {
|
Transform4F {
|
||||||
c0: F32x4::new(m00, m10, m20, m30),
|
c0: F32x4::new(m00, m10, m20, m30),
|
||||||
c1: F32x4::new(m01, m11, m21, m31),
|
c1: F32x4::new(m01, m11, m21, m31),
|
||||||
c2: F32x4::new(m02, m12, m22, m32),
|
c2: F32x4::new(m02, m12, m22, m32),
|
||||||
|
@ -69,26 +69,28 @@ impl Transform3DF {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_scale(x: f32, y: f32, z: f32) -> Transform3DF {
|
pub fn from_scale(scale: Vector4F) -> Transform4F {
|
||||||
Transform3DF::row_major(
|
Transform4F {
|
||||||
x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, 1.0,
|
c0: F32x4::new(scale.x(), 0.0, 0.0, 0.0),
|
||||||
)
|
c1: F32x4::new(0.0, scale.y(), 0.0, 0.0),
|
||||||
|
c2: F32x4::new(0.0, 0.0, scale.z(), 0.0),
|
||||||
|
c3: F32x4::new(0.0, 0.0, 0.0, 1.0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_uniform_scale(factor: f32) -> Transform3DF {
|
pub fn from_uniform_scale(factor: f32) -> Transform4F {
|
||||||
Transform3DF::from_scale(factor, factor, factor)
|
Transform4F::from_scale(Vector4F::splat(factor))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_translation(x: f32, y: f32, z: f32) -> Transform3DF {
|
pub fn from_translation(mut translation: Vector4F) -> Transform4F {
|
||||||
Transform3DF::row_major(
|
translation.set_w(1.0);
|
||||||
1.0, 0.0, 0.0, x, 0.0, 1.0, 0.0, y, 0.0, 0.0, 1.0, z, 0.0, 0.0, 0.0, 1.0,
|
Transform4F { c3: translation.0, ..Transform4F::default() }
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Optimize.
|
// TODO(pcwalton): Optimize.
|
||||||
pub fn from_rotation(yaw: f32, pitch: f32, roll: f32) -> Transform3DF {
|
pub fn from_rotation(yaw: f32, pitch: f32, roll: f32) -> Transform4F {
|
||||||
let (cos_b, sin_b) = (yaw.cos(), yaw.sin());
|
let (cos_b, sin_b) = (yaw.cos(), yaw.sin());
|
||||||
let (cos_c, sin_c) = (pitch.cos(), pitch.sin());
|
let (cos_c, sin_c) = (pitch.cos(), pitch.sin());
|
||||||
let (cos_a, sin_a) = (roll.cos(), roll.sin());
|
let (cos_a, sin_a) = (roll.cos(), roll.sin());
|
||||||
|
@ -101,7 +103,7 @@ impl Transform3DF {
|
||||||
let m20 = -sin_b;
|
let m20 = -sin_b;
|
||||||
let m21 = cos_b * sin_c;
|
let m21 = cos_b * sin_c;
|
||||||
let m22 = cos_b * cos_c;
|
let m22 = cos_b * cos_c;
|
||||||
Transform3DF::row_major(
|
Transform4F::row_major(
|
||||||
m00, m01, m02, 0.0, m10, m11, m12, 0.0, m20, m21, m22, 0.0, 0.0, 0.0, 0.0, 1.0,
|
m00, m01, m02, 0.0, m10, m11, m12, 0.0, m20, m21, m22, 0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -110,7 +112,7 @@ impl Transform3DF {
|
||||||
///
|
///
|
||||||
/// The quaternion is expected to be packed into a SIMD type (x, y, z, w) corresponding to
|
/// The quaternion is expected to be packed into a SIMD type (x, y, z, w) corresponding to
|
||||||
/// x + yi + zj + wk.
|
/// x + yi + zj + wk.
|
||||||
pub fn from_rotation_quaternion(q: F32x4) -> Transform3DF {
|
pub fn from_rotation_quaternion(q: F32x4) -> Transform4F {
|
||||||
// TODO(pcwalton): Optimize better with more shuffles.
|
// TODO(pcwalton): Optimize better with more shuffles.
|
||||||
let (mut sq, mut w, mut xy_xz_yz) = (q * q, q.wwww() * q, q.xxyy() * q.yzzy());
|
let (mut sq, mut w, mut xy_xz_yz) = (q * q, q.wwww() * q, q.xxyy() * q.yzzy());
|
||||||
sq += sq;
|
sq += sq;
|
||||||
|
@ -119,7 +121,7 @@ impl Transform3DF {
|
||||||
let diag = F32x4::splat(1.0) - (sq.yxxy() + sq.zzyy());
|
let diag = F32x4::splat(1.0) - (sq.yxxy() + sq.zzyy());
|
||||||
let (wx2, wy2, wz2) = (w.x(), w.y(), w.z());
|
let (wx2, wy2, wz2) = (w.x(), w.y(), w.z());
|
||||||
let (xy2, xz2, yz2) = (xy_xz_yz.x(), xy_xz_yz.y(), xy_xz_yz.z());
|
let (xy2, xz2, yz2) = (xy_xz_yz.x(), xy_xz_yz.y(), xy_xz_yz.z());
|
||||||
Transform3DF::row_major(
|
Transform4F::row_major(
|
||||||
diag.x(),
|
diag.x(),
|
||||||
xy2 - wz2,
|
xy2 - wz2,
|
||||||
xz2 + wy2,
|
xz2 + wy2,
|
||||||
|
@ -148,14 +150,14 @@ impl Transform3DF {
|
||||||
top: f32,
|
top: f32,
|
||||||
near_val: f32,
|
near_val: f32,
|
||||||
far_val: f32,
|
far_val: f32,
|
||||||
) -> Transform3DF {
|
) -> Transform4F {
|
||||||
let x_inv = 1.0 / (right - left);
|
let x_inv = 1.0 / (right - left);
|
||||||
let y_inv = 1.0 / (top - bottom);
|
let y_inv = 1.0 / (top - bottom);
|
||||||
let z_inv = 1.0 / (far_val - near_val);
|
let z_inv = 1.0 / (far_val - near_val);
|
||||||
let tx = -(right + left) * x_inv;
|
let tx = -(right + left) * x_inv;
|
||||||
let ty = -(top + bottom) * y_inv;
|
let ty = -(top + bottom) * y_inv;
|
||||||
let tz = -(far_val + near_val) * z_inv;
|
let tz = -(far_val + near_val) * z_inv;
|
||||||
Transform3DF::row_major(
|
Transform4F::row_major(
|
||||||
2.0 * x_inv,
|
2.0 * x_inv,
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -176,17 +178,17 @@ impl Transform3DF {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Linearly interpolate between transforms
|
/// Linearly interpolate between transforms
|
||||||
pub fn lerp(&self, weight: f32, other: &Transform3DF) -> Transform3DF {
|
pub fn lerp(&self, weight: f32, other: &Transform4F) -> Transform4F {
|
||||||
let c0 = self.c0 * F32x4::splat(weight) + other.c0 * F32x4::splat(1.0 - weight);
|
let c0 = self.c0 * F32x4::splat(weight) + other.c0 * F32x4::splat(1.0 - weight);
|
||||||
let c1 = self.c1 * F32x4::splat(weight) + other.c1 * F32x4::splat(1.0 - weight);
|
let c1 = self.c1 * F32x4::splat(weight) + other.c1 * F32x4::splat(1.0 - weight);
|
||||||
let c2 = self.c2 * F32x4::splat(weight) + other.c2 * F32x4::splat(1.0 - weight);
|
let c2 = self.c2 * F32x4::splat(weight) + other.c2 * F32x4::splat(1.0 - weight);
|
||||||
let c3 = self.c3 * F32x4::splat(weight) + other.c3 * F32x4::splat(1.0 - weight);
|
let c3 = self.c3 * F32x4::splat(weight) + other.c3 * F32x4::splat(1.0 - weight);
|
||||||
Transform3DF { c0, c1, c2, c3 }
|
Transform4F { c0, c1, c2, c3 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Just like `gluPerspective()`.
|
/// Just like `gluPerspective()`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_perspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) -> Transform3DF {
|
pub fn from_perspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) -> Transform4F {
|
||||||
let f = 1.0 / (fov_y * 0.5).tan();
|
let f = 1.0 / (fov_y * 0.5).tan();
|
||||||
let z_denom = 1.0 / (z_near - z_far);
|
let z_denom = 1.0 / (z_near - z_far);
|
||||||
let m00 = f / aspect;
|
let m00 = f / aspect;
|
||||||
|
@ -194,7 +196,7 @@ impl Transform3DF {
|
||||||
let m22 = (z_far + z_near) * z_denom;
|
let m22 = (z_far + z_near) * z_denom;
|
||||||
let m23 = 2.0 * z_far * z_near * z_denom;
|
let m23 = 2.0 * z_far * z_near * z_denom;
|
||||||
let m32 = -1.0;
|
let m32 = -1.0;
|
||||||
Transform3DF::row_major(
|
Transform4F::row_major(
|
||||||
m00, 0.0, 0.0, 0.0, 0.0, m11, 0.0, 0.0, 0.0, 0.0, m22, m23, 0.0, 0.0, m32, 0.0,
|
m00, 0.0, 0.0, 0.0, 0.0, m11, 0.0, 0.0, 0.0, 0.0, m22, m23, 0.0, 0.0, m32, 0.0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -209,8 +211,8 @@ impl Transform3DF {
|
||||||
b: Matrix2x2F,
|
b: Matrix2x2F,
|
||||||
c: Matrix2x2F,
|
c: Matrix2x2F,
|
||||||
d: Matrix2x2F,
|
d: Matrix2x2F,
|
||||||
) -> Transform3DF {
|
) -> Transform4F {
|
||||||
Transform3DF {
|
Transform4F {
|
||||||
c0: a.0.concat_xy_xy(c.0),
|
c0: a.0.concat_xy_xy(c.0),
|
||||||
c1: a.0.concat_zw_zw(c.0),
|
c1: a.0.concat_zw_zw(c.0),
|
||||||
c2: b.0.concat_xy_xy(d.0),
|
c2: b.0.concat_xy_xy(d.0),
|
||||||
|
@ -218,38 +220,24 @@ impl Transform3DF {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): Is this right, due to transposition? I think we may have to reverse the
|
|
||||||
// two.
|
|
||||||
//
|
|
||||||
// https://stackoverflow.com/a/18508113
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pre_mul(&self, other: &Transform3DF) -> Transform3DF {
|
pub fn rotate(&self, yaw: f32, pitch: f32, roll: f32) -> Transform4F {
|
||||||
return Transform3DF {
|
Transform4F::from_rotation(yaw, pitch, roll) * *self
|
||||||
c0: mul_col(self.c0, other),
|
|
||||||
c1: mul_col(self.c1, other),
|
|
||||||
c2: mul_col(self.c2, other),
|
|
||||||
c3: mul_col(self.c3, other),
|
|
||||||
};
|
|
||||||
|
|
||||||
fn mul_col(a_col: F32x4, b: &Transform3DF) -> F32x4 {
|
|
||||||
let (a0, a1) = (F32x4::splat(a_col[0]), F32x4::splat(a_col[1]));
|
|
||||||
let (a2, a3) = (F32x4::splat(a_col[2]), F32x4::splat(a_col[3]));
|
|
||||||
a0 * b.c0 + a1 * b.c1 + a2 * b.c2 + a3 * b.c3
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn post_mul(&self, other: &Transform3DF) -> Transform3DF {
|
pub fn scale(&self, scale: Vector4F) -> Transform4F {
|
||||||
other.pre_mul(self)
|
Transform4F::from_scale(scale) * *self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_point(&self, point: Vector4F) -> Vector4F {
|
pub fn uniform_scale(&self, scale: f32) -> Transform4F {
|
||||||
let term0 = self.c0 * F32x4::splat(point.x());
|
Transform4F::from_uniform_scale(scale) * *self
|
||||||
let term1 = self.c1 * F32x4::splat(point.y());
|
}
|
||||||
let term2 = self.c2 * F32x4::splat(point.z());
|
|
||||||
let term3 = self.c3 * F32x4::splat(point.w());
|
#[inline]
|
||||||
Vector4F(term0 + term1 + term2 + term3)
|
pub fn translate(&self, translation: Vector4F) -> Transform4F {
|
||||||
|
Transform4F::from_translation(translation) * *self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -276,26 +264,26 @@ impl Transform3DF {
|
||||||
//
|
//
|
||||||
// If A is the upper left submatrix of this matrix, this method assumes that A and the Schur
|
// If A is the upper left submatrix of this matrix, this method assumes that A and the Schur
|
||||||
// complement of A are invertible.
|
// complement of A are invertible.
|
||||||
pub fn inverse(&self) -> Transform3DF {
|
pub fn inverse(&self) -> Transform4F {
|
||||||
// Extract submatrices.
|
// Extract submatrices.
|
||||||
let (a, b) = (self.upper_left(), self.upper_right());
|
let (a, b) = (self.upper_left(), self.upper_right());
|
||||||
let (c, d) = (self.lower_left(), self.lower_right());
|
let (c, d) = (self.lower_left(), self.lower_right());
|
||||||
|
|
||||||
// Compute temporary matrices.
|
// Compute temporary matrices.
|
||||||
let a_inv = a.inverse();
|
let a_inv = a.inverse();
|
||||||
let x = c.post_mul(&a_inv);
|
let x = c * a_inv;
|
||||||
let y = (d - x.post_mul(&b)).inverse();
|
let y = (d - x * b).inverse();
|
||||||
let z = a_inv.post_mul(&b);
|
let z = a_inv * b;
|
||||||
|
|
||||||
// Compute new submatrices.
|
// Compute new submatrices.
|
||||||
let (a_new, b_new) = (a_inv + z.post_mul(&y).post_mul(&x), (-z).post_mul(&y));
|
let (a_new, b_new) = (a_inv + z * y * x, -z * y);
|
||||||
let (c_new, d_new) = ((-y).post_mul(&x), y);
|
let (c_new, d_new) = (-y * x, y);
|
||||||
|
|
||||||
// Construct inverse.
|
// Construct inverse.
|
||||||
Transform3DF::from_submatrices(a_new, b_new, c_new, d_new)
|
Transform4F::from_submatrices(a_new, b_new, c_new, d_new)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn approx_eq(&self, other: &Transform3DF, epsilon: f32) -> bool {
|
pub fn approx_eq(&self, other: &Transform4F, epsilon: f32) -> bool {
|
||||||
self.c0.approx_eq(other.c0, epsilon)
|
self.c0.approx_eq(other.c0, epsilon)
|
||||||
&& self.c1.approx_eq(other.c1, epsilon)
|
&& self.c1.approx_eq(other.c1, epsilon)
|
||||||
&& self.c2.approx_eq(other.c2, epsilon)
|
&& self.c2.approx_eq(other.c2, epsilon)
|
||||||
|
@ -306,6 +294,50 @@ impl Transform3DF {
|
||||||
pub fn as_ptr(&self) -> *const f32 {
|
pub fn as_ptr(&self) -> *const f32 {
|
||||||
(&self.c0) as *const F32x4 as *const f32
|
(&self.c0) as *const F32x4 as *const f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_columns(&self) -> [F32x4; 4] {
|
||||||
|
[self.c0, self.c1, self.c2, self.c3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Transform4F> for Transform4F {
|
||||||
|
type Output = Transform4F;
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/18508113
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: Transform4F) -> Transform4F {
|
||||||
|
return Transform4F {
|
||||||
|
c0: mul_col(&self, other.c0),
|
||||||
|
c1: mul_col(&self, other.c1),
|
||||||
|
c2: mul_col(&self, other.c2),
|
||||||
|
c3: mul_col(&self, other.c3),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul_col(a: &Transform4F, b_col: F32x4) -> F32x4 {
|
||||||
|
a.c0 * b_col.xxxx() + a.c1 * b_col.yyyy() + a.c2 * b_col.zzzz() + a.c3 * b_col.wwww()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Vector4F> for Transform4F {
|
||||||
|
type Output = Vector4F;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, vector: Vector4F) -> Vector4F {
|
||||||
|
let term0 = self.c0 * F32x4::splat(vector.x());
|
||||||
|
let term1 = self.c1 * F32x4::splat(vector.y());
|
||||||
|
let term2 = self.c2 * F32x4::splat(vector.z());
|
||||||
|
let term3 = self.c3 * F32x4::splat(vector.w());
|
||||||
|
Vector4F(term0 + term1 + term2 + term3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign<Transform4F> for Transform4F {
|
||||||
|
fn mul_assign(&mut self, other: Transform4F) {
|
||||||
|
*self = *self * other
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add<Matrix2x2F> for Matrix2x2F {
|
impl Add<Matrix2x2F> for Matrix2x2F {
|
||||||
|
@ -326,108 +358,110 @@ impl Neg for Matrix2x2F {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Perspective {
|
pub struct Perspective {
|
||||||
pub transform: Transform3DF,
|
pub transform: Transform4F,
|
||||||
pub window_size: Vector2I,
|
pub window_size: Vector2I,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Perspective {
|
impl Perspective {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(transform: &Transform3DF, window_size: Vector2I) -> Perspective {
|
pub fn new(transform: &Transform4F, window_size: Vector2I) -> Perspective {
|
||||||
Perspective {
|
Perspective {
|
||||||
transform: *transform,
|
transform: *transform,
|
||||||
window_size,
|
window_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn transform_point_2d(&self, point: &Vector2F) -> Vector2F {
|
|
||||||
let point = self
|
|
||||||
.transform
|
|
||||||
.transform_point(point.to_3d())
|
|
||||||
.perspective_divide()
|
|
||||||
.to_2d()
|
|
||||||
* Vector2F::new(1.0, -1.0);
|
|
||||||
(point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): SIMD?
|
impl Mul<Transform4F> for Perspective {
|
||||||
|
type Output = Perspective;
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_rect(&self, rect: RectF) -> RectF {
|
fn mul(self, other: Transform4F) -> Perspective {
|
||||||
let upper_left = self.transform_point_2d(&rect.origin());
|
Perspective {
|
||||||
let upper_right = self.transform_point_2d(&rect.upper_right());
|
transform: self.transform * other,
|
||||||
let lower_left = self.transform_point_2d(&rect.lower_left());
|
window_size: self.window_size,
|
||||||
let lower_right = self.transform_point_2d(&rect.lower_right());
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Vector2F> for Perspective {
|
||||||
|
type Output = Vector2F;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, vector: Vector2F) -> Vector2F {
|
||||||
|
let point = (self.transform * vector.to_3d()).perspective_divide().to_2d() *
|
||||||
|
Vector2F::new(1.0, -1.0);
|
||||||
|
(point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<RectF> for Perspective {
|
||||||
|
type Output = RectF;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rect: RectF) -> RectF {
|
||||||
|
let (upper_left, upper_right) = (self * rect.origin(), self * rect.upper_right());
|
||||||
|
let (lower_left, lower_right) = (self * rect.lower_left(), self * rect.lower_right());
|
||||||
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
|
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
|
||||||
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
|
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
|
||||||
RectF::from_points(min_point, max_point)
|
RectF::from_points(min_point, max_point)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn post_mul(&self, other: &Transform3DF) -> Perspective {
|
|
||||||
Perspective {
|
|
||||||
transform: self.transform.post_mul(other),
|
|
||||||
window_size: self.window_size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::vector::Vector4F;
|
use crate::vector::Vector4F;
|
||||||
use crate::transform3d::Transform3DF;
|
use crate::transform3d::Transform4F;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_post_mul() {
|
fn test_post_mul() {
|
||||||
let a = Transform3DF::row_major(
|
let a = Transform4F::row_major(
|
||||||
3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
|
3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
|
||||||
);
|
);
|
||||||
let b = Transform3DF::row_major(
|
let b = Transform4F::row_major(
|
||||||
3.0, 8.0, 4.0, 6.0, 2.0, 6.0, 4.0, 3.0, 3.0, 8.0, 3.0, 2.0, 7.0, 9.0, 5.0, 0.0,
|
3.0, 8.0, 4.0, 6.0, 2.0, 6.0, 4.0, 3.0, 3.0, 8.0, 3.0, 2.0, 7.0, 9.0, 5.0, 0.0,
|
||||||
);
|
);
|
||||||
let c = Transform3DF::row_major(
|
let c = Transform4F::row_major(
|
||||||
58.0, 107.0, 53.0, 29.0, 84.0, 177.0, 87.0, 72.0, 106.0, 199.0, 101.0, 49.0, 62.0,
|
58.0, 107.0, 53.0, 29.0, 84.0, 177.0, 87.0, 72.0, 106.0, 199.0, 101.0, 49.0, 62.0,
|
||||||
152.0, 83.0, 75.0,
|
152.0, 83.0, 75.0,
|
||||||
);
|
);
|
||||||
assert_eq!(a.post_mul(&b), c);
|
assert_eq!(a * b, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pre_mul() {
|
fn test_pre_mul() {
|
||||||
let a = Transform3DF::row_major(
|
let a = Transform4F::row_major(
|
||||||
3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
|
3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
|
||||||
);
|
);
|
||||||
let b = Transform3DF::row_major(
|
let b = Transform4F::row_major(
|
||||||
3.0, 8.0, 4.0, 6.0, 2.0, 6.0, 4.0, 3.0, 3.0, 8.0, 3.0, 2.0, 7.0, 9.0, 5.0, 0.0,
|
3.0, 8.0, 4.0, 6.0, 2.0, 6.0, 4.0, 3.0, 3.0, 8.0, 3.0, 2.0, 7.0, 9.0, 5.0, 0.0,
|
||||||
);
|
);
|
||||||
let c = Transform3DF::row_major(
|
let c = Transform4F::row_major(
|
||||||
135.0, 93.0, 110.0, 103.0, 93.0, 61.0, 85.0, 82.0, 104.0, 52.0, 90.0, 86.0, 117.0,
|
135.0, 93.0, 110.0, 103.0, 93.0, 61.0, 85.0, 82.0, 104.0, 52.0, 90.0, 86.0, 117.0,
|
||||||
50.0, 122.0, 125.0,
|
50.0, 122.0, 125.0,
|
||||||
);
|
);
|
||||||
assert_eq!(a.pre_mul(&b), c);
|
assert_eq!(b * a, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transform_point() {
|
fn test_transform_point() {
|
||||||
let a = Transform3DF::row_major(
|
let a = Transform4F::row_major(
|
||||||
3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
|
3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
|
||||||
);
|
);
|
||||||
let p = Vector4F::new(3.0, 8.0, 4.0, 6.0);
|
let p = Vector4F::new(3.0, 8.0, 4.0, 6.0);
|
||||||
let q = Vector4F::new(63.0, 97.0, 135.0, 117.0);
|
let q = Vector4F::new(63.0, 97.0, 135.0, 117.0);
|
||||||
assert_eq!(a.transform_point(p), q);
|
assert_eq!(a * p, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_inverse() {
|
fn test_inverse() {
|
||||||
// Random matrix.
|
// Random matrix.
|
||||||
let m = Transform3DF::row_major(
|
let m = Transform4F::row_major(
|
||||||
0.86277982, 0.15986552, 0.90739898, 0.60066808, 0.17386167, 0.016353, 0.8535783,
|
0.86277982, 0.15986552, 0.90739898, 0.60066808, 0.17386167, 0.016353, 0.8535783,
|
||||||
0.12969608, 0.0946466, 0.43248631, 0.63480505, 0.08154603, 0.50305436, 0.48359687,
|
0.12969608, 0.0946466, 0.43248631, 0.63480505, 0.08154603, 0.50305436, 0.48359687,
|
||||||
0.51057162, 0.24812012,
|
0.51057162, 0.24812012,
|
||||||
);
|
);
|
||||||
let p0 = Vector4F::new(0.95536648, 0.80633691, 0.16357357, 0.5477598);
|
let p0 = Vector4F::new(0.95536648, 0.80633691, 0.16357357, 0.5477598);
|
||||||
let p1 = m.transform_point(p0);
|
let p1 = m * p0;
|
||||||
let m_inv = m.inverse();
|
let m_inv = m.inverse();
|
||||||
let m_inv_exp = Transform3DF::row_major(
|
let m_inv_exp = Transform4F::row_major(
|
||||||
-2.47290136,
|
-2.47290136,
|
||||||
3.48865688,
|
3.48865688,
|
||||||
-6.12298336,
|
-6.12298336,
|
||||||
|
@ -446,7 +480,7 @@ mod test {
|
||||||
-9.10374060,
|
-9.10374060,
|
||||||
);
|
);
|
||||||
assert!(m_inv.approx_eq(&m_inv_exp, 0.0001));
|
assert!(m_inv.approx_eq(&m_inv_exp, 0.0001));
|
||||||
let p2 = m_inv.transform_point(p1);
|
let p2 = m_inv * p1;
|
||||||
assert!(p0.approx_eq(&p2, 0.0001));
|
assert!(p0.approx_eq(p2, 0.0001));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
//! A utility module that allows unit vectors to be treated like angles.
|
//! A utility module that allows unit vectors to be treated like angles.
|
||||||
|
|
||||||
use crate::vector::Vector2F;
|
use crate::vector::Vector2F;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x2;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct UnitVector(pub Vector2F);
|
pub struct UnitVector(pub Vector2F);
|
||||||
|
@ -25,14 +25,14 @@ impl UnitVector {
|
||||||
/// Angle addition formula.
|
/// Angle addition formula.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rotate_by(&self, other: UnitVector) -> UnitVector {
|
pub fn rotate_by(&self, other: UnitVector) -> UnitVector {
|
||||||
let products = (self.0).0.xyyx() * (other.0).0.xyxy();
|
let products = (self.0).0.to_f32x4().xyyx() * (other.0).0.to_f32x4().xyxy();
|
||||||
UnitVector(Vector2F::new(products[0] - products[1], products[2] + products[3]))
|
UnitVector(Vector2F::new(products[0] - products[1], products[2] + products[3]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Angle subtraction formula.
|
/// Angle subtraction formula.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rev_rotate_by(&self, other: UnitVector) -> UnitVector {
|
pub fn rev_rotate_by(&self, other: UnitVector) -> UnitVector {
|
||||||
let products = (self.0).0.xyyx() * (other.0).0.xyxy();
|
let products = (self.0).0.to_f32x4().xyyx() * (other.0).0.to_f32x4().xyxy();
|
||||||
UnitVector(Vector2F::new(products[0] + products[1], products[2] - products[3]))
|
UnitVector(Vector2F::new(products[0] + products[1], products[2] - products[3]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ impl UnitVector {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn halve_angle(&self) -> UnitVector {
|
pub fn halve_angle(&self) -> UnitVector {
|
||||||
let x = self.0.x();
|
let x = self.0.x();
|
||||||
let term = F32x4::new(x, -x, 0.0, 0.0);
|
let term = F32x2::new(x, -x);
|
||||||
UnitVector(Vector2F((F32x4::splat(0.5) * (F32x4::splat(1.0) + term)).sqrt()))
|
UnitVector(Vector2F((F32x2::splat(0.5) * (F32x2::splat(1.0) + term)).sqrt()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,36 +10,36 @@
|
||||||
|
|
||||||
//! A SIMD-optimized point type.
|
//! A SIMD-optimized point type.
|
||||||
|
|
||||||
use pathfinder_simd::default::{F32x4, I32x4};
|
use pathfinder_simd::default::{F32x2, F32x4, I32x2};
|
||||||
use std::ops::{Add, AddAssign, Mul, Neg, 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)]
|
||||||
pub struct Vector2F(pub F32x4);
|
pub struct Vector2F(pub F32x2);
|
||||||
|
|
||||||
impl Vector2F {
|
impl Vector2F {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(x: f32, y: f32) -> Vector2F {
|
pub fn new(x: f32, y: f32) -> Vector2F {
|
||||||
Vector2F(F32x4::new(x, y, 0.0, 0.0))
|
Vector2F(F32x2::new(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn splat(value: f32) -> Vector2F {
|
pub fn splat(value: f32) -> Vector2F {
|
||||||
Vector2F(F32x4::splat(value))
|
Vector2F(F32x2::splat(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_3d(self) -> Vector4F {
|
pub fn to_3d(self) -> Vector4F {
|
||||||
Vector4F(self.0.concat_xy_xy(F32x4::new(0.0, 1.0, 0.0, 0.0)))
|
Vector4F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 1.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn x(&self) -> f32 {
|
pub fn x(self) -> f32 {
|
||||||
self.0[0]
|
self.0[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn y(&self) -> f32 {
|
pub fn y(self) -> f32 {
|
||||||
self.0[1]
|
self.0[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,97 +54,96 @@ impl Vector2F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min(&self, other: Vector2F) -> Vector2F {
|
pub fn min(self, other: Vector2F) -> Vector2F {
|
||||||
Vector2F(self.0.min(other.0))
|
Vector2F(self.0.min(other.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn max(&self, other: Vector2F) -> Vector2F {
|
pub fn max(self, other: Vector2F) -> Vector2F {
|
||||||
Vector2F(self.0.max(other.0))
|
Vector2F(self.0.max(other.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clamp(&self, min_val: Vector2F, max_val: Vector2F) -> Vector2F {
|
pub fn clamp(self, min_val: Vector2F, max_val: Vector2F) -> Vector2F {
|
||||||
self.max(min_val).min(max_val)
|
self.max(min_val).min(max_val)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn det(&self, other: Vector2F) -> f32 {
|
pub fn det(self, other: Vector2F) -> f32 {
|
||||||
self.x() * other.y() - self.y() * other.x()
|
self.x() * other.y() - self.y() * other.x()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dot(&self, other: Vector2F) -> f32 {
|
pub fn dot(self, other: Vector2F) -> f32 {
|
||||||
let xy = self.0 * other.0;
|
let xy = self.0 * other.0;
|
||||||
xy.x() + xy.y()
|
xy.x() + xy.y()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale(&self, x: f32) -> Vector2F {
|
pub fn scale(self, x: f32) -> Vector2F {
|
||||||
Vector2F(self.0 * F32x4::splat(x))
|
Vector2F(self.0 * F32x2::splat(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_xy(&self, factors: Vector2F) -> Vector2F {
|
pub fn scale_xy(self, factors: Vector2F) -> Vector2F {
|
||||||
Vector2F(self.0 * factors.0)
|
Vector2F(self.0 * factors.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn floor(&self) -> Vector2F {
|
pub fn floor(self) -> Vector2F {
|
||||||
Vector2F(self.0.floor())
|
Vector2F(self.0.floor())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ceil(&self) -> Vector2F {
|
pub fn ceil(self) -> Vector2F {
|
||||||
Vector2F(self.0.ceil())
|
Vector2F(self.0.ceil())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Treats this point as a vector and calculates its squared length.
|
/// Treats this point as a vector and calculates its squared length.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn square_length(&self) -> f32 {
|
pub fn square_length(self) -> f32 {
|
||||||
let squared = self.0 * self.0;
|
let squared = self.0 * self.0;
|
||||||
squared[0] + squared[1]
|
squared[0] + squared[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Treats this point as a vector and calculates its length.
|
/// Treats this point as a vector and calculates its length.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn length(&self) -> f32 {
|
pub fn length(self) -> f32 {
|
||||||
f32::sqrt(self.square_length())
|
f32::sqrt(self.square_length())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Treats this point as a vector and normalizes it.
|
/// Treats this point as a vector and normalizes it.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn normalize(&self) -> Vector2F {
|
pub fn normalize(self) -> Vector2F {
|
||||||
self.scale(1.0 / self.length())
|
self.scale(1.0 / self.length())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Swaps y and x.
|
/// Swaps y and x.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn yx(&self) -> Vector2F {
|
pub fn yx(self) -> Vector2F {
|
||||||
Vector2F(self.0.yxwz())
|
Vector2F(self.0.yx())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_zero(&self) -> bool {
|
pub fn is_zero(self) -> bool {
|
||||||
*self == Vector2F::default()
|
self == Vector2F::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn lerp(&self, other: Vector2F, t: f32) -> Vector2F {
|
pub fn lerp(self, other: Vector2F, t: f32) -> Vector2F {
|
||||||
*self + (other - *self).scale(t)
|
self + (other - self).scale(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_i32(&self) -> Vector2I {
|
pub fn to_i32(self) -> Vector2I {
|
||||||
Vector2I(self.0.to_i32x4())
|
Vector2I(self.0.to_i32x2())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Vector2F {
|
impl PartialEq for Vector2F {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Vector2F) -> bool {
|
fn eq(&self, other: &Vector2F) -> bool {
|
||||||
let results = self.0.packed_eq(other.0);
|
self.0.packed_eq(other.0).is_all_ones()
|
||||||
results[0] != 0 && results[1] != 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,26 +181,26 @@ impl Neg for Vector2F {
|
||||||
|
|
||||||
/// 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 Vector2I(pub I32x4);
|
pub struct Vector2I(pub I32x2);
|
||||||
|
|
||||||
impl Vector2I {
|
impl Vector2I {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(x: i32, y: i32) -> Vector2I {
|
pub fn new(x: i32, y: i32) -> Vector2I {
|
||||||
Vector2I(I32x4::new(x, y, 0, 0))
|
Vector2I(I32x2::new(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn splat(value: i32) -> Vector2I {
|
pub fn splat(value: i32) -> Vector2I {
|
||||||
Vector2I(I32x4::splat(value))
|
Vector2I(I32x2::splat(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn x(&self) -> i32 {
|
pub fn x(self) -> i32 {
|
||||||
self.0[0]
|
self.0[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn y(&self) -> i32 {
|
pub fn y(self) -> i32 {
|
||||||
self.0[1]
|
self.0[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,18 +215,18 @@ impl Vector2I {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale(&self, factor: i32) -> Vector2I {
|
pub fn scale(self, factor: i32) -> Vector2I {
|
||||||
Vector2I(self.0 * I32x4::splat(factor))
|
Vector2I(self.0 * I32x2::splat(factor))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_xy(&self, factors: Vector2I) -> Vector2I {
|
pub fn scale_xy(self, factors: Vector2I) -> Vector2I {
|
||||||
Vector2I(self.0 * factors.0)
|
Vector2I(self.0 * factors.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_f32(&self) -> Vector2F {
|
pub fn to_f32(self) -> Vector2F {
|
||||||
Vector2F(self.0.to_f32x4())
|
Vector2F(self.0.to_f32x2())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,8 +256,7 @@ impl Sub<Vector2I> for Vector2I {
|
||||||
impl PartialEq for Vector2I {
|
impl PartialEq for Vector2I {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Vector2I) -> bool {
|
fn eq(&self, other: &Vector2I) -> bool {
|
||||||
let results = self.0.packed_eq(other.0);
|
self.0.packed_eq(other.0).is_all_ones()
|
||||||
results[0] != 0 && results[1] != 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +277,7 @@ impl Vector4F {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_2d(self) -> Vector2F {
|
pub fn to_2d(self) -> Vector2F {
|
||||||
Vector2F(self.0)
|
Vector2F(self.0.xy())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -303,7 +301,7 @@ impl Vector4F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale(&self, x: f32) -> Vector4F {
|
pub fn scale(self, x: f32) -> Vector4F {
|
||||||
let mut factors = F32x4::splat(x);
|
let mut factors = F32x4::splat(x);
|
||||||
factors[3] = 1.0;
|
factors[3] = 1.0;
|
||||||
Vector4F(self.0 * factors)
|
Vector4F(self.0 * factors)
|
||||||
|
@ -335,7 +333,7 @@ impl Vector4F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn approx_eq(&self, other: &Vector4F, epsilon: f32) -> bool {
|
pub fn approx_eq(self, other: Vector4F, epsilon: f32) -> bool {
|
||||||
self.0.approx_eq(other.0, epsilon)
|
self.0.approx_eq(other.0, epsilon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +375,16 @@ impl Mul<Vector4F> for Vector4F {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Neg for Vector4F {
|
||||||
|
type Output = Vector4F;
|
||||||
|
/// NB: This does not negate w, because that is rarely what you what for homogeneous
|
||||||
|
/// coordinates.
|
||||||
|
#[inline]
|
||||||
|
fn neg(self) -> Vector4F {
|
||||||
|
Vector4F(self.0 * F32x4::new(-1.0, -1.0, -1.0, 1.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Vector4F {
|
impl Default for Vector4F {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Vector4F {
|
fn default() -> Vector4F {
|
||||||
|
|
|
@ -14,9 +14,9 @@ use crate::resources::ResourceLoader;
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
use pathfinder_content::color::ColorF;
|
use pathfinder_content::color::ColorF;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::Transform3DF;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::{F32x2, F32x4};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
|
@ -153,7 +153,7 @@ pub enum ShaderKind {
|
||||||
pub enum UniformData {
|
pub enum UniformData {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
Mat4([F32x4; 4]),
|
Mat4([F32x4; 4]),
|
||||||
Vec2(F32x4),
|
Vec2(F32x2),
|
||||||
Vec4(F32x4),
|
Vec4(F32x4),
|
||||||
TextureUnit(u32),
|
TextureUnit(u32),
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,7 @@ pub enum TextureData {
|
||||||
|
|
||||||
impl UniformData {
|
impl UniformData {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_transform_3d(transform: &Transform3DF) -> UniformData {
|
pub fn from_transform_3d(transform: &Transform4F) -> UniformData {
|
||||||
UniformData::Mat4([transform.c0, transform.c1, transform.c2, transform.c3])
|
UniformData::Mat4([transform.c0, transform.c1, transform.c2, transform.c3])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, Dep
|
||||||
use pathfinder_gpu::{Primitive, RenderState, RenderTarget, ShaderKind, StencilFunc, TextureData};
|
use pathfinder_gpu::{Primitive, RenderState, RenderTarget, ShaderKind, StencilFunc, TextureData};
|
||||||
use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass};
|
use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass};
|
||||||
use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType};
|
use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType};
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::{F32x2, F32x4};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -1146,7 +1146,7 @@ impl UniformDataExt for UniformData {
|
||||||
Some(slice::from_raw_parts(&data[0] as *const F32x4 as *const u8, 4 * 16))
|
Some(slice::from_raw_parts(&data[0] as *const F32x4 as *const u8, 4 * 16))
|
||||||
}
|
}
|
||||||
UniformData::Vec2(ref data) => {
|
UniformData::Vec2(ref data) => {
|
||||||
Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 2))
|
Some(slice::from_raw_parts(data as *const F32x2 as *const u8, 4 * 2))
|
||||||
}
|
}
|
||||||
UniformData::Vec4(ref data) => {
|
UniformData::Vec4(ref data) => {
|
||||||
Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4))
|
Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4))
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
use pathfinder_renderer::{scene::Scene};
|
|
||||||
use pathfinder_geometry::{vector::Vector2F, rect::RectF};
|
|
||||||
use pathfinder_content::{outline::Outline, segment::{Segment, SegmentKind}, color::ColorF};
|
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
mod pdf;
|
|
||||||
use pdf::Pdf;
|
|
||||||
|
|
||||||
pub struct PdfBuilder {
|
|
||||||
pdf: Pdf
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PdfBuilder {
|
|
||||||
pub fn new() -> PdfBuilder {
|
|
||||||
PdfBuilder {
|
|
||||||
pdf: Pdf::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_scene(&mut self, scene: &Scene) {
|
|
||||||
let view_box = scene.view_box();
|
|
||||||
self.pdf.add_page(view_box.size());
|
|
||||||
|
|
||||||
let height = view_box.size().y();
|
|
||||||
let tr = |v: Vector2F| -> Vector2F {
|
|
||||||
let r = v - view_box.origin();
|
|
||||||
Vector2F::new(r.x(), height - r.y())
|
|
||||||
};
|
|
||||||
|
|
||||||
for (paint, outline) in scene.paths() {
|
|
||||||
self.pdf.set_fill_color(paint.color);
|
|
||||||
|
|
||||||
for contour in outline.contours() {
|
|
||||||
for (segment_index, segment) in contour.iter().enumerate() {
|
|
||||||
if segment_index == 0 {
|
|
||||||
self.pdf.move_to(tr(segment.baseline.from()));
|
|
||||||
}
|
|
||||||
|
|
||||||
match segment.kind {
|
|
||||||
SegmentKind::None => {}
|
|
||||||
SegmentKind::Line => self.pdf.line_to(tr(segment.baseline.to())),
|
|
||||||
SegmentKind::Quadratic => {
|
|
||||||
let current = segment.baseline.from();
|
|
||||||
let c = segment.ctrl.from();
|
|
||||||
let p = segment.baseline.to();
|
|
||||||
let c1 = Vector2F::splat(2./3.) * c + Vector2F::splat(1./3.) * current;
|
|
||||||
let c2 = Vector2F::splat(2./3.) * c + Vector2F::splat(1./3.) * p;
|
|
||||||
self.pdf.cubic_to(c1, c2, p);
|
|
||||||
}
|
|
||||||
SegmentKind::Cubic => self.pdf.cubic_to(tr(segment.ctrl.from()), tr(segment.ctrl.to()), tr(segment.baseline.to()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if contour.is_closed() {
|
|
||||||
self.pdf.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// closes implicitly
|
|
||||||
self.pdf.fill();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write<W: Write>(mut self, out: W) {
|
|
||||||
self.pdf.write_to(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_pdf<W: Write>(mut writer: W, scene: &Scene) {
|
|
||||||
let mut pdf = PdfBuilder::new();
|
|
||||||
pdf.add_scene(scene);
|
|
||||||
pdf.write(writer);
|
|
||||||
}
|
|
|
@ -160,7 +160,7 @@ impl BuiltObject {
|
||||||
fn add_fill(
|
fn add_fill(
|
||||||
&mut self,
|
&mut self,
|
||||||
builder: &SceneBuilder,
|
builder: &SceneBuilder,
|
||||||
segment: &LineSegment2F,
|
segment: LineSegment2F,
|
||||||
tile_coords: Vector2I,
|
tile_coords: Vector2I,
|
||||||
) {
|
) {
|
||||||
debug!("add_fill({:?} ({:?}))", segment, tile_coords);
|
debug!("add_fill({:?} ({:?}))", segment, tile_coords);
|
||||||
|
@ -171,31 +171,19 @@ impl BuiltObject {
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_assert_eq!(TILE_WIDTH, TILE_HEIGHT);
|
debug_assert_eq!(TILE_WIDTH, TILE_HEIGHT);
|
||||||
|
|
||||||
|
// Compute the upper left corner of the tile.
|
||||||
let tile_size = F32x4::splat(TILE_WIDTH as f32);
|
let tile_size = F32x4::splat(TILE_WIDTH as f32);
|
||||||
let (min, max) = (
|
let tile_upper_left = tile_coords.to_f32().0.to_f32x4().xyxy() * tile_size;
|
||||||
F32x4::default(),
|
|
||||||
F32x4::splat((TILE_WIDTH * 256 - 1) as f32),
|
|
||||||
);
|
|
||||||
let shuffle_mask = I32x4::new(0x0c08_0400, 0x0d05_0901, 0, 0).as_u8x16();
|
|
||||||
|
|
||||||
let tile_upper_left = tile_coords.to_f32().0.xyxy() * tile_size;
|
|
||||||
|
|
||||||
|
// Convert to 4.8 fixed point.
|
||||||
let segment = (segment.0 - tile_upper_left) * F32x4::splat(256.0);
|
let segment = (segment.0 - tile_upper_left) * F32x4::splat(256.0);
|
||||||
let segment = segment
|
let (min, max) = (F32x4::default(), F32x4::splat((TILE_WIDTH * 256 - 1) as f32));
|
||||||
.clamp(min, max)
|
let segment = segment.clamp(min, max).to_i32x4();
|
||||||
.to_i32x4()
|
let (from_x, from_y, to_x, to_y) = (segment[0], segment[1], segment[2], segment[3]);
|
||||||
.as_u8x16()
|
|
||||||
.shuffle(shuffle_mask)
|
|
||||||
.as_i32x4();
|
|
||||||
|
|
||||||
// Unpack whole and fractional pixels.
|
|
||||||
let px = LineSegmentU4((segment[1] | (segment[1] >> 12)) as u16);
|
|
||||||
let subpx = LineSegmentU8(segment[0] as u32);
|
|
||||||
|
|
||||||
// Cull degenerate fills.
|
// Cull degenerate fills.
|
||||||
if (px.0 & 0xf) as u8 == ((px.0 >> 8) & 0xf) as u8
|
if from_x == to_x {
|
||||||
&& (subpx.0 & 0xff) as u8 == ((subpx.0 >> 16) & 0xff) as u8
|
|
||||||
{
|
|
||||||
debug!("... culling!");
|
debug!("... culling!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -203,10 +191,20 @@ impl BuiltObject {
|
||||||
// Allocate global tile if necessary.
|
// Allocate global tile if necessary.
|
||||||
let alpha_tile_index = self.get_or_allocate_alpha_tile_index(builder, tile_coords);
|
let alpha_tile_index = self.get_or_allocate_alpha_tile_index(builder, tile_coords);
|
||||||
|
|
||||||
|
// Pack whole pixels.
|
||||||
|
let mut px = (segment & I32x4::splat(0xf00)) >> I32x4::new(8, 4, 8, 4);
|
||||||
|
px = px | px.yxwz();
|
||||||
|
|
||||||
|
// Pack instance data.
|
||||||
debug!("... OK, pushing");
|
debug!("... OK, pushing");
|
||||||
self.fills.push(FillBatchPrimitive {
|
self.fills.push(FillBatchPrimitive {
|
||||||
px,
|
px: LineSegmentU4 { from: px[0] as u8, to: px[2] as u8 },
|
||||||
subpx,
|
subpx: LineSegmentU8 {
|
||||||
|
from_x: from_x as u8,
|
||||||
|
from_y: from_y as u8,
|
||||||
|
to_x: to_x as u8,
|
||||||
|
to_y: to_y as u8,
|
||||||
|
},
|
||||||
alpha_tile_index,
|
alpha_tile_index,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -256,7 +254,7 @@ impl BuiltObject {
|
||||||
);
|
);
|
||||||
|
|
||||||
while winding != 0 {
|
while winding != 0 {
|
||||||
self.add_fill(builder, &segment, tile_coords);
|
self.add_fill(builder, segment, tile_coords);
|
||||||
if winding < 0 {
|
if winding < 0 {
|
||||||
winding += 1
|
winding += 1
|
||||||
} else {
|
} else {
|
||||||
|
@ -315,7 +313,7 @@ impl BuiltObject {
|
||||||
|
|
||||||
let fill_segment = LineSegment2F::new(fill_from, fill_to);
|
let fill_segment = LineSegment2F::new(fill_from, fill_to);
|
||||||
let fill_tile_coords = Vector2I::new(subsegment_tile_x, tile_y);
|
let fill_tile_coords = Vector2I::new(subsegment_tile_x, tile_y);
|
||||||
self.add_fill(builder, &fill_segment, fill_tile_coords);
|
self.add_fill(builder, fill_segment, fill_tile_coords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,9 +90,10 @@ impl SceneProxy {
|
||||||
renderer.end_scene();
|
renderer.end_scene();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_svg(&self) -> Vec<u8> {
|
#[inline]
|
||||||
|
pub fn copy_scene(&self) -> Scene {
|
||||||
let (sender, receiver) = mpsc::channel();
|
let (sender, receiver) = mpsc::channel();
|
||||||
self.sender.send(MainToWorkerMsg::GetSVG(sender)).unwrap();
|
self.sender.send(MainToWorkerMsg::CopyScene(sender)).unwrap();
|
||||||
receiver.recv().unwrap()
|
receiver.recv().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,22 +105,18 @@ fn scene_thread<E>(mut scene: Scene,
|
||||||
while let Ok(msg) = main_to_worker_receiver.recv() {
|
while let Ok(msg) = main_to_worker_receiver.recv() {
|
||||||
match msg {
|
match msg {
|
||||||
MainToWorkerMsg::ReplaceScene(new_scene) => scene = new_scene,
|
MainToWorkerMsg::ReplaceScene(new_scene) => scene = new_scene,
|
||||||
|
MainToWorkerMsg::CopyScene(sender) => sender.send(scene.clone()).unwrap(),
|
||||||
MainToWorkerMsg::SetViewBox(new_view_box) => scene.set_view_box(new_view_box),
|
MainToWorkerMsg::SetViewBox(new_view_box) => scene.set_view_box(new_view_box),
|
||||||
MainToWorkerMsg::Build(options, listener) => scene.build(options, listener, &executor),
|
MainToWorkerMsg::Build(options, listener) => scene.build(options, listener, &executor)
|
||||||
MainToWorkerMsg::GetSVG(sender) => {
|
|
||||||
let mut bytes = vec![];
|
|
||||||
scene.write_svg(&mut bytes).unwrap();
|
|
||||||
sender.send(bytes).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MainToWorkerMsg {
|
enum MainToWorkerMsg {
|
||||||
ReplaceScene(Scene),
|
ReplaceScene(Scene),
|
||||||
|
CopyScene(Sender<Scene>),
|
||||||
SetViewBox(RectF),
|
SetViewBox(RectF),
|
||||||
Build(BuildOptions, Box<dyn RenderCommandListener>),
|
Build(BuildOptions, Box<dyn RenderCommandListener>),
|
||||||
GetSVG(Sender<Vec<u8>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenderCommandStream {
|
pub struct RenderCommandStream {
|
||||||
|
|
|
@ -16,14 +16,14 @@ use crate::post::DefringingKernel;
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::Transform3DF;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_content::color::ColorF;
|
use pathfinder_content::color::ColorF;
|
||||||
use pathfinder_gpu::resources::ResourceLoader;
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearOps};
|
use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearOps};
|
||||||
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderOptions, RenderState};
|
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderOptions, RenderState};
|
||||||
use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureFormat, UniformData};
|
use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureFormat, UniformData};
|
||||||
use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
||||||
use pathfinder_simd::default::{F32x4, I32x4};
|
use pathfinder_simd::default::{F32x2, F32x4};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -447,15 +447,10 @@ where
|
||||||
textures: &[&self.area_lut_texture],
|
textures: &[&self.area_lut_texture],
|
||||||
uniforms: &[
|
uniforms: &[
|
||||||
(&self.fill_program.framebuffer_size_uniform,
|
(&self.fill_program.framebuffer_size_uniform,
|
||||||
UniformData::Vec2(I32x4::new(MASK_FRAMEBUFFER_WIDTH,
|
UniformData::Vec2(F32x2::new(MASK_FRAMEBUFFER_WIDTH as f32,
|
||||||
MASK_FRAMEBUFFER_HEIGHT,
|
MASK_FRAMEBUFFER_HEIGHT as f32))),
|
||||||
0,
|
|
||||||
0).to_f32x4())),
|
|
||||||
(&self.fill_program.tile_size_uniform,
|
(&self.fill_program.tile_size_uniform,
|
||||||
UniformData::Vec2(I32x4::new(TILE_WIDTH as i32,
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
||||||
TILE_HEIGHT as i32,
|
|
||||||
0,
|
|
||||||
0).to_f32x4())),
|
|
||||||
(&self.fill_program.area_lut_uniform, UniformData::TextureUnit(0)),
|
(&self.fill_program.area_lut_uniform, UniformData::TextureUnit(0)),
|
||||||
],
|
],
|
||||||
viewport: self.mask_viewport(),
|
viewport: self.mask_viewport(),
|
||||||
|
@ -473,30 +468,28 @@ where
|
||||||
self.buffered_fills.clear();
|
self.buffered_fills.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tile_transform(&self) -> Transform4F {
|
||||||
|
let draw_viewport = self.draw_viewport().size().to_f32();
|
||||||
|
let scale = Vector4F::new(2.0 / draw_viewport.x(), -2.0 / draw_viewport.y(), 1.0, 1.0);
|
||||||
|
Transform4F::from_scale(scale).translate(Vector4F::new(-1.0, 1.0, 0.0, 1.0))
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_alpha_tiles(&mut self, count: u32) {
|
fn draw_alpha_tiles(&mut self, count: u32) {
|
||||||
let clear_color = self.clear_color_for_draw_operation();
|
let clear_color = self.clear_color_for_draw_operation();
|
||||||
|
|
||||||
let alpha_tile_vertex_array = self.alpha_tile_vertex_array();
|
let alpha_tile_vertex_array = self.alpha_tile_vertex_array();
|
||||||
let alpha_tile_program = self.alpha_tile_program();
|
let alpha_tile_program = self.alpha_tile_program();
|
||||||
|
|
||||||
let draw_viewport = self.draw_viewport();
|
|
||||||
let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)];
|
let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)];
|
||||||
let mut uniforms = vec![
|
let mut uniforms = vec![
|
||||||
(&alpha_tile_program.framebuffer_size_uniform,
|
(&alpha_tile_program.transform_uniform,
|
||||||
UniformData::Vec2(draw_viewport.size().to_f32().0)),
|
UniformData::Mat4(self.tile_transform().to_columns())),
|
||||||
(&alpha_tile_program.tile_size_uniform,
|
(&alpha_tile_program.tile_size_uniform,
|
||||||
UniformData::Vec2(I32x4::new(TILE_WIDTH as i32,
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
||||||
TILE_HEIGHT as i32,
|
|
||||||
0,
|
|
||||||
0).to_f32x4())),
|
|
||||||
(&alpha_tile_program.stencil_texture_uniform, UniformData::TextureUnit(0)),
|
(&alpha_tile_program.stencil_texture_uniform, UniformData::TextureUnit(0)),
|
||||||
(&alpha_tile_program.stencil_texture_size_uniform,
|
(&alpha_tile_program.stencil_texture_size_uniform,
|
||||||
UniformData::Vec2(I32x4::new(MASK_FRAMEBUFFER_WIDTH,
|
UniformData::Vec2(F32x2::new(MASK_FRAMEBUFFER_WIDTH as f32,
|
||||||
MASK_FRAMEBUFFER_HEIGHT,
|
MASK_FRAMEBUFFER_HEIGHT as f32))),
|
||||||
0,
|
|
||||||
0).to_f32x4())),
|
|
||||||
// FIXME(pcwalton): Fill this in properly!
|
|
||||||
(&alpha_tile_program.view_box_origin_uniform, UniformData::Vec2(F32x4::default())),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
match self.render_mode {
|
match self.render_mode {
|
||||||
|
@ -509,7 +502,7 @@ where
|
||||||
UniformData::Vec2(self.device
|
UniformData::Vec2(self.device
|
||||||
.texture_size(paint_texture)
|
.texture_size(paint_texture)
|
||||||
.0
|
.0
|
||||||
.to_f32x4())));
|
.to_f32x2())));
|
||||||
}
|
}
|
||||||
RenderMode::Monochrome { .. } if self.postprocessing_needed() => {
|
RenderMode::Monochrome { .. } if self.postprocessing_needed() => {
|
||||||
uniforms.push((&self.alpha_monochrome_tile_program.color_uniform,
|
uniforms.push((&self.alpha_monochrome_tile_program.color_uniform,
|
||||||
|
@ -528,7 +521,7 @@ where
|
||||||
primitive: Primitive::Triangles,
|
primitive: Primitive::Triangles,
|
||||||
textures: &textures,
|
textures: &textures,
|
||||||
uniforms: &uniforms,
|
uniforms: &uniforms,
|
||||||
viewport: draw_viewport,
|
viewport: self.draw_viewport(),
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha,
|
blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha,
|
||||||
stencil: self.stencil_state(),
|
stencil: self.stencil_state(),
|
||||||
|
@ -546,18 +539,12 @@ where
|
||||||
let solid_tile_vertex_array = self.solid_tile_vertex_array();
|
let solid_tile_vertex_array = self.solid_tile_vertex_array();
|
||||||
let solid_tile_program = self.solid_tile_program();
|
let solid_tile_program = self.solid_tile_program();
|
||||||
|
|
||||||
let draw_viewport = self.draw_viewport();
|
|
||||||
let mut textures = vec![];
|
let mut textures = vec![];
|
||||||
let mut uniforms = vec![
|
let mut uniforms = vec![
|
||||||
(&solid_tile_program.framebuffer_size_uniform,
|
(&solid_tile_program.transform_uniform,
|
||||||
UniformData::Vec2(draw_viewport.size().0.to_f32x4())),
|
UniformData::Mat4(self.tile_transform().to_columns())),
|
||||||
(&solid_tile_program.tile_size_uniform,
|
(&solid_tile_program.tile_size_uniform,
|
||||||
UniformData::Vec2(I32x4::new(TILE_WIDTH as i32,
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
||||||
TILE_HEIGHT as i32,
|
|
||||||
0,
|
|
||||||
0).to_f32x4())),
|
|
||||||
// FIXME(pcwalton): Fill this in properly!
|
|
||||||
(&solid_tile_program.view_box_origin_uniform, UniformData::Vec2(F32x4::default())),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
match self.render_mode {
|
match self.render_mode {
|
||||||
|
@ -570,7 +557,7 @@ where
|
||||||
UniformData::Vec2(self.device
|
UniformData::Vec2(self.device
|
||||||
.texture_size(paint_texture)
|
.texture_size(paint_texture)
|
||||||
.0
|
.0
|
||||||
.to_f32x4())));
|
.to_f32x2())));
|
||||||
}
|
}
|
||||||
RenderMode::Monochrome { .. } if self.postprocessing_needed() => {
|
RenderMode::Monochrome { .. } if self.postprocessing_needed() => {
|
||||||
uniforms.push((&self.solid_monochrome_tile_program.color_uniform,
|
uniforms.push((&self.solid_monochrome_tile_program.color_uniform,
|
||||||
|
@ -589,7 +576,7 @@ where
|
||||||
primitive: Primitive::Triangles,
|
primitive: Primitive::Triangles,
|
||||||
textures: &textures,
|
textures: &textures,
|
||||||
uniforms: &uniforms,
|
uniforms: &uniforms,
|
||||||
viewport: draw_viewport,
|
viewport: self.draw_viewport(),
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
stencil: self.stencil_state(),
|
stencil: self.stencil_state(),
|
||||||
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
||||||
|
@ -635,7 +622,7 @@ where
|
||||||
UniformData::Vec2(main_viewport.size().to_f32().0)),
|
UniformData::Vec2(main_viewport.size().to_f32().0)),
|
||||||
(&self.postprocess_program.source_uniform, UniformData::TextureUnit(0)),
|
(&self.postprocess_program.source_uniform, UniformData::TextureUnit(0)),
|
||||||
(&self.postprocess_program.source_size_uniform,
|
(&self.postprocess_program.source_size_uniform,
|
||||||
UniformData::Vec2(source_texture_size.0.to_f32x4())),
|
UniformData::Vec2(source_texture_size.0.to_f32x2())),
|
||||||
(&self.postprocess_program.gamma_lut_uniform, UniformData::TextureUnit(1)),
|
(&self.postprocess_program.gamma_lut_uniform, UniformData::TextureUnit(1)),
|
||||||
(&self.postprocess_program.fg_color_uniform, UniformData::Vec4(fg_color.0)),
|
(&self.postprocess_program.fg_color_uniform, UniformData::Vec4(fg_color.0)),
|
||||||
(&self.postprocess_program.bg_color_uniform, UniformData::Vec4(bg_color.0)),
|
(&self.postprocess_program.bg_color_uniform, UniformData::Vec4(bg_color.0)),
|
||||||
|
@ -747,8 +734,8 @@ where
|
||||||
pub fn reproject_texture(
|
pub fn reproject_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture: &D::Texture,
|
texture: &D::Texture,
|
||||||
old_transform: &Transform3DF,
|
old_transform: &Transform4F,
|
||||||
new_transform: &Transform3DF,
|
new_transform: &Transform4F,
|
||||||
) {
|
) {
|
||||||
let clear_color = self.clear_color_for_draw_operation();
|
let clear_color = self.clear_color_for_draw_operation();
|
||||||
|
|
||||||
|
@ -1217,9 +1204,8 @@ where
|
||||||
D: Device,
|
D: Device,
|
||||||
{
|
{
|
||||||
program: D::Program,
|
program: D::Program,
|
||||||
framebuffer_size_uniform: D::Uniform,
|
transform_uniform: D::Uniform,
|
||||||
tile_size_uniform: D::Uniform,
|
tile_size_uniform: D::Uniform,
|
||||||
view_box_origin_uniform: D::Uniform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> SolidTileProgram<D>
|
impl<D> SolidTileProgram<D>
|
||||||
|
@ -1233,15 +1219,9 @@ where
|
||||||
program_name,
|
program_name,
|
||||||
"tile_solid",
|
"tile_solid",
|
||||||
);
|
);
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
let view_box_origin_uniform = device.get_uniform(&program, "ViewBoxOrigin");
|
SolidTileProgram { program, transform_uniform, tile_size_uniform }
|
||||||
SolidTileProgram {
|
|
||||||
program,
|
|
||||||
framebuffer_size_uniform,
|
|
||||||
tile_size_uniform,
|
|
||||||
view_box_origin_uniform,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1299,11 +1279,10 @@ where
|
||||||
D: Device,
|
D: Device,
|
||||||
{
|
{
|
||||||
program: D::Program,
|
program: D::Program,
|
||||||
framebuffer_size_uniform: D::Uniform,
|
transform_uniform: D::Uniform,
|
||||||
tile_size_uniform: D::Uniform,
|
tile_size_uniform: D::Uniform,
|
||||||
stencil_texture_uniform: D::Uniform,
|
stencil_texture_uniform: D::Uniform,
|
||||||
stencil_texture_size_uniform: D::Uniform,
|
stencil_texture_size_uniform: D::Uniform,
|
||||||
view_box_origin_uniform: D::Uniform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> AlphaTileProgram<D>
|
impl<D> AlphaTileProgram<D>
|
||||||
|
@ -1317,18 +1296,16 @@ where
|
||||||
program_name,
|
program_name,
|
||||||
"tile_alpha",
|
"tile_alpha",
|
||||||
);
|
);
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
let stencil_texture_uniform = device.get_uniform(&program, "StencilTexture");
|
let stencil_texture_uniform = device.get_uniform(&program, "StencilTexture");
|
||||||
let stencil_texture_size_uniform = device.get_uniform(&program, "StencilTextureSize");
|
let stencil_texture_size_uniform = device.get_uniform(&program, "StencilTextureSize");
|
||||||
let view_box_origin_uniform = device.get_uniform(&program, "ViewBoxOrigin");
|
|
||||||
AlphaTileProgram {
|
AlphaTileProgram {
|
||||||
program,
|
program,
|
||||||
framebuffer_size_uniform,
|
transform_uniform,
|
||||||
tile_size_uniform,
|
tile_size_uniform,
|
||||||
stencil_texture_uniform,
|
stencil_texture_uniform,
|
||||||
stencil_texture_size_uniform,
|
stencil_texture_size_uniform,
|
||||||
view_box_origin_uniform,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use crate::gpu_data::RenderCommand;
|
use crate::gpu_data::RenderCommand;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector4F};
|
use pathfinder_geometry::vector::{Vector2F, Vector4F};
|
||||||
use pathfinder_content::clip::PolygonClipper3D;
|
use pathfinder_content::clip::PolygonClipper3D;
|
||||||
|
@ -51,14 +51,14 @@ impl BuildOptions {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum RenderTransform {
|
pub enum RenderTransform {
|
||||||
Transform2D(Transform2DF),
|
Transform2D(Transform2F),
|
||||||
Perspective(Perspective),
|
Perspective(Perspective),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RenderTransform {
|
impl Default for RenderTransform {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> RenderTransform {
|
fn default() -> RenderTransform {
|
||||||
RenderTransform::Transform2D(Transform2DF::default())
|
RenderTransform::Transform2D(Transform2F::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ impl RenderTransform {
|
||||||
debug!("-----");
|
debug!("-----");
|
||||||
debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
|
debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
|
||||||
for point in &mut points {
|
for point in &mut points {
|
||||||
*point = perspective.transform.transform_point(*point);
|
*point = perspective.transform * *point;
|
||||||
}
|
}
|
||||||
debug!("... PERSPECTIVE quad={:?}", points);
|
debug!("... PERSPECTIVE quad={:?}", points);
|
||||||
|
|
||||||
|
@ -105,12 +105,7 @@ impl RenderTransform {
|
||||||
let inverse_transform = perspective.transform.inverse();
|
let inverse_transform = perspective.transform.inverse();
|
||||||
let clip_polygon = points
|
let clip_polygon = points
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|point| {
|
.map(|point| (inverse_transform * point).perspective_divide().to_2d())
|
||||||
inverse_transform
|
|
||||||
.transform_point(point)
|
|
||||||
.perspective_divide()
|
|
||||||
.to_2d()
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
return PreparedRenderTransform::Perspective {
|
return PreparedRenderTransform::Perspective {
|
||||||
perspective,
|
perspective,
|
||||||
|
@ -140,7 +135,7 @@ pub(crate) type BoundingQuad = [Vector4F; 4];
|
||||||
|
|
||||||
pub(crate) enum PreparedRenderTransform {
|
pub(crate) enum PreparedRenderTransform {
|
||||||
None,
|
None,
|
||||||
Transform2D(Transform2DF),
|
Transform2D(Transform2F),
|
||||||
Perspective {
|
Perspective {
|
||||||
perspective: Perspective,
|
perspective: Perspective,
|
||||||
clip_polygon: Vec<Vector2F>,
|
clip_polygon: Vec<Vector2F>,
|
||||||
|
|
|
@ -18,10 +18,9 @@ use crate::paint::{Paint, PaintId};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_content::color::ColorU;
|
use pathfinder_content::color::ColorU;
|
||||||
use pathfinder_content::outline::Outline;
|
use pathfinder_content::outline::Outline;
|
||||||
use std::io::{self, Write};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
|
@ -116,12 +115,11 @@ impl Scene {
|
||||||
if options.transform.is_2d() || options.subpixel_aa_enabled {
|
if options.transform.is_2d() || options.subpixel_aa_enabled {
|
||||||
let mut transform = match options.transform {
|
let mut transform = match options.transform {
|
||||||
PreparedRenderTransform::Transform2D(transform) => transform,
|
PreparedRenderTransform::Transform2D(transform) => transform,
|
||||||
PreparedRenderTransform::None => Transform2DF::default(),
|
PreparedRenderTransform::None => Transform2F::default(),
|
||||||
PreparedRenderTransform::Perspective { .. } => unreachable!(),
|
PreparedRenderTransform::Perspective { .. } => unreachable!(),
|
||||||
};
|
};
|
||||||
if options.subpixel_aa_enabled {
|
if options.subpixel_aa_enabled {
|
||||||
transform = transform
|
transform *= Transform2F::from_scale(Vector2F::new(3.0, 1.0))
|
||||||
.post_mul(&Transform2DF::from_scale(Vector2F::new(3.0, 1.0)))
|
|
||||||
}
|
}
|
||||||
outline.transform(&transform);
|
outline.transform(&transform);
|
||||||
}
|
}
|
||||||
|
@ -174,31 +172,6 @@ impl Scene {
|
||||||
SceneBuilder::new(self, &prepared_options, listener).build(executor)
|
SceneBuilder::new(self, &prepared_options, listener).build(executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_svg<W>(&self, writer: &mut W) -> io::Result<()> where W: Write {
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"{} {} {} {}\">",
|
|
||||||
self.view_box.origin().x(),
|
|
||||||
self.view_box.origin().y(),
|
|
||||||
self.view_box.size().x(),
|
|
||||||
self.view_box.size().y()
|
|
||||||
)?;
|
|
||||||
for path_object in &self.paths {
|
|
||||||
let paint = &self.paints[path_object.paint.0 as usize];
|
|
||||||
write!(writer, " <path")?;
|
|
||||||
if !path_object.name.is_empty() {
|
|
||||||
write!(writer, " id=\"{}\"", path_object.name)?;
|
|
||||||
}
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
" fill=\"{:?}\" d=\"{:?}\" />",
|
|
||||||
paint.color, path_object.outline
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
writeln!(writer, "</svg>")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paths<'a>(&'a self) -> PathIter {
|
pub fn paths<'a>(&'a self) -> PathIter {
|
||||||
PathIter {
|
PathIter {
|
||||||
scene: self,
|
scene: self,
|
||||||
|
@ -211,10 +184,14 @@ pub struct PathIter<'a> {
|
||||||
pos: usize
|
pos: usize
|
||||||
}
|
}
|
||||||
impl<'a> Iterator for PathIter<'a> {
|
impl<'a> Iterator for PathIter<'a> {
|
||||||
type Item = (&'a Paint, &'a Outline);
|
type Item = (&'a Paint, &'a Outline, &'a str);
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let item = self.scene.paths.get(self.pos).map(|path_object| {
|
let item = self.scene.paths.get(self.pos).map(|path_object| {
|
||||||
(self.scene.paints.get(path_object.paint.0 as usize).unwrap(), &path_object.outline)
|
(
|
||||||
|
self.scene.paints.get(path_object.paint.0 as usize).unwrap(),
|
||||||
|
&path_object.outline,
|
||||||
|
&*path_object.name
|
||||||
|
)
|
||||||
});
|
});
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
item
|
item
|
||||||
|
|
|
@ -44,15 +44,11 @@ impl<T> DenseTileMap<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn coords_to_index(&self, coords: Vector2I) -> Option<usize> {
|
pub fn coords_to_index(&self, coords: Vector2I) -> Option<usize> {
|
||||||
// TODO(pcwalton): SIMD?
|
if self.rect.contains_point(coords) {
|
||||||
if coords.x() < self.rect.min_x()
|
|
||||||
|| coords.x() >= self.rect.max_x()
|
|
||||||
|| coords.y() < self.rect.min_y()
|
|
||||||
|| coords.y() >= self.rect.max_y()
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(self.coords_to_index_unchecked(coords))
|
Some(self.coords_to_index_unchecked(coords))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -413,14 +413,11 @@ impl ActiveEdge {
|
||||||
} else {
|
} else {
|
||||||
segment.baseline.to()
|
segment.baseline.to()
|
||||||
};
|
};
|
||||||
ActiveEdge::from_segment_and_crossing(segment, &crossing)
|
ActiveEdge::from_segment_and_crossing(segment, crossing)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_segment_and_crossing(segment: &Segment, crossing: &Vector2F) -> ActiveEdge {
|
fn from_segment_and_crossing(segment: &Segment, crossing: Vector2F) -> ActiveEdge {
|
||||||
ActiveEdge {
|
ActiveEdge { segment: *segment, crossing }
|
||||||
segment: *segment,
|
|
||||||
crossing: *crossing,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&mut self, builder: &SceneBuilder, built_object: &mut BuiltObject, tile_y: i32) {
|
fn process(&mut self, builder: &SceneBuilder, built_object: &mut BuiltObject, tile_y: i32) {
|
||||||
|
@ -436,8 +433,8 @@ impl ActiveEdge {
|
||||||
if segment.is_line() {
|
if segment.is_line() {
|
||||||
let line_segment = segment.as_line_segment();
|
let line_segment = segment.as_line_segment();
|
||||||
self.segment =
|
self.segment =
|
||||||
match self.process_line_segment(&line_segment, builder, built_object, tile_y) {
|
match self.process_line_segment(line_segment, builder, built_object, tile_y) {
|
||||||
Some(lower_part) => Segment::line(&lower_part),
|
Some(lower_part) => Segment::line(lower_part),
|
||||||
None => Segment::none(),
|
None => Segment::none(),
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
|
@ -453,7 +450,7 @@ impl ActiveEdge {
|
||||||
let first_line_segment =
|
let first_line_segment =
|
||||||
LineSegment2F::new(self.crossing, segment.baseline.upper_point()).orient(winding);
|
LineSegment2F::new(self.crossing, segment.baseline.upper_point()).orient(winding);
|
||||||
if self
|
if self
|
||||||
.process_line_segment(&first_line_segment, builder, built_object, tile_y)
|
.process_line_segment(first_line_segment, builder, built_object, tile_y)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -484,9 +481,9 @@ impl ActiveEdge {
|
||||||
);
|
);
|
||||||
|
|
||||||
let line = before_segment.baseline.orient(winding);
|
let line = before_segment.baseline.orient(winding);
|
||||||
match self.process_line_segment(&line, builder, built_object, tile_y) {
|
match self.process_line_segment(line, builder, built_object, tile_y) {
|
||||||
Some(ref lower_part) if split_t == 1.0 => {
|
Some(lower_part) if split_t == 1.0 => {
|
||||||
self.segment = Segment::line(&lower_part);
|
self.segment = Segment::line(lower_part);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
None if split_t == 1.0 => {
|
None if split_t == 1.0 => {
|
||||||
|
@ -504,7 +501,7 @@ impl ActiveEdge {
|
||||||
|
|
||||||
fn process_line_segment(
|
fn process_line_segment(
|
||||||
&mut self,
|
&mut self,
|
||||||
line_segment: &LineSegment2F,
|
line_segment: LineSegment2F,
|
||||||
builder: &SceneBuilder,
|
builder: &SceneBuilder,
|
||||||
built_object: &mut BuiltObject,
|
built_object: &mut BuiltObject,
|
||||||
tile_y: i32,
|
tile_y: i32,
|
||||||
|
@ -516,7 +513,7 @@ impl ActiveEdge {
|
||||||
);
|
);
|
||||||
|
|
||||||
if line_segment.max_y() <= tile_bottom {
|
if line_segment.max_y() <= tile_bottom {
|
||||||
built_object.generate_fill_primitives_for_line(builder, *line_segment, tile_y);
|
built_object.generate_fill_primitives_for_line(builder, line_segment, tile_y);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,9 @@ precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
uniform mat4 uTransform;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uStencilTextureSize;
|
uniform vec2 uStencilTextureSize;
|
||||||
uniform vec2 uViewBoxOrigin;
|
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
in uvec2 aTessCoord;
|
||||||
in uvec3 aTileOrigin;
|
in uvec3 aTileOrigin;
|
||||||
|
@ -51,15 +50,14 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){
|
||||||
|
|
||||||
void computeVaryings(){
|
void computeVaryings(){
|
||||||
vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0;
|
vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0;
|
||||||
vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin;
|
vec2 position =(origin + vec2(aTessCoord))* uTileSize;
|
||||||
vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0);
|
|
||||||
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x);
|
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x);
|
||||||
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
|
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
|
||||||
|
|
||||||
vTexCoord = maskTexCoord / uStencilTextureSize;
|
vTexCoord = maskTexCoord / uStencilTextureSize;
|
||||||
vBackdrop = float(aBackdrop);
|
vBackdrop = float(aBackdrop);
|
||||||
vColor = getColor();
|
vColor = getColor();
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,9 @@ precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
uniform mat4 uTransform;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uStencilTextureSize;
|
uniform vec2 uStencilTextureSize;
|
||||||
uniform vec2 uViewBoxOrigin;
|
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
in uvec2 aTessCoord;
|
||||||
in uvec3 aTileOrigin;
|
in uvec3 aTileOrigin;
|
||||||
|
@ -51,15 +50,14 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){
|
||||||
|
|
||||||
void computeVaryings(){
|
void computeVaryings(){
|
||||||
vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0;
|
vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0;
|
||||||
vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin;
|
vec2 position =(origin + vec2(aTessCoord))* uTileSize;
|
||||||
vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0);
|
|
||||||
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x);
|
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x);
|
||||||
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
|
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
|
||||||
|
|
||||||
vTexCoord = maskTexCoord / uStencilTextureSize;
|
vTexCoord = maskTexCoord / uStencilTextureSize;
|
||||||
vBackdrop = float(aBackdrop);
|
vBackdrop = float(aBackdrop);
|
||||||
vColor = getColor();
|
vColor = getColor();
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,8 @@ precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
uniform mat4 uTransform;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uViewBoxOrigin;
|
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
in uvec2 aTessCoord;
|
||||||
in ivec2 aTileOrigin;
|
in ivec2 aTileOrigin;
|
||||||
|
@ -39,11 +38,9 @@ out vec4 vColor;
|
||||||
vec4 getColor();
|
vec4 getColor();
|
||||||
|
|
||||||
void computeVaryings(){
|
void computeVaryings(){
|
||||||
vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin;
|
vec2 position = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize;
|
||||||
vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0);
|
|
||||||
|
|
||||||
vColor = getColor();
|
vColor = getColor();
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,8 @@ precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
uniform mat4 uTransform;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uViewBoxOrigin;
|
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
in uvec2 aTessCoord;
|
||||||
in ivec2 aTileOrigin;
|
in ivec2 aTileOrigin;
|
||||||
|
@ -39,11 +38,9 @@ out vec4 vColor;
|
||||||
vec4 getColor();
|
vec4 getColor();
|
||||||
|
|
||||||
void computeVaryings(){
|
void computeVaryings(){
|
||||||
vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin;
|
vec2 position = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize;
|
||||||
vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0);
|
|
||||||
|
|
||||||
vColor = getColor();
|
vColor = getColor();
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,9 @@ using namespace metal;
|
||||||
struct spvDescriptorSetBuffer0
|
struct spvDescriptorSetBuffer0
|
||||||
{
|
{
|
||||||
constant float2* uTileSize [[id(0)]];
|
constant float2* uTileSize [[id(0)]];
|
||||||
constant float2* uViewBoxOrigin [[id(1)]];
|
constant float2* uStencilTextureSize [[id(1)]];
|
||||||
constant float2* uFramebufferSize [[id(2)]];
|
constant float4x4* uTransform [[id(2)]];
|
||||||
constant float2* uStencilTextureSize [[id(3)]];
|
constant float4* uColor [[id(3)]];
|
||||||
constant float4* uColor [[id(4)]];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct main0_out
|
struct main0_out
|
||||||
|
@ -43,11 +42,10 @@ float4 getColor(thread float4 uColor)
|
||||||
return uColor;
|
return uColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4 uColor)
|
void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4x4 uTransform, thread float4 uColor)
|
||||||
{
|
{
|
||||||
float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0);
|
float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0);
|
||||||
float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin;
|
float2 position = (origin + float2(aTessCoord)) * uTileSize;
|
||||||
float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0);
|
|
||||||
uint param = uint(aTileIndex);
|
uint param = uint(aTileIndex);
|
||||||
float param_1 = uStencilTextureSize.x;
|
float param_1 = uStencilTextureSize.x;
|
||||||
float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize);
|
float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize);
|
||||||
|
@ -55,13 +53,13 @@ void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread
|
||||||
vTexCoord = maskTexCoord / uStencilTextureSize;
|
vTexCoord = maskTexCoord / uStencilTextureSize;
|
||||||
vBackdrop = float(aBackdrop);
|
vBackdrop = float(aBackdrop);
|
||||||
vColor = getColor(uColor);
|
vColor = getColor(uColor);
|
||||||
gl_Position = float4(position, 0.0, 1.0);
|
gl_Position = uTransform * float4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
||||||
{
|
{
|
||||||
main0_out out = {};
|
main0_out out = {};
|
||||||
computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor));
|
computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, (*spvDescriptorSet0.uTransform), (*spvDescriptorSet0.uColor));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,10 @@ using namespace metal;
|
||||||
struct spvDescriptorSetBuffer0
|
struct spvDescriptorSetBuffer0
|
||||||
{
|
{
|
||||||
constant float2* uTileSize [[id(0)]];
|
constant float2* uTileSize [[id(0)]];
|
||||||
constant float2* uViewBoxOrigin [[id(1)]];
|
constant float2* uStencilTextureSize [[id(1)]];
|
||||||
constant float2* uFramebufferSize [[id(2)]];
|
constant float4x4* uTransform [[id(2)]];
|
||||||
constant float2* uStencilTextureSize [[id(3)]];
|
texture2d<float> uPaintTexture [[id(3)]];
|
||||||
texture2d<float> uPaintTexture [[id(4)]];
|
sampler uPaintTextureSmplr [[id(4)]];
|
||||||
sampler uPaintTextureSmplr [[id(5)]];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct main0_out
|
struct main0_out
|
||||||
|
@ -45,11 +44,10 @@ float4 getColor(thread texture2d<float> uPaintTexture, thread const sampler uPai
|
||||||
return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0));
|
return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord)
|
void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4x4 uTransform, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord)
|
||||||
{
|
{
|
||||||
float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0);
|
float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0);
|
||||||
float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin;
|
float2 position = (origin + float2(aTessCoord)) * uTileSize;
|
||||||
float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0);
|
|
||||||
uint param = uint(aTileIndex);
|
uint param = uint(aTileIndex);
|
||||||
float param_1 = uStencilTextureSize.x;
|
float param_1 = uStencilTextureSize.x;
|
||||||
float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize);
|
float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize);
|
||||||
|
@ -57,13 +55,13 @@ void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread
|
||||||
vTexCoord = maskTexCoord / uStencilTextureSize;
|
vTexCoord = maskTexCoord / uStencilTextureSize;
|
||||||
vBackdrop = float(aBackdrop);
|
vBackdrop = float(aBackdrop);
|
||||||
vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord);
|
vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord);
|
||||||
gl_Position = float4(position, 0.0, 1.0);
|
gl_Position = uTransform * float4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
||||||
{
|
{
|
||||||
main0_out out = {};
|
main0_out out = {};
|
||||||
computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord);
|
computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, (*spvDescriptorSet0.uTransform), spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,8 @@ using namespace metal;
|
||||||
struct spvDescriptorSetBuffer0
|
struct spvDescriptorSetBuffer0
|
||||||
{
|
{
|
||||||
constant float2* uTileSize [[id(0)]];
|
constant float2* uTileSize [[id(0)]];
|
||||||
constant float2* uViewBoxOrigin [[id(1)]];
|
constant float4x4* uTransform [[id(1)]];
|
||||||
constant float2* uFramebufferSize [[id(2)]];
|
constant float4* uColor [[id(2)]];
|
||||||
constant float4* uColor [[id(3)]];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct main0_out
|
struct main0_out
|
||||||
|
@ -31,18 +30,17 @@ float4 getColor(thread float4 uColor)
|
||||||
return uColor;
|
return uColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread float4 uColor)
|
void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float4& vColor, thread float4& gl_Position, thread float4x4 uTransform, thread float4 uColor)
|
||||||
{
|
{
|
||||||
float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin;
|
float2 position = float2(aTileOrigin + int2(aTessCoord)) * uTileSize;
|
||||||
float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0);
|
|
||||||
vColor = getColor(uColor);
|
vColor = getColor(uColor);
|
||||||
gl_Position = float4(position, 0.0, 1.0);
|
gl_Position = uTransform * float4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
||||||
{
|
{
|
||||||
main0_out out = {};
|
main0_out out = {};
|
||||||
computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor));
|
computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), out.vColor, out.gl_Position, (*spvDescriptorSet0.uTransform), (*spvDescriptorSet0.uColor));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,9 @@ using namespace metal;
|
||||||
struct spvDescriptorSetBuffer0
|
struct spvDescriptorSetBuffer0
|
||||||
{
|
{
|
||||||
constant float2* uTileSize [[id(0)]];
|
constant float2* uTileSize [[id(0)]];
|
||||||
constant float2* uViewBoxOrigin [[id(1)]];
|
constant float4x4* uTransform [[id(1)]];
|
||||||
constant float2* uFramebufferSize [[id(2)]];
|
texture2d<float> uPaintTexture [[id(2)]];
|
||||||
texture2d<float> uPaintTexture [[id(3)]];
|
sampler uPaintTextureSmplr [[id(3)]];
|
||||||
sampler uPaintTextureSmplr [[id(4)]];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct main0_out
|
struct main0_out
|
||||||
|
@ -33,18 +32,17 @@ float4 getColor(thread texture2d<float> uPaintTexture, thread const sampler uPai
|
||||||
return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0));
|
return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord)
|
void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float4& vColor, thread float4& gl_Position, thread float4x4 uTransform, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord)
|
||||||
{
|
{
|
||||||
float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin;
|
float2 position = float2(aTileOrigin + int2(aTessCoord)) * uTileSize;
|
||||||
float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0);
|
|
||||||
vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord);
|
vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord);
|
||||||
gl_Position = float4(position, 0.0, 1.0);
|
gl_Position = uTransform * float4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
||||||
{
|
{
|
||||||
main0_out out = {};
|
main0_out out = {};
|
||||||
computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord);
|
computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), out.vColor, out.gl_Position, (*spvDescriptorSet0.uTransform), spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,9 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
uniform mat4 uTransform;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uStencilTextureSize;
|
uniform vec2 uStencilTextureSize;
|
||||||
uniform vec2 uViewBoxOrigin;
|
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
in uvec2 aTessCoord;
|
||||||
in uvec3 aTileOrigin;
|
in uvec3 aTileOrigin;
|
||||||
|
@ -32,14 +31,13 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
|
||||||
|
|
||||||
void computeVaryings() {
|
void computeVaryings() {
|
||||||
vec2 origin = vec2(aTileOrigin.xy) + vec2(aTileOrigin.z & 15u, aTileOrigin.z >> 4u) * 256.0;
|
vec2 origin = vec2(aTileOrigin.xy) + vec2(aTileOrigin.z & 15u, aTileOrigin.z >> 4u) * 256.0;
|
||||||
vec2 pixelPosition = (origin + vec2(aTessCoord)) * uTileSize + uViewBoxOrigin;
|
vec2 position = (origin + vec2(aTessCoord)) * uTileSize;
|
||||||
vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0);
|
|
||||||
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize.x);
|
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize.x);
|
||||||
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
|
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
|
||||||
|
|
||||||
vTexCoord = maskTexCoord / uStencilTextureSize;
|
vTexCoord = maskTexCoord / uStencilTextureSize;
|
||||||
vBackdrop = float(aBackdrop);
|
vBackdrop = float(aBackdrop);
|
||||||
vColor = getColor();
|
vColor = getColor();
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
uniform mat4 uTransform;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uViewBoxOrigin;
|
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
in uvec2 aTessCoord;
|
||||||
in ivec2 aTileOrigin;
|
in ivec2 aTileOrigin;
|
||||||
|
@ -20,9 +19,7 @@ out vec4 vColor;
|
||||||
vec4 getColor();
|
vec4 getColor();
|
||||||
|
|
||||||
void computeVaryings() {
|
void computeVaryings() {
|
||||||
vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord)) * uTileSize + uViewBoxOrigin;
|
vec2 position = vec2(aTileOrigin + ivec2(aTessCoord)) * uTileSize;
|
||||||
vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0);
|
|
||||||
|
|
||||||
vColor = getColor();
|
vColor = getColor();
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,198 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::arch::aarch64::{self, float32x4_t, int32x4_t, uint32x4_t, uint64x2_t, uint8x16_t};
|
use std::arch::aarch64::{self, float32x2_t, float32x4_t, int32x2_t, int32x4_t};
|
||||||
use std::arch::aarch64::{uint8x8_t, uint8x8x2_t};
|
use std::arch::aarch64::{uint32x2_t, uint32x4_t};
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Add, Index, IndexMut, Mul, Sub};
|
use std::ops::{Add, BitAnd, BitOr, Index, IndexMut, Mul, Shr, Sub};
|
||||||
|
|
||||||
mod swizzle_f32x4;
|
mod swizzle_f32x4;
|
||||||
mod swizzle_i32x4;
|
mod swizzle_i32x4;
|
||||||
|
|
||||||
// 32-bit floats
|
// Two 32-bit floats
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct F32x2(pub float32x2_t);
|
||||||
|
|
||||||
|
impl F32x2 {
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new(a: f32, b: f32) -> F32x2 {
|
||||||
|
unsafe { F32x2(mem::transmute([a, b])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn splat(x: f32) -> F32x2 {
|
||||||
|
F32x2::new(x, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic operations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn approx_recip(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(vrecpe_v2f32(self.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn min(self, other: F32x2) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_fmin(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn max(self, other: F32x2) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_fmax(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clamp(self, min: F32x2, max: F32x2) -> F32x2 {
|
||||||
|
self.max(min).min(max)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn abs(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(fabs_v2f32(self.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn floor(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(floor_v2f32(self.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ceil(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(ceil_v2f32(self.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn round(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(round_v2f32(self.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn sqrt(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(sqrt_v2f32(self.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packed comparisons
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_eq(self, other: F32x2) -> U32x2 {
|
||||||
|
unsafe { U32x2(simd_eq(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_gt(self, other: F32x2) -> U32x2 {
|
||||||
|
unsafe { U32x2(simd_gt(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_lt(self, other: F32x2) -> U32x2 {
|
||||||
|
unsafe { U32x2(simd_lt(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_le(self, other: F32x2) -> U32x2 {
|
||||||
|
unsafe { U32x2(simd_le(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_f32x4(self) -> F32x4 {
|
||||||
|
self.concat_xy_xy(F32x2::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_i32x2(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_cast(self.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_i32x4(self) -> I32x4 {
|
||||||
|
self.to_i32x2().concat_xy_xy(I32x2::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swizzle
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yx(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_shuffle2(self.0, self.0, [1, 0])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concatenations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn concat_xy_xy(self, other: F32x2) -> F32x4 {
|
||||||
|
unsafe { F32x4(simd_shuffle4(self.0, other.0, [0, 1, 0, 1])) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> F32x2 {
|
||||||
|
F32x2::new(0.0, 0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "<{}, {}>", self[0], self[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for F32x2 {
|
||||||
|
type Output = f32;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &f32 {
|
||||||
|
unsafe {
|
||||||
|
assert!(index < 2);
|
||||||
|
let ptr = &self.0 as *const float32x2_t as *const f32;
|
||||||
|
mem::transmute::<*const f32, &f32>(ptr.offset(index as isize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut f32 {
|
||||||
|
unsafe {
|
||||||
|
assert!(index < 2);
|
||||||
|
let ptr = &mut self.0 as *mut float32x2_t as *mut f32;
|
||||||
|
mem::transmute::<*mut f32, &mut f32>(ptr.offset(index as isize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Add<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: F32x2) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_add(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: F32x2) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_mul(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: F32x2) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_sub(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit floats
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct F32x4(pub float32x4_t);
|
pub struct F32x4(pub float32x4_t);
|
||||||
|
@ -103,32 +284,56 @@ impl F32x4 {
|
||||||
unsafe { U32x4(simd_lt(self.0, other.0)) }
|
unsafe { U32x4(simd_lt(self.0, other.0)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts these packed floats to integers.
|
// Swizzle conversions
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_i32x4(self) -> I32x4 {
|
pub fn xy(self) -> F32x2 {
|
||||||
unsafe { I32x4(simd_cast(self.0)) }
|
unsafe { F32x2(simd_shuffle2(self.0, self.0, [0, 1])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yx(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_shuffle2(self.0, self.0, [1, 0])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xw(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_shuffle2(self.0, self.0, [0, 3])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zy(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_shuffle2(self.0, self.0, [2, 1])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zw(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_shuffle2(self.0, self.0, [2, 3])) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concatenations
|
// Concatenations
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn concat_xy_xy(self, other: F32x4) -> F32x4 {
|
pub fn concat_xy_xy(self, other: F32x4) -> F32x4 {
|
||||||
unsafe { F32x4(simd_shuffle4(self.0, other.0, [0, 1, 4, 5])) }
|
unsafe { F32x4(simd_shuffle4(self.0, other.0, [0, 1, 0, 1])) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn concat_xy_zw(self, other: F32x4) -> F32x4 {
|
pub fn concat_xy_zw(self, other: F32x4) -> F32x4 {
|
||||||
unsafe { F32x4(simd_shuffle4(self.0, other.0, [0, 1, 6, 7])) }
|
unsafe { F32x4(simd_shuffle4(self.0, other.0, [0, 1, 2, 3])) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn concat_zw_zw(self, other: F32x4) -> F32x4 {
|
pub fn concat_zw_zw(self, other: F32x4) -> F32x4 {
|
||||||
unsafe { F32x4(simd_shuffle4(self.0, other.0, [2, 3, 6, 7])) }
|
unsafe { F32x4(simd_shuffle4(self.0, other.0, [2, 3, 2, 3])) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
|
||||||
|
// Converts these packed floats to integers.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn concat_wz_yx(self, other: F32x4) -> F32x4 {
|
pub fn to_i32x4(self) -> I32x4 {
|
||||||
unsafe { F32x4(simd_shuffle4(self.0, other.0, [3, 2, 5, 4])) }
|
unsafe { I32x4(simd_cast(self.0)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +405,105 @@ impl Sub<F32x4> for F32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32-bit signed integers
|
// Two 32-bit signed integers
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct I32x2(pub int32x2_t);
|
||||||
|
|
||||||
|
impl I32x2 {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(x: i32, y: i32) -> I32x2 {
|
||||||
|
unsafe { I32x2(mem::transmute([x, y])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn splat(x: i32) -> I32x2 {
|
||||||
|
I32x2::new(x, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_eq(self, other: I32x2) -> U32x2 {
|
||||||
|
unsafe { U32x2(simd_eq(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concatenations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn concat_xy_xy(self, other: I32x2) -> I32x4 {
|
||||||
|
unsafe { I32x4(simd_shuffle4(self.0, other.0, [0, 1, 0, 1])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
|
||||||
|
/// Converts these packed integers to floats.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_f32x2(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(simd_cast(self.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> I32x2 {
|
||||||
|
I32x2::splat(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &I32x2) -> bool {
|
||||||
|
self.packed_eq(*other).is_all_ones()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for I32x2 {
|
||||||
|
type Output = i32;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &i32 {
|
||||||
|
unsafe {
|
||||||
|
assert!(index < 2);
|
||||||
|
let ptr = &self.0 as *const int32x2_t as *const i32;
|
||||||
|
mem::transmute::<*const i32, &i32>(ptr.offset(index as isize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut i32 {
|
||||||
|
unsafe {
|
||||||
|
assert!(index < 2);
|
||||||
|
let ptr = &mut self.0 as *mut int32x2_t as *mut i32;
|
||||||
|
mem::transmute::<*mut i32, &mut i32>(ptr.offset(index as isize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: I32x2) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_add(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: I32x2) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_sub(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: I32x2) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_mul(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit signed integers
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct I32x4(pub int32x4_t);
|
pub struct I32x4(pub int32x4_t);
|
||||||
|
@ -216,11 +519,6 @@ impl I32x4 {
|
||||||
I32x4::new(x, x, x, x)
|
I32x4::new(x, x, x, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn as_u8x16(self) -> U8x16 {
|
|
||||||
unsafe { U8x16(*mem::transmute::<&int32x4_t, &uint8x16_t>(&self.0)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min(self, other: I32x4) -> I32x4 {
|
pub fn min(self, other: I32x4) -> I32x4 {
|
||||||
unsafe { I32x4(simd_fmin(self.0, other.0)) }
|
unsafe { I32x4(simd_fmin(self.0, other.0)) }
|
||||||
|
@ -245,6 +543,33 @@ impl I32x4 {
|
||||||
unsafe { I32x4(simd_shuffle4(self.0, other.0, [0, 1, 4, 5])) }
|
unsafe { I32x4(simd_shuffle4(self.0, other.0, [0, 1, 4, 5])) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swizzle conversions
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xy(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_shuffle2(self.0, self.0, [0, 1])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yx(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_shuffle2(self.0, self.0, [1, 0])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xw(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_shuffle2(self.0, self.0, [0, 3])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zy(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_shuffle2(self.0, self.0, [2, 1])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zw(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(simd_shuffle2(self.0, self.0, [2, 3])) }
|
||||||
|
}
|
||||||
|
|
||||||
// Conversions
|
// Conversions
|
||||||
|
|
||||||
/// Converts these packed integers to floats.
|
/// Converts these packed integers to floats.
|
||||||
|
@ -315,7 +640,60 @@ impl PartialEq for I32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32-bit unsigned integers
|
impl BitAnd<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn bitand(self, other: I32x4) -> I32x4 {
|
||||||
|
unsafe { I32x4(simd_and(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn bitor(self, other: I32x4) -> I32x4 {
|
||||||
|
unsafe { I32x4(simd_or(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shr<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn shr(self, other: I32x4) -> I32x4 {
|
||||||
|
unsafe { I32x4(simd_shr(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two 32-bit unsigned integers
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct U32x2(pub uint32x2_t);
|
||||||
|
|
||||||
|
impl U32x2 {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_all_ones(&self) -> bool {
|
||||||
|
unsafe { aarch64::vminv_u32(self.0) == !0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_all_zeroes(&self) -> bool {
|
||||||
|
unsafe { aarch64::vmaxv_u32(self.0) == 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for U32x2 {
|
||||||
|
type Output = u32;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &u32 {
|
||||||
|
unsafe {
|
||||||
|
assert!(index < 2);
|
||||||
|
let ptr = &self.0 as *const uint32x2_t as *const u32;
|
||||||
|
mem::transmute::<*const u32, &u32>(ptr.offset(index as isize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit unsigned integers
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct U32x4(pub uint32x4_t);
|
pub struct U32x4(pub uint32x4_t);
|
||||||
|
@ -344,44 +722,6 @@ impl Index<usize> for U32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-bit unsigned integers
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct U8x16(pub uint8x16_t);
|
|
||||||
|
|
||||||
impl U8x16 {
|
|
||||||
#[inline]
|
|
||||||
pub fn as_i32x4(self) -> I32x4 {
|
|
||||||
unsafe { I32x4(*mem::transmute::<&uint8x16_t, &int32x4_t>(&self.0)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn shuffle(self, indices: U8x16) -> U8x16 {
|
|
||||||
unsafe {
|
|
||||||
let table = mem::transmute::<uint8x16_t, uint8x8x2_t>(self.0);
|
|
||||||
let low = aarch64::vtbl2_u8(table, indices.extract_low());
|
|
||||||
let high = aarch64::vtbl2_u8(table, indices.extract_high());
|
|
||||||
U8x16(aarch64::vcombine_u8(low, high))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn extract_low(self) -> uint8x8_t {
|
|
||||||
unsafe {
|
|
||||||
let low = simd_extract(mem::transmute::<uint8x16_t, uint64x2_t>(self.0), 0);
|
|
||||||
mem::transmute::<u64, uint8x8_t>(low)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn extract_high(self) -> uint8x8_t {
|
|
||||||
unsafe {
|
|
||||||
let high = simd_extract(mem::transmute::<uint8x16_t, uint64x2_t>(self.0), 1);
|
|
||||||
mem::transmute::<u64, uint8x8_t>(high)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intrinsics
|
// Intrinsics
|
||||||
|
|
||||||
extern "platform-intrinsic" {
|
extern "platform-intrinsic" {
|
||||||
|
@ -389,6 +729,11 @@ extern "platform-intrinsic" {
|
||||||
fn simd_mul<T>(x: T, y: T) -> T;
|
fn simd_mul<T>(x: T, y: T) -> T;
|
||||||
fn simd_sub<T>(x: T, y: T) -> T;
|
fn simd_sub<T>(x: T, y: T) -> T;
|
||||||
|
|
||||||
|
fn simd_shr<T>(x: T, y: T) -> T;
|
||||||
|
|
||||||
|
fn simd_and<T>(x: T, y: T) -> T;
|
||||||
|
fn simd_or<T>(x: T, y: T) -> T;
|
||||||
|
|
||||||
fn simd_fmin<T>(x: T, y: T) -> T;
|
fn simd_fmin<T>(x: T, y: T) -> T;
|
||||||
fn simd_fmax<T>(x: T, y: T) -> T;
|
fn simd_fmax<T>(x: T, y: T) -> T;
|
||||||
|
|
||||||
|
@ -397,15 +742,24 @@ extern "platform-intrinsic" {
|
||||||
fn simd_le<T, U>(x: T, y: T) -> U;
|
fn simd_le<T, U>(x: T, y: T) -> U;
|
||||||
fn simd_lt<T, U>(x: T, y: T) -> U;
|
fn simd_lt<T, U>(x: T, y: T) -> U;
|
||||||
|
|
||||||
|
fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
|
||||||
fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
|
fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
|
||||||
|
|
||||||
fn simd_cast<T, U>(x: T) -> U;
|
fn simd_cast<T, U>(x: T) -> U;
|
||||||
|
|
||||||
fn simd_insert<T, U>(x: T, index: u32, value: U) -> T;
|
|
||||||
fn simd_extract<T, U>(x: T, index: u32) -> U;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#[link_name = "llvm.fabs.v2f32"]
|
||||||
|
fn fabs_v2f32(a: float32x2_t) -> float32x2_t;
|
||||||
|
#[link_name = "llvm.floor.v2f32"]
|
||||||
|
fn floor_v2f32(a: float32x2_t) -> float32x2_t;
|
||||||
|
#[link_name = "llvm.ceil.v2f32"]
|
||||||
|
fn ceil_v2f32(a: float32x2_t) -> float32x2_t;
|
||||||
|
#[link_name = "llvm.round.v2f32"]
|
||||||
|
fn round_v2f32(a: float32x2_t) -> float32x2_t;
|
||||||
|
#[link_name = "llvm.sqrt.v2f32"]
|
||||||
|
fn sqrt_v2f32(a: float32x2_t) -> float32x2_t;
|
||||||
|
|
||||||
#[link_name = "llvm.fabs.v4f32"]
|
#[link_name = "llvm.fabs.v4f32"]
|
||||||
fn fabs_v4f32(a: float32x4_t) -> float32x4_t;
|
fn fabs_v4f32(a: float32x4_t) -> float32x4_t;
|
||||||
#[link_name = "llvm.floor.v4f32"]
|
#[link_name = "llvm.floor.v4f32"]
|
||||||
|
@ -417,6 +771,9 @@ extern "C" {
|
||||||
#[link_name = "llvm.sqrt.v4f32"]
|
#[link_name = "llvm.sqrt.v4f32"]
|
||||||
fn sqrt_v4f32(a: float32x4_t) -> float32x4_t;
|
fn sqrt_v4f32(a: float32x4_t) -> float32x4_t;
|
||||||
|
|
||||||
|
#[link_name = "llvm.aarch64.neon.frecpe.v2f32"]
|
||||||
|
fn vrecpe_v2f32(a: float32x2_t) -> float32x2_t;
|
||||||
|
|
||||||
#[link_name = "llvm.aarch64.neon.frecpe.v4f32"]
|
#[link_name = "llvm.aarch64.neon.frecpe.v4f32"]
|
||||||
fn vrecpe_v4f32(a: float32x4_t) -> float32x4_t;
|
fn vrecpe_v4f32(a: float32x4_t) -> float32x4_t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,84 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::default::{F32x4, I32x4};
|
use crate::default::{F32x2, F32x4, I32x2, I32x4};
|
||||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||||
|
|
||||||
// 32-bit floats
|
// Two 32-bit floats
|
||||||
|
|
||||||
|
impl F32x2 {
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_slice(slice: &[f32]) -> F32x2 {
|
||||||
|
F32x2::new(slice[0], slice[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn x(self) -> f32 {
|
||||||
|
self[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn y(self) -> f32 {
|
||||||
|
self[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutators
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_x(&mut self, x: f32) {
|
||||||
|
self[0] = x
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_y(&mut self, y: f32) {
|
||||||
|
self[1] = y
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparisons
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn approx_eq(self, other: F32x2, epsilon: f32) -> bool {
|
||||||
|
(self - other)
|
||||||
|
.abs()
|
||||||
|
.packed_gt(F32x2::splat(epsilon))
|
||||||
|
.is_all_zeroes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, other: F32x2) {
|
||||||
|
*self = *self + other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, other: F32x2) {
|
||||||
|
*self = *self - other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn mul_assign(&mut self, other: F32x2) {
|
||||||
|
*self = *self * other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self) -> F32x2 {
|
||||||
|
F32x2::default() - self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit floats
|
||||||
|
|
||||||
impl F32x4 {
|
impl F32x4 {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
@ -105,7 +179,38 @@ impl Neg for F32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32-bit integers
|
// Two 32-bit integers
|
||||||
|
|
||||||
|
impl AddAssign for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, other: I32x2) {
|
||||||
|
*self = *self + other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, other: I32x2) {
|
||||||
|
*self = *self - other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn mul_assign(&mut self, other: I32x2) {
|
||||||
|
*self = *self * other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self) -> I32x2 {
|
||||||
|
I32x2::default() - self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit integers
|
||||||
|
|
||||||
impl AddAssign for I32x4 {
|
impl AddAssign for I32x4 {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -10,13 +10,182 @@
|
||||||
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::ops::{Add, BitAnd, BitOr, Index, IndexMut, Mul, Shr, Sub};
|
||||||
use std::ops::{Add, Index, IndexMut, Mul, Sub};
|
|
||||||
|
|
||||||
mod swizzle_f32x4;
|
mod swizzle_f32x4;
|
||||||
mod swizzle_i32x4;
|
mod swizzle_i32x4;
|
||||||
|
|
||||||
// 32-bit floats
|
// Two 32-bit floats
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
pub struct F32x2(pub [f32; 2]);
|
||||||
|
|
||||||
|
impl F32x2 {
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new(a: f32, b: f32) -> F32x2 {
|
||||||
|
F32x2([a, b])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn splat(x: f32) -> F32x2 {
|
||||||
|
F32x2([x, x])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic operations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn approx_recip(self) -> F32x2 {
|
||||||
|
F32x2([1.0 / self[0], 1.0 / self[1]])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn min(self, other: F32x2) -> F32x2 {
|
||||||
|
F32x2([f32::min(self[0], other[0]), f32::min(self[1], other[1])])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn max(self, other: F32x2) -> F32x2 {
|
||||||
|
F32x2([f32::max(self[0], other[0]), f32::max(self[1], other[1])])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clamp(self, min: F32x2, max: F32x2) -> F32x2 {
|
||||||
|
self.max(min).min(max)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn abs(self) -> F32x2 {
|
||||||
|
F32x2([self[0].abs(), self[1].abs()])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn floor(self) -> F32x2 {
|
||||||
|
F32x2([self[0].floor(), self[1].floor()])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ceil(self) -> F32x2 {
|
||||||
|
F32x2([self[0].ceil(), self[1].ceil()])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn round(self) -> F32x2 {
|
||||||
|
F32x2([self[0].round(), self[1].round()])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn sqrt(self) -> F32x2 {
|
||||||
|
F32x2([self[0].sqrt(), self[1].sqrt()])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packed comparisons
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_eq(self, other: F32x2) -> U32x2 {
|
||||||
|
U32x2([
|
||||||
|
if self[0] == other[0] { !0 } else { 0 },
|
||||||
|
if self[1] == other[1] { !0 } else { 0 },
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_gt(self, other: F32x2) -> U32x2 {
|
||||||
|
U32x2([
|
||||||
|
if self[0] > other[0] { !0 } else { 0 },
|
||||||
|
if self[1] > other[1] { !0 } else { 0 },
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_lt(self, other: F32x2) -> U32x2 {
|
||||||
|
U32x2([
|
||||||
|
if self[0] < other[0] { !0 } else { 0 },
|
||||||
|
if self[1] < other[1] { !0 } else { 0 },
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_le(self, other: F32x2) -> U32x2 {
|
||||||
|
U32x2([
|
||||||
|
if self[0] <= other[0] { !0 } else { 0 },
|
||||||
|
if self[1] <= other[1] { !0 } else { 0 },
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_f32x4(self) -> F32x4 {
|
||||||
|
F32x4([self[0] as f32, self[1] as f32, 0.0, 0.0])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_i32x2(self) -> I32x2 {
|
||||||
|
I32x2([self[0] as i32, self[1] as i32])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_i32x4(self) -> I32x4 {
|
||||||
|
I32x4([self[0] as i32, self[1] as i32, 0, 0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swizzle
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yx(self) -> F32x2 {
|
||||||
|
F32x2([self[1], self[0]])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concatenations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn concat_xy_xy(self, other: F32x2) -> F32x4 {
|
||||||
|
F32x4([self[0], self[1], other[0], other[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for F32x2 {
|
||||||
|
type Output = f32;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &f32 {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut f32 {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: F32x2) -> F32x2 {
|
||||||
|
F32x2([self[0] + other[0], self[1] + other[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: F32x2) -> F32x2 {
|
||||||
|
F32x2([self[0] * other[0], self[1] * other[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: F32x2) -> F32x2 {
|
||||||
|
F32x2([self[0] - other[0], self[1] - other[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit floats
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, PartialEq)]
|
#[derive(Clone, Copy, Default, PartialEq)]
|
||||||
pub struct F32x4(pub [f32; 4]);
|
pub struct F32x4(pub [f32; 4]);
|
||||||
|
@ -162,6 +331,33 @@ impl F32x4 {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swizzle conversions
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xy(self) -> F32x2 {
|
||||||
|
F32x2([self[0], self[1]])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xw(self) -> F32x2 {
|
||||||
|
F32x2([self[0], self[3]])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yx(self) -> F32x2 {
|
||||||
|
F32x2([self[1], self[0]])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zy(self) -> F32x2 {
|
||||||
|
F32x2([self[2], self[1]])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zw(self) -> F32x2 {
|
||||||
|
F32x2([self[2], self[3]])
|
||||||
|
}
|
||||||
|
|
||||||
// Concatenations
|
// Concatenations
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -246,7 +442,84 @@ impl Sub<F32x4> for F32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32-bit signed integers
|
// Two 32-bit signed integers
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
||||||
|
pub struct I32x2([i32; 2]);
|
||||||
|
|
||||||
|
impl I32x2 {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(x: i32, y: i32) -> I32x2 {
|
||||||
|
I32x2([x, y])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn splat(x: i32) -> I32x2 {
|
||||||
|
I32x2([x, x])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_eq(self, other: I32x2) -> U32x2 {
|
||||||
|
U32x2([
|
||||||
|
if self[0] == other[0] { !0 } else { 0 },
|
||||||
|
if self[1] == other[1] { !0 } else { 0 },
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn concat_xy_xy(self, other: I32x2) -> I32x4 {
|
||||||
|
I32x4([self[0], self[1], other[0], other[1]])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
|
||||||
|
/// Converts these packed integers to floats.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_f32x2(self) -> F32x2 {
|
||||||
|
F32x2([self[0] as f32, self[1] as f32])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for I32x2 {
|
||||||
|
type Output = i32;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &i32 {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut i32 {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: I32x2) -> I32x2 {
|
||||||
|
I32x2([self[0] + other[0], self[1] + other[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: I32x2) -> I32x2 {
|
||||||
|
I32x2([self[0] - other[0], self[1] - other[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: I32x2) -> I32x2 {
|
||||||
|
I32x2([self[0] * other[0], self[1] * other[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit signed integers
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
||||||
pub struct I32x4([i32; 4]);
|
pub struct I32x4([i32; 4]);
|
||||||
|
@ -263,10 +536,6 @@ impl I32x4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_u8x16(self) -> U8x16 {
|
|
||||||
unsafe { U8x16(*mem::transmute::<&[i32; 4], &[u8; 16]>(&self.0)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min(self, other: I32x4) -> I32x4 {
|
pub fn min(self, other: I32x4) -> I32x4 {
|
||||||
I32x4([
|
I32x4([
|
||||||
|
@ -306,6 +575,28 @@ impl I32x4 {
|
||||||
I32x4([self[0], self[1], other[0], other[1]])
|
I32x4([self[0], self[1], other[0], other[1]])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swizzle conversions
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xy(self) -> I32x2 {
|
||||||
|
I32x2([self[0], self[1]])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xw(self) -> I32x2 {
|
||||||
|
I32x2([self[0], self[3]])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zy(self) -> I32x2 {
|
||||||
|
I32x2([self[2], self[1]])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zw(self) -> I32x2 {
|
||||||
|
I32x2([self[2], self[3]])
|
||||||
|
}
|
||||||
|
|
||||||
// Conversions
|
// Conversions
|
||||||
|
|
||||||
/// Converts these packed integers to floats.
|
/// Converts these packed integers to floats.
|
||||||
|
@ -374,7 +665,61 @@ impl Mul<I32x4> for I32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32-bit unsigned integers
|
impl BitAnd<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn bitand(self, other: I32x4) -> I32x4 {
|
||||||
|
I32x4([self[0] & other[0], self[1] & other[1], self[2] & other[2], self[3] & other[3]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn bitor(self, other: I32x4) -> I32x4 {
|
||||||
|
I32x4([self[0] | other[0], self[1] | other[1], self[2] | other[2], self[3] | other[3]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shr<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn shr(self, other: I32x4) -> I32x4 {
|
||||||
|
I32x4([
|
||||||
|
self[0] >> other[0],
|
||||||
|
self[1] >> other[1],
|
||||||
|
self[2] >> other[2],
|
||||||
|
self[3] >> other[3],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two 32-bit unsigned integers
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct U32x2(pub [u32; 2]);
|
||||||
|
|
||||||
|
impl U32x2 {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_all_ones(&self) -> bool {
|
||||||
|
self[0] == !0 && self[1] == !0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_all_zeroes(&self) -> bool {
|
||||||
|
self[0] == 0 && self[1] == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for U32x2 {
|
||||||
|
type Output = u32;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &u32 {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit unsigned integers
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct U32x4(pub [u32; 4]);
|
pub struct U32x4(pub [u32; 4]);
|
||||||
|
@ -398,24 +743,3 @@ impl Index<usize> for U32x4 {
|
||||||
&self.0[index]
|
&self.0[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-bit unsigned integers
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct U8x16([u8; 16]);
|
|
||||||
|
|
||||||
impl U8x16 {
|
|
||||||
#[inline]
|
|
||||||
pub fn as_i32x4(self) -> I32x4 {
|
|
||||||
unsafe { I32x4(*mem::transmute::<&[u8; 16], &[i32; 4]>(&self.0)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn shuffle(self, indices: U8x16) -> U8x16 {
|
|
||||||
let mut result = [0; 16];
|
|
||||||
for index in 0..16 {
|
|
||||||
result[index] = self.0[(indices.0[index] & 0x0f) as usize]
|
|
||||||
}
|
|
||||||
U8x16(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,12 +12,195 @@ use std::arch::x86_64::{self, __m128, __m128i, _MM_FROUND_TO_NEAREST_INT};
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Add, BitXor, Index, IndexMut, Mul, Not, Sub};
|
use std::ops::{Add, BitAnd, BitOr, BitXor, Index, IndexMut, Mul, Not, Shr, Sub};
|
||||||
|
|
||||||
mod swizzle_f32x4;
|
mod swizzle_f32x4;
|
||||||
mod swizzle_i32x4;
|
mod swizzle_i32x4;
|
||||||
|
|
||||||
// 32-bit floats
|
// Two 32-bit floats
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct F32x2(pub u64);
|
||||||
|
|
||||||
|
impl F32x2 {
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new(a: f32, b: f32) -> F32x2 {
|
||||||
|
unsafe {
|
||||||
|
let a = mem::transmute::<*const f32, *const u32>(&a);
|
||||||
|
let b = mem::transmute::<*const f32, *const u32>(&b);
|
||||||
|
F32x2((*a as u64) | ((*b as u64) << 32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn splat(x: f32) -> F32x2 {
|
||||||
|
F32x2::new(x, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic operations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn approx_recip(self) -> F32x2 {
|
||||||
|
self.to_f32x4().approx_recip().xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn min(self, other: F32x2) -> F32x2 {
|
||||||
|
self.to_f32x4().min(other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn max(self, other: F32x2) -> F32x2 {
|
||||||
|
self.to_f32x4().max(other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clamp(self, min: F32x2, max: F32x2) -> F32x2 {
|
||||||
|
self.to_f32x4().clamp(min.to_f32x4(), max.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn abs(self) -> F32x2 {
|
||||||
|
self.to_f32x4().abs().xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn floor(self) -> F32x2 {
|
||||||
|
self.to_f32x4().floor().xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ceil(self) -> F32x2 {
|
||||||
|
self.to_f32x4().ceil().xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn round(self) -> F32x2 {
|
||||||
|
self.to_f32x4().round().xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn sqrt(self) -> F32x2 {
|
||||||
|
self.to_f32x4().sqrt().xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packed comparisons
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_eq(self, other: F32x2) -> U32x2 {
|
||||||
|
self.to_f32x4().packed_eq(other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_gt(self, other: F32x2) -> U32x2 {
|
||||||
|
self.to_f32x4().packed_gt(other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_lt(self, other: F32x2) -> U32x2 {
|
||||||
|
self.to_f32x4().packed_lt(other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_le(self, other: F32x2) -> U32x2 {
|
||||||
|
self.to_f32x4().packed_le(other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_f32x4(self) -> F32x4 {
|
||||||
|
unsafe { F32x4(x86_64::_mm_castsi128_ps(x86_64::_mm_cvtsi64_si128(self.0 as i64))) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_i32x2(self) -> I32x2 {
|
||||||
|
self.to_i32x4().xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_i32x4(self) -> I32x4 {
|
||||||
|
self.to_f32x4().to_i32x4()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swizzle
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yx(self) -> F32x2 {
|
||||||
|
self.to_f32x4().yx()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concatenations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn concat_xy_xy(self, other: F32x2) -> F32x4 {
|
||||||
|
self.to_f32x4().concat_xy_xy(other.to_f32x4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> F32x2 {
|
||||||
|
F32x2(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for F32x2 {
|
||||||
|
type Output = f32;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &f32 {
|
||||||
|
unsafe { &mem::transmute::<&u64, &[f32; 2]>(&self.0)[index] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut f32 {
|
||||||
|
unsafe { &mut mem::transmute::<&mut u64, &mut [f32; 2]>(&mut self.0)[index] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "<{}, {}>", self[0], self[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for F32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &F32x2) -> bool {
|
||||||
|
self.packed_eq(*other).is_all_ones()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: F32x2) -> F32x2 {
|
||||||
|
(self.to_f32x4() + other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: F32x2) -> F32x2 {
|
||||||
|
(self.to_f32x4() * other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<F32x2> for F32x2 {
|
||||||
|
type Output = F32x2;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: F32x2) -> F32x2 {
|
||||||
|
(self.to_f32x4() - other.to_f32x4()).xy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit floats
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct F32x4(pub __m128);
|
pub struct F32x4(pub __m128);
|
||||||
|
@ -126,6 +309,33 @@ impl F32x4 {
|
||||||
unsafe { I32x4(x86_64::_mm_cvtps_epi32(self.0)) }
|
unsafe { I32x4(x86_64::_mm_cvtps_epi32(self.0)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extraction
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xy(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(x86_64::_mm_cvtsi128_si64(x86_64::_mm_castps_si128(self.0)) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xw(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(x86_64::_mm_cvtsi128_si64(x86_64::_mm_castps_si128(self.xwyz().0)) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yx(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(x86_64::_mm_cvtsi128_si64(x86_64::_mm_castps_si128(self.yxwz().0)) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zy(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(x86_64::_mm_cvtsi128_si64(x86_64::_mm_castps_si128(self.zyxw().0)) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zw(self) -> F32x2 {
|
||||||
|
unsafe { F32x2(x86_64::_mm_cvtsi128_si64(x86_64::_mm_castps_si128(self.zwxy().0)) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
// Concatenations
|
// Concatenations
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -224,7 +434,140 @@ impl Sub<F32x4> for F32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32-bit signed integers
|
// Two 32-bit signed integers
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct I32x2(pub u64);
|
||||||
|
|
||||||
|
impl I32x2 {
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new(a: i32, b: i32) -> I32x2 {
|
||||||
|
unsafe {
|
||||||
|
let a = mem::transmute::<*const i32, *const u32>(&a);
|
||||||
|
let b = mem::transmute::<*const i32, *const u32>(&b);
|
||||||
|
I32x2((*a as u64) | ((*b as u64) << 32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn splat(x: i32) -> I32x2 {
|
||||||
|
I32x2::new(x, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concatenations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn concat_xy_xy(self, other: I32x2) -> I32x4 {
|
||||||
|
self.to_i32x4().concat_xy_xy(other.to_i32x4())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_i32x4(self) -> I32x4 {
|
||||||
|
unsafe { I32x4(x86_64::_mm_cvtsi64_si128(self.0 as i64)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_f32x4(self) -> F32x4 {
|
||||||
|
self.to_i32x4().to_f32x4()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts these packed integers to floats.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_f32x2(self) -> F32x2 {
|
||||||
|
self.to_f32x4().xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic operations
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn min(self, other: I32x2) -> I32x2 {
|
||||||
|
self.to_i32x4().min(other.to_i32x4()).xy()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparisons
|
||||||
|
|
||||||
|
// TODO(pcwalton): Make a `U32x2` type and use that!
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_eq(self, other: I32x2) -> U32x4 {
|
||||||
|
self.to_i32x4().packed_eq(other.to_i32x4())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_gt(self, other: I32x2) -> U32x4 {
|
||||||
|
self.to_i32x4().packed_gt(other.to_i32x4())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn packed_le(self, other: I32x2) -> U32x4 {
|
||||||
|
self.to_i32x4().packed_le(other.to_i32x4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> I32x2 {
|
||||||
|
I32x2(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for I32x2 {
|
||||||
|
type Output = i32;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &i32 {
|
||||||
|
unsafe { &mem::transmute::<&u64, &[i32; 2]>(&self.0)[index] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut i32 {
|
||||||
|
unsafe { &mut mem::transmute::<&mut u64, &mut [i32; 2]>(&mut self.0)[index] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: I32x2) -> I32x2 {
|
||||||
|
(self.to_i32x4() + other.to_i32x4()).xy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, other: I32x2) -> I32x2 {
|
||||||
|
(self.to_i32x4() - other.to_i32x4()).xy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<I32x2> for I32x2 {
|
||||||
|
type Output = I32x2;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: I32x2) -> I32x2 {
|
||||||
|
(self.to_i32x4() * other.to_i32x4()).xy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "<{}, {}>", self[0], self[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for I32x2 {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &I32x2) -> bool {
|
||||||
|
self.packed_eq(*other).is_all_ones()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit signed integers
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct I32x4(pub __m128i);
|
pub struct I32x4(pub __m128i);
|
||||||
|
@ -245,6 +588,33 @@ impl I32x4 {
|
||||||
unsafe { I32x4(x86_64::_mm_set1_epi32(x)) }
|
unsafe { I32x4(x86_64::_mm_set1_epi32(x)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extraction
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xy(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(x86_64::_mm_cvtsi128_si64(self.0) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xw(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(x86_64::_mm_cvtsi128_si64(self.xwyz().0) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn yx(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(x86_64::_mm_cvtsi128_si64(self.yxwz().0) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zy(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(x86_64::_mm_cvtsi128_si64(self.zyxw().0) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zw(self) -> I32x2 {
|
||||||
|
unsafe { I32x2(x86_64::_mm_cvtsi128_si64(self.zwxy().0) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
// Concatenations
|
// Concatenations
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -259,11 +629,6 @@ impl I32x4 {
|
||||||
|
|
||||||
// Conversions
|
// Conversions
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn as_u8x16(self) -> U8x16 {
|
|
||||||
U8x16(self.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts these packed integers to floats.
|
/// Converts these packed integers to floats.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_f32x4(self) -> F32x4 {
|
pub fn to_f32x4(self) -> F32x4 {
|
||||||
|
@ -343,6 +708,30 @@ impl Mul<I32x4> for I32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BitAnd<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn bitand(self, other: I32x4) -> I32x4 {
|
||||||
|
unsafe { I32x4(x86_64::_mm_and_si128(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn bitor(self, other: I32x4) -> I32x4 {
|
||||||
|
unsafe { I32x4(x86_64::_mm_or_si128(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shr<I32x4> for I32x4 {
|
||||||
|
type Output = I32x4;
|
||||||
|
#[inline]
|
||||||
|
fn shr(self, other: I32x4) -> I32x4 {
|
||||||
|
unsafe { I32x4(x86_64::_mm_srlv_epi32(self.0, other.0)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Debug for I32x4 {
|
impl Debug for I32x4 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||||
|
@ -357,7 +746,24 @@ impl PartialEq for I32x4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32-bit unsigned integers
|
// Two 32-bit unsigned integers
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct U32x2(pub u64);
|
||||||
|
|
||||||
|
impl U32x2 {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_all_ones(self) -> bool {
|
||||||
|
self.0 == !0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_all_zeroes(self) -> bool {
|
||||||
|
self.0 == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Four 32-bit unsigned integers
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct U32x4(pub __m128i);
|
pub struct U32x4(pub __m128i);
|
||||||
|
@ -390,6 +796,13 @@ impl U32x4 {
|
||||||
unsafe { x86_64::_mm_test_all_zeros(self.0, self.0) != 0 }
|
unsafe { x86_64::_mm_test_all_zeros(self.0, self.0) != 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extraction
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn xy(self) -> U32x2 {
|
||||||
|
unsafe { U32x2(x86_64::_mm_cvtsi128_si64(self.0) as u64) }
|
||||||
|
}
|
||||||
|
|
||||||
// Packed comparisons
|
// Packed comparisons
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -435,20 +848,3 @@ impl BitXor<U32x4> for U32x4 {
|
||||||
unsafe { U32x4(x86_64::_mm_xor_si128(self.0, other.0)) }
|
unsafe { U32x4(x86_64::_mm_xor_si128(self.0, other.0)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-bit unsigned integers
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct U8x16(pub __m128i);
|
|
||||||
|
|
||||||
impl U8x16 {
|
|
||||||
#[inline]
|
|
||||||
pub fn as_i32x4(self) -> I32x4 {
|
|
||||||
I32x4(self.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn shuffle(self, indices: U8x16) -> U8x16 {
|
|
||||||
unsafe { U8x16(x86_64::_mm_shuffle_epi8(self.0, indices.0)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ use pathfinder_content::color::ColorU;
|
||||||
use pathfinder_content::outline::Outline;
|
use pathfinder_content::outline::Outline;
|
||||||
use pathfinder_content::segment::{Segment, SegmentFlags};
|
use pathfinder_content::segment::{Segment, SegmentFlags};
|
||||||
use pathfinder_content::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_content::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle};
|
||||||
use pathfinder_content::transform::Transform2DFPathIter;
|
use pathfinder_content::transform::Transform2FPathIter;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_renderer::paint::Paint;
|
use pathfinder_renderer::paint::Paint;
|
||||||
use pathfinder_renderer::scene::{PathObject, Scene};
|
use pathfinder_renderer::scene::{PathObject, Scene};
|
||||||
|
@ -62,7 +62,7 @@ bitflags! {
|
||||||
impl BuiltSVG {
|
impl BuiltSVG {
|
||||||
// TODO(pcwalton): Allow a global transform to be set.
|
// TODO(pcwalton): Allow a global transform to be set.
|
||||||
pub fn from_tree(tree: Tree) -> BuiltSVG {
|
pub fn from_tree(tree: Tree) -> BuiltSVG {
|
||||||
let global_transform = Transform2DF::default();
|
let global_transform = Transform2F::default();
|
||||||
|
|
||||||
let mut built_svg = BuiltSVG {
|
let mut built_svg = BuiltSVG {
|
||||||
scene: Scene::new(),
|
scene: Scene::new(),
|
||||||
|
@ -87,9 +87,9 @@ impl BuiltSVG {
|
||||||
built_svg
|
built_svg
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_node(&mut self, node: &Node, transform: &Transform2DF) {
|
fn process_node(&mut self, node: &Node, transform: &Transform2F) {
|
||||||
let node_transform = usvg_transform_to_transform_2d(&node.transform());
|
let node_transform = usvg_transform_to_transform_2d(&node.transform());
|
||||||
let transform = transform.pre_mul(&node_transform);
|
let transform = node_transform * *transform;
|
||||||
|
|
||||||
match *node.borrow() {
|
match *node.borrow() {
|
||||||
NodeKind::Group(ref group) => {
|
NodeKind::Group(ref group) => {
|
||||||
|
@ -119,7 +119,7 @@ impl BuiltSVG {
|
||||||
));
|
));
|
||||||
|
|
||||||
let path = UsvgPathToSegments::new(path.segments.iter().cloned());
|
let path = UsvgPathToSegments::new(path.segments.iter().cloned());
|
||||||
let path = Transform2DFPathIter::new(path, &transform);
|
let path = Transform2FPathIter::new(path, &transform);
|
||||||
let outline = Outline::from_segments(path);
|
let outline = Outline::from_segments(path);
|
||||||
|
|
||||||
let name = format!("Fill({})", node.id());
|
let name = format!("Fill({})", node.id());
|
||||||
|
@ -266,8 +266,8 @@ fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> RectF {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usvg_transform_to_transform_2d(transform: &UsvgTransform) -> Transform2DF {
|
fn usvg_transform_to_transform_2d(transform: &UsvgTransform) -> Transform2F {
|
||||||
Transform2DF::row_major(
|
Transform2F::row_major(
|
||||||
transform.a as f32,
|
transform.a as f32,
|
||||||
transform.b as f32,
|
transform.b as f32,
|
||||||
transform.c as f32,
|
transform.c as f32,
|
||||||
|
@ -318,7 +318,7 @@ where
|
||||||
}
|
}
|
||||||
UsvgPathSegment::LineTo { x, y } => {
|
UsvgPathSegment::LineTo { x, y } => {
|
||||||
let to = Vector2F::new(x as f32, y as f32);
|
let to = Vector2F::new(x as f32, y as f32);
|
||||||
let mut segment = Segment::line(&LineSegment2F::new(self.last_subpath_point, to));
|
let mut segment = Segment::line(LineSegment2F::new(self.last_subpath_point, to));
|
||||||
if self.just_moved {
|
if self.just_moved {
|
||||||
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
|
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
|
||||||
}
|
}
|
||||||
|
@ -338,8 +338,8 @@ where
|
||||||
let ctrl1 = Vector2F::new(x2 as f32, y2 as f32);
|
let ctrl1 = Vector2F::new(x2 as f32, y2 as f32);
|
||||||
let to = Vector2F::new(x as f32, y as f32);
|
let to = Vector2F::new(x as f32, y as f32);
|
||||||
let mut segment = Segment::cubic(
|
let mut segment = Segment::cubic(
|
||||||
&LineSegment2F::new(self.last_subpath_point, to),
|
LineSegment2F::new(self.last_subpath_point, to),
|
||||||
&LineSegment2F::new(ctrl0, ctrl1),
|
LineSegment2F::new(ctrl0, ctrl1),
|
||||||
);
|
);
|
||||||
if self.just_moved {
|
if self.just_moved {
|
||||||
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
|
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
|
||||||
|
@ -349,7 +349,7 @@ where
|
||||||
Some(segment)
|
Some(segment)
|
||||||
}
|
}
|
||||||
UsvgPathSegment::ClosePath => {
|
UsvgPathSegment::ClosePath => {
|
||||||
let mut segment = Segment::line(&LineSegment2F::new(
|
let mut segment = Segment::line(LineSegment2F::new(
|
||||||
self.last_subpath_point,
|
self.last_subpath_point,
|
||||||
self.first_subpath_point,
|
self.first_subpath_point,
|
||||||
));
|
));
|
||||||
|
|
|
@ -93,13 +93,13 @@ impl Shape {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn first(&self) -> &LineSegment {
|
fn first(&self) -> LineSegment {
|
||||||
&self.outline.first().unwrap()
|
self.outline.first().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn last(&self) -> &LineSegment {
|
fn last(&self) -> LineSegment {
|
||||||
&self.outline.last().unwrap()
|
self.outline.last().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -15,7 +15,7 @@ use font_kit::loader::Loader;
|
||||||
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
|
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
|
||||||
use pathfinder_content::outline::{Contour, Outline};
|
use pathfinder_content::outline::{Contour, Outline};
|
||||||
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||||
use pathfinder_geometry::transform2d::Transform2DF;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_renderer::paint::PaintId;
|
use pathfinder_renderer::paint::PaintId;
|
||||||
use pathfinder_renderer::scene::{PathObject, Scene};
|
use pathfinder_renderer::scene::{PathObject, Scene};
|
||||||
|
@ -27,7 +27,7 @@ pub trait SceneExt {
|
||||||
fn push_glyph<F>(&mut self,
|
fn push_glyph<F>(&mut self,
|
||||||
font: &F,
|
font: &F,
|
||||||
glyph_id: u32,
|
glyph_id: u32,
|
||||||
transform: &Transform2DF,
|
transform: &Transform2F,
|
||||||
render_mode: TextRenderMode,
|
render_mode: TextRenderMode,
|
||||||
hinting_options: HintingOptions,
|
hinting_options: HintingOptions,
|
||||||
paint_id: PaintId)
|
paint_id: PaintId)
|
||||||
|
@ -37,7 +37,7 @@ pub trait SceneExt {
|
||||||
fn push_layout(&mut self,
|
fn push_layout(&mut self,
|
||||||
layout: &Layout,
|
layout: &Layout,
|
||||||
style: &TextStyle,
|
style: &TextStyle,
|
||||||
transform: &Transform2DF,
|
transform: &Transform2F,
|
||||||
render_mode: TextRenderMode,
|
render_mode: TextRenderMode,
|
||||||
hinting_options: HintingOptions,
|
hinting_options: HintingOptions,
|
||||||
paint_id: PaintId)
|
paint_id: PaintId)
|
||||||
|
@ -47,7 +47,7 @@ pub trait SceneExt {
|
||||||
text: &str,
|
text: &str,
|
||||||
style: &TextStyle,
|
style: &TextStyle,
|
||||||
collection: &FontCollection,
|
collection: &FontCollection,
|
||||||
transform: &Transform2DF,
|
transform: &Transform2F,
|
||||||
render_mode: TextRenderMode,
|
render_mode: TextRenderMode,
|
||||||
hinting_options: HintingOptions,
|
hinting_options: HintingOptions,
|
||||||
paint_id: PaintId)
|
paint_id: PaintId)
|
||||||
|
@ -59,7 +59,7 @@ impl SceneExt for Scene {
|
||||||
fn push_glyph<F>(&mut self,
|
fn push_glyph<F>(&mut self,
|
||||||
font: &F,
|
font: &F,
|
||||||
glyph_id: u32,
|
glyph_id: u32,
|
||||||
transform: &Transform2DF,
|
transform: &Transform2F,
|
||||||
render_mode: TextRenderMode,
|
render_mode: TextRenderMode,
|
||||||
hinting_options: HintingOptions,
|
hinting_options: HintingOptions,
|
||||||
paint_id: PaintId)
|
paint_id: PaintId)
|
||||||
|
@ -82,7 +82,7 @@ impl SceneExt for Scene {
|
||||||
fn push_layout(&mut self,
|
fn push_layout(&mut self,
|
||||||
layout: &Layout,
|
layout: &Layout,
|
||||||
style: &TextStyle,
|
style: &TextStyle,
|
||||||
transform: &Transform2DF,
|
transform: &Transform2F,
|
||||||
render_mode: TextRenderMode,
|
render_mode: TextRenderMode,
|
||||||
hinting_options: HintingOptions,
|
hinting_options: HintingOptions,
|
||||||
paint_id: PaintId)
|
paint_id: PaintId)
|
||||||
|
@ -93,8 +93,7 @@ impl SceneExt for Scene {
|
||||||
// FIXME(pcwalton): Cache this!
|
// FIXME(pcwalton): Cache this!
|
||||||
let scale = style.size / (font.metrics().units_per_em as f32);
|
let scale = style.size / (font.metrics().units_per_em as f32);
|
||||||
let scale = Vector2F::new(scale, -scale);
|
let scale = Vector2F::new(scale, -scale);
|
||||||
let transform =
|
let transform = *transform * Transform2F::from_scale(scale).translate(offset);
|
||||||
Transform2DF::from_scale(scale).post_mul(transform).post_translate(offset);
|
|
||||||
self.push_glyph(font,
|
self.push_glyph(font,
|
||||||
glyph.glyph_id,
|
glyph.glyph_id,
|
||||||
&transform,
|
&transform,
|
||||||
|
@ -110,7 +109,7 @@ impl SceneExt for Scene {
|
||||||
text: &str,
|
text: &str,
|
||||||
style: &TextStyle,
|
style: &TextStyle,
|
||||||
collection: &FontCollection,
|
collection: &FontCollection,
|
||||||
transform: &Transform2DF,
|
transform: &Transform2F,
|
||||||
render_mode: TextRenderMode,
|
render_mode: TextRenderMode,
|
||||||
hinting_options: HintingOptions,
|
hinting_options: HintingOptions,
|
||||||
paint_id: PaintId)
|
paint_id: PaintId)
|
||||||
|
@ -129,11 +128,11 @@ pub enum TextRenderMode {
|
||||||
struct OutlinePathBuilder {
|
struct OutlinePathBuilder {
|
||||||
outline: Outline,
|
outline: Outline,
|
||||||
current_contour: Contour,
|
current_contour: Contour,
|
||||||
transform: Transform2DF,
|
transform: Transform2F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutlinePathBuilder {
|
impl OutlinePathBuilder {
|
||||||
fn new(transform: &Transform2DF) -> OutlinePathBuilder {
|
fn new(transform: &Transform2F) -> OutlinePathBuilder {
|
||||||
OutlinePathBuilder {
|
OutlinePathBuilder {
|
||||||
outline: Outline::new(),
|
outline: Outline::new(),
|
||||||
current_contour: Contour::new(),
|
current_contour: Contour::new(),
|
||||||
|
@ -148,7 +147,7 @@ impl OutlinePathBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_point(&self, point: Point2D<f32>) -> Vector2F {
|
fn convert_point(&self, point: Point2D<f32>) -> Vector2F {
|
||||||
self.transform.transform_point(Vector2F::new(point.x, point.y))
|
self.transform * Vector2F::new(point.x, point.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
primitive,
|
primitive,
|
||||||
uniforms: &[
|
uniforms: &[
|
||||||
(&self.solid_program.framebuffer_size_uniform,
|
(&self.solid_program.framebuffer_size_uniform,
|
||||||
UniformData::Vec2(self.framebuffer_size.0.to_f32x4())),
|
UniformData::Vec2(self.framebuffer_size.0.to_f32x2())),
|
||||||
(&self.solid_program.color_uniform, get_color_uniform(color)),
|
(&self.solid_program.color_uniform, get_color_uniform(color)),
|
||||||
],
|
],
|
||||||
textures: &[],
|
textures: &[],
|
||||||
|
@ -414,11 +414,11 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
textures: &[&texture],
|
textures: &[&texture],
|
||||||
uniforms: &[
|
uniforms: &[
|
||||||
(&self.texture_program.framebuffer_size_uniform,
|
(&self.texture_program.framebuffer_size_uniform,
|
||||||
UniformData::Vec2(self.framebuffer_size.0.to_f32x4())),
|
UniformData::Vec2(self.framebuffer_size.0.to_f32x2())),
|
||||||
(&self.texture_program.color_uniform, get_color_uniform(color)),
|
(&self.texture_program.color_uniform, get_color_uniform(color)),
|
||||||
(&self.texture_program.texture_uniform, UniformData::TextureUnit(0)),
|
(&self.texture_program.texture_uniform, UniformData::TextureUnit(0)),
|
||||||
(&self.texture_program.texture_size_uniform,
|
(&self.texture_program.texture_size_uniform,
|
||||||
UniformData::Vec2(device.texture_size(&texture).0.to_f32x4()))
|
UniformData::Vec2(device.texture_size(&texture).0.to_f32x2()))
|
||||||
],
|
],
|
||||||
viewport: RectI::new(Vector2I::default(), self.framebuffer_size),
|
viewport: RectI::new(Vector2I::default(), self.framebuffer_size),
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "svg2pdf"
|
name = "convert"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Sebastian Köln <sebk@rynx.org>"]
|
authors = ["Sebastian Köln <sebk@rynx.org>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
@ -7,6 +7,6 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
pathfinder_export = { path = "../../export" }
|
||||||
pathfinder_svg = { path = "../../svg" }
|
pathfinder_svg = { path = "../../svg" }
|
||||||
pathfinder_pdf = { path = "../../pdf" }
|
|
||||||
usvg = "*"
|
usvg = "*"
|
|
@ -0,0 +1,27 @@
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, BufWriter};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use pathfinder_svg::BuiltSVG;
|
||||||
|
use pathfinder_export::{Export, FileFormat};
|
||||||
|
use usvg::{Tree, Options};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut args = std::env::args_os().skip(1);
|
||||||
|
let input = PathBuf::from(args.next().expect("no input given"));
|
||||||
|
let output = PathBuf::from(args.next().expect("no output given"));
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
File::open(input)?.read_to_end(&mut data)?;
|
||||||
|
let svg = BuiltSVG::from_tree(Tree::from_data(&data, &Options::default()).unwrap());
|
||||||
|
|
||||||
|
let scene = &svg.scene;
|
||||||
|
let mut writer = BufWriter::new(File::create(&output)?);
|
||||||
|
let format = match output.extension().and_then(|s| s.to_str()) {
|
||||||
|
Some("pdf") => FileFormat::PDF,
|
||||||
|
Some("ps") => FileFormat::PS,
|
||||||
|
_ => return Err("output filename must have .ps or .pdf extension".into())
|
||||||
|
};
|
||||||
|
scene.export(&mut writer, format).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue