merge with master

This commit is contained in:
Sebastian Köln 2019-06-24 18:31:13 +03:00
commit 0a5c4007f9
163 changed files with 5856 additions and 1701 deletions

2
.gitignore vendored
View File

@ -6,6 +6,8 @@ target
/site/dist
node_modules
/examples/c_canvas_minimal/build
/shaders/build
/c/build
# Editors
*.swp

635
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,23 +2,29 @@
members = [
"c",
"canvas",
"content",
"demo/android/rust",
"demo/common",
"demo/magicleap",
"demo/native",
"examples/canvas_glutin_minimal",
"examples/canvas_metal_minimal",
"examples/canvas_minimal",
"examples/canvas_moire",
"examples/canvas_text",
"examples/lottie_basic",
"examples/svg2pdf",
"examples/swf_basic",
"geometry",
"gl",
"gpu",
"lottie",
"pdf",
"metal",
"renderer",
"simd",
"svg",
"swf",
"text",
"ui",
"utils/area-lut",

View File

@ -3,16 +3,23 @@ name = "pathfinder_c"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
build = "build.rs"
[lib]
crate-type = ["staticlib"]
[dependencies]
font-kit = "0.2"
foreign-types = "0.3"
gl = "0.6"
libc = "0.2"
[dependencies.pathfinder_canvas]
path = "../canvas"
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"
@ -27,3 +34,12 @@ path = "../renderer"
[dependencies.pathfinder_simd]
path = "../simd"
[target.'cfg(target_os = "macos")'.dependencies]
metal = "0.14"
[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal]
path = "../metal"
[build-dependencies]
cbindgen = "0.8"

20
c/build.rs Normal file
View File

@ -0,0 +1,20 @@
// pathfinder/c/build.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use cbindgen;
use std::env;
use std::fs;
fn main() {
fs::create_dir_all("build/include/pathfinder").expect("Failed to create directories!");
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
cbindgen::generate(crate_dir).expect("cbindgen failed!")
.write_to_file("build/include/pathfinder/pathfinder.h");
}

19
c/cbindgen.toml Normal file
View File

@ -0,0 +1,19 @@
language = "C"
header = """\
/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */
extern \"C\" {
"""
trailer = "}"
include_guard = "PF_PATHFINDER_H"
include_version = true
[parse]
parse_deps = true
include = [
"pathfinder_canvas",
"pathfinder_content",
"pathfinder_geometry",
"pathfinder_gl",
"pathfinder_renderer",
]

View File

@ -1,171 +0,0 @@
// pathfinder/c/include/pathfinder/pathfinder.h
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#ifndef PF_PATHFINDER_H
#define PF_PATHFINDER_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// Macros
// `canvas`
#define PF_LINE_CAP_BUTT 0
#define PF_LINE_CAP_SQUARE 1
#define PF_LINE_CAP_ROUND 2
// `gl`
#define PF_GL_VERSION_GL3 0
#define PF_GL_VERSION_GLES3 1
// `gpu`
#define PF_CLEAR_FLAGS_HAS_COLOR 0x1
#define PF_CLEAR_FLAGS_HAS_DEPTH 0x2
#define PF_CLEAR_FLAGS_HAS_STENCIL 0x4
#define PF_CLEAR_FLAGS_HAS_RECT 0x8
// Types
// `canvas`
struct PFCanvas;
typedef struct PFCanvas *PFCanvasRef;
struct PFPath;
typedef struct PFPath *PFPathRef;
struct PFCanvasFontContext;
typedef struct PFCanvasFontContext *PFCanvasFontContextRef;
typedef uint8_t PFLineCap;
// `geometry`
struct PFColorF {
float r, g, b, a;
};
typedef struct PFColorF PFColorF;
struct PFVector2F {
float x, y;
};
typedef struct PFVector2F PFVector2F;
struct PFVector2I {
int32_t x, y;
};
typedef struct PFVector2I PFVector2I;
struct PFRectF {
PFVector2F origin, lower_right;
};
typedef struct PFRectF PFRectF;
struct PFRectI {
PFVector2I origin, lower_right;
};
typedef struct PFRectI PFRectI;
// `gl`
struct PFGLDevice;
typedef struct PFGLDevice *PFGLDeviceRef;
struct PFGLDestFramebuffer;
typedef struct PFGLDestFramebuffer *PFGLDestFramebufferRef;
typedef const void *(*PFGLFunctionLoader)(const char *data, void *userdata);
struct PFGLRenderer;
typedef struct PFGLRenderer *PFGLRendererRef;
typedef uint32_t PFGLVersion;
// `gpu`
typedef uint8_t PFClearFlags;
struct PFClearParams {
PFColorF color;
float depth;
uint8_t stencil;
PFRectI rect;
PFClearFlags flags;
};
typedef struct PFClearParams PFClearParams;
struct PFResourceLoader;
typedef struct PFResourceLoader *PFResourceLoaderRef;
// `renderer`
struct PFRenderOptions {
uint32_t placeholder;
};
typedef struct PFRenderOptions PFRenderOptions;
struct PFScene;
typedef struct PFScene *PFSceneRef;
struct PFSceneProxy;
typedef struct PFSceneProxy *PFSceneProxyRef;
// Functions
// `canvas`
PFCanvasRef PFCanvasCreate(PFCanvasFontContextRef font_context, const PFVector2F *size);
void PFCanvasDestroy(PFCanvasRef canvas);
PFCanvasFontContextRef PFCanvasFontContextCreate();
void PFCanvasFontContextDestroy(PFCanvasFontContextRef font_context);
PFCanvasFontContextRef PFCanvasFontContextClone(PFCanvasFontContextRef font_context);
PFSceneRef PFCanvasCreateScene(PFCanvasRef canvas);
void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect);
void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect);
void PFCanvasSetLineWidth(PFCanvasRef canvas, float new_line_width);
void PFCanvasSetLineCap(PFCanvasRef canvas, PFLineCap new_line_cap);
void PFCanvasFillPath(PFCanvasRef canvas, PFPathRef path);
void PFCanvasStrokePath(PFCanvasRef canvas, PFPathRef path);
PFPathRef PFPathCreate();
void PFPathDestroy(PFPathRef path);
PFPathRef PFPathClone(PFPathRef path);
void PFPathMoveTo(PFPathRef path, const PFVector2F *to);
void PFPathLineTo(PFPathRef path, const PFVector2F *to);
void PFPathQuadraticCurveTo(PFPathRef path, const PFVector2F *ctrl, const PFVector2F *to);
void PFPathBezierCurveTo(PFPathRef path,
const PFVector2F *ctrl0,
const PFVector2F *ctrl1,
const PFVector2F *to);
void PFPathClosePath(PFPathRef path);
// `gl`
PFGLDestFramebufferRef PFGLDestFramebufferCreateFullWindow(const PFVector2I *window_size);
void PFGLDestFramebufferDestroy(PFGLDestFramebufferRef dest_framebuffer);
PFGLDeviceRef PFGLDeviceCreate(PFGLVersion version, uint32_t default_framebuffer);
void PFGLDeviceDestroy(PFGLDeviceRef device);
void PFGLDeviceClear(PFGLDeviceRef device, const PFClearParams *params);
void PFGLLoadWith(PFGLFunctionLoader loader, void *userdata);
PFGLRendererRef PFGLRendererCreate(PFGLDeviceRef device,
PFResourceLoaderRef resources,
PFGLDestFramebufferRef dest_framebuffer);
void PFGLRendererDestroy(PFGLRendererRef renderer);
/// Returns a borrowed reference to the device.
PFGLDeviceRef PFGLRendererGetDevice(PFGLRendererRef renderer);
void PFSceneProxyBuildAndRenderGL(PFSceneProxyRef scene_proxy,
PFGLRendererRef renderer,
const PFRenderOptions *options);
// `gpu`
PFResourceLoaderRef PFFilesystemResourceLoaderLocate();
void PFResourceLoaderDestroy(PFResourceLoaderRef loader);
// `renderer`
PFSceneProxyRef PFSceneProxyCreateFromSceneAndRayonExecutor(PFSceneRef scene);
void PFSceneProxyDestroy(PFSceneProxyRef scene_proxy);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -10,42 +10,89 @@
//! C bindings to Pathfinder.
use font_kit::handle::Handle;
use foreign_types::ForeignTypeRef;
use gl;
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::basic::rect::{RectF, RectI};
use pathfinder_geometry::color::ColorF;
use pathfinder_geometry::stroke::LineCap;
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin};
use pathfinder_canvas::{Path2D, TextMetrics};
use pathfinder_content::color::{ColorF, ColorU};
use pathfinder_content::outline::ArcDirection;
use pathfinder_content::stroke::LineCap;
use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader};
use pathfinder_gpu::{ClearParams, Device};
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer};
use pathfinder_renderer::options::RenderOptions;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use pathfinder_renderer::scene::Scene;
use pathfinder_simd::default::F32x4;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::slice;
use std::str;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use metal::{CAMetalLayer, CoreAnimationLayerRef};
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice;
// Constants
// `canvas`
pub const PF_LINE_CAP_BUTT: u8 = 0;
pub const PF_LINE_CAP_SQUARE: u8 = 1;
pub const PF_LINE_CAP_ROUND: u8 = 2;
pub const PF_CLEAR_FLAGS_HAS_COLOR: u8 = 0x1;
pub const PF_CLEAR_FLAGS_HAS_DEPTH: u8 = 0x2;
pub const PF_CLEAR_FLAGS_HAS_STENCIL: u8 = 0x4;
pub const PF_CLEAR_FLAGS_HAS_RECT: u8 = 0x8;
pub const PF_LINE_JOIN_MITER: u8 = 0;
pub const PF_LINE_JOIN_BEVEL: u8 = 1;
pub const PF_LINE_JOIN_ROUND: u8 = 2;
// `content`
pub const PF_ARC_DIRECTION_CW: u8 = 0;
pub const PF_ARC_DIRECTION_CCW: u8 = 1;
// `renderer`
pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1;
// Types
// External: `font-kit`
pub type FKHandleRef = *mut Handle;
// `canvas`
pub type PFCanvasRef = *mut CanvasRenderingContext2D;
pub type PFPathRef = *mut Path2D;
pub type PFCanvasFontContextRef = *mut CanvasFontContext;
pub type PFFillStyleRef = *mut FillStyle;
pub type PFLineCap = u8;
pub type PFLineJoin = u8;
pub type PFArcDirection = u8;
#[repr(C)]
pub struct PFTextMetrics {
pub width: f32,
}
// `content`
#[repr(C)]
pub struct PFColorF {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
#[repr(C)]
pub struct PFColorU {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
// `geometry`
#[repr(C)]
@ -68,13 +115,6 @@ pub struct PFRectI {
pub origin: PFVector2I,
pub lower_right: PFVector2I,
}
#[repr(C)]
pub struct PFColorF {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
// `gl`
pub type PFGLDeviceRef = *mut GLDevice;
@ -84,25 +124,30 @@ pub type PFGLFunctionLoader = extern "C" fn(name: *const c_char, userdata: *mut
// `gpu`
pub type PFGLDestFramebufferRef = *mut DestFramebuffer<GLDevice>;
pub type PFGLRendererRef = *mut Renderer<GLDevice>;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
pub type PFMetalDestFramebufferRef = *mut DestFramebuffer<MetalDevice>;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
pub type PFMetalRendererRef = *mut Renderer<MetalDevice>;
// FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is
// stable?
pub type PFResourceLoaderRef = *mut Box<dyn ResourceLoader>;
#[repr(C)]
pub struct PFClearParams {
pub color: PFColorF,
pub depth: f32,
pub stencil: u8,
pub rect: PFRectI,
pub flags: PFClearFlags,
}
pub type PFClearFlags = u8;
// `metal`
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
pub type PFMetalDeviceRef = *mut MetalDevice;
// `renderer`
pub type PFSceneRef = *mut Scene;
pub type PFSceneProxyRef = *mut SceneProxy;
#[repr(C)]
pub struct PFRendererOptions {
pub background_color: PFColorF,
pub flags: PFRendererOptionsFlags,
}
pub type PFRendererOptionsFlags = u8;
// TODO(pcwalton)
#[repr(C)]
pub struct PFRenderOptions {
pub struct PFBuildOptions {
pub placeholder: u32,
}
@ -123,8 +168,18 @@ pub unsafe extern "C" fn PFCanvasDestroy(canvas: PFCanvasRef) {
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextCreate() -> PFCanvasFontContextRef {
Box::into_raw(Box::new(CanvasFontContext::new()))
pub unsafe extern "C" fn PFCanvasFontContextCreateWithSystemSource() -> PFCanvasFontContextRef {
Box::into_raw(Box::new(CanvasFontContext::from_system_source()))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextCreateWithFonts(fonts: *const FKHandleRef,
font_count: usize)
-> PFCanvasFontContextRef {
let fonts = slice::from_raw_parts(fonts, font_count);
Box::into_raw(Box::new(CanvasFontContext::from_fonts(fonts.into_iter().map(|font| {
(**font).clone()
}))))
}
#[no_mangle]
@ -144,6 +199,8 @@ pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef
Box::into_raw(Box::new(Box::from_raw(canvas).into_scene()))
}
// Drawing rectangles
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFillRect(canvas: PFCanvasRef, rect: *const PFRectF) {
(*canvas).fill_rect((*rect).to_rust())
@ -154,6 +211,33 @@ pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PF
(*canvas).stroke_rect((*rect).to_rust())
}
// Drawing text
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFillText(canvas: PFCanvasRef,
string: *const c_char,
string_len: usize,
position: *const PFVector2F) {
(*canvas).fill_text(to_rust_string(&string, string_len), (*position).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasStrokeText(canvas: PFCanvasRef,
string: *const c_char,
string_len: usize,
position: *const PFVector2F) {
(*canvas).stroke_text(to_rust_string(&string, string_len), (*position).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasMeasureText(canvas: PFCanvasRef,
string: *const c_char,
string_len: usize,
out_text_metrics: *mut PFTextMetrics) {
debug_assert!(!out_text_metrics.is_null());
*out_text_metrics = (*canvas).measure_text(to_rust_string(&string, string_len)).to_c()
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineWidth(canvas: PFCanvasRef, new_line_width: f32) {
(*canvas).set_line_width(new_line_width)
@ -168,6 +252,55 @@ pub unsafe extern "C" fn PFCanvasSetLineCap(canvas: PFCanvasRef, new_line_cap: P
});
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineJoin(canvas: PFCanvasRef, new_line_join: PFLineJoin) {
(*canvas).set_line_join(match new_line_join {
PF_LINE_JOIN_BEVEL => LineJoin::Bevel,
PF_LINE_JOIN_ROUND => LineJoin::Round,
_ => LineJoin::Miter,
});
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetMiterLimit(canvas: PFCanvasRef, new_miter_limit: f32) {
(*canvas).set_miter_limit(new_miter_limit);
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineDash(canvas: PFCanvasRef,
new_line_dashes: *const f32,
new_line_dash_count: usize) {
(*canvas).set_line_dash(slice::from_raw_parts(new_line_dashes, new_line_dash_count).to_vec())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offset: f32) {
(*canvas).set_line_dash_offset(new_offset)
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef,
postscript_name: *const c_char,
postscript_name_len: usize) {
(*canvas).set_font_by_postscript_name(to_rust_string(&postscript_name, postscript_name_len))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFontSize(canvas: PFCanvasRef, new_font_size: f32) {
(*canvas).set_font_size(new_font_size)
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFillStyle(canvas: PFCanvasRef, fill_style: PFFillStyleRef) {
(*canvas).set_fill_style(*fill_style)
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetStrokeStyle(canvas: PFCanvasRef,
stroke_style: PFFillStyleRef) {
(*canvas).set_stroke_style(*stroke_style)
}
/// Consumes the path.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) {
@ -220,11 +353,55 @@ pub unsafe extern "C" fn PFPathBezierCurveTo(path: PFPathRef,
(*path).bezier_curve_to((*ctrl0).to_rust(), (*ctrl1).to_rust(), (*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathArc(path: PFPathRef,
center: *const PFVector2F,
radius: f32,
start_angle: f32,
end_angle: f32,
direction: PFArcDirection) {
let direction = if direction == 0 { ArcDirection::CW } else { ArcDirection::CCW };
(*path).arc((*center).to_rust(), radius, start_angle, end_angle, direction)
}
#[no_mangle]
pub unsafe extern "C" fn PFPathArcTo(path: PFPathRef,
ctrl: *const PFVector2F,
to: *const PFVector2F,
radius: f32) {
(*path).arc_to((*ctrl).to_rust(), (*to).to_rust(), radius)
}
#[no_mangle]
pub unsafe extern "C" fn PFPathRect(path: PFPathRef, rect: *const PFRectF) {
(*path).rect((*rect).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathEllipse(path: PFPathRef,
center: *const PFVector2F,
axes: *const PFVector2F,
rotation: f32,
start_angle: f32,
end_angle: f32) {
(*path).ellipse((*center).to_rust(), (*axes).to_rust(), rotation, start_angle, end_angle)
}
#[no_mangle]
pub unsafe extern "C" fn PFPathClosePath(path: PFPathRef) {
(*path).close_path()
}
#[no_mangle]
pub unsafe extern "C" fn PFFillStyleCreateColor(color: *const PFColorU) -> PFFillStyleRef {
Box::into_raw(Box::new(FillStyle::Color((*color).to_rust())))
}
#[no_mangle]
pub unsafe extern "C" fn PFFillStyleDestroy(fill_style: PFFillStyleRef) {
drop(Box::from_raw(fill_style))
}
// `gl`
#[no_mangle]
@ -252,11 +429,6 @@ pub unsafe extern "C" fn PFGLDeviceDestroy(device: PFGLDeviceRef) {
drop(Box::from_raw(device))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLDeviceClear(device: PFGLDeviceRef, params: *const PFClearParams) {
(*device).clear(&(*params).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFResourceLoaderDestroy(loader: PFResourceLoaderRef) {
drop(Box::from_raw(loader))
@ -279,11 +451,13 @@ pub unsafe extern "C" fn PFGLDestFramebufferDestroy(dest_framebuffer: PFGLDestFr
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef,
resources: PFResourceLoaderRef,
dest_framebuffer: PFGLDestFramebufferRef)
dest_framebuffer: PFGLDestFramebufferRef,
options: *const PFRendererOptions)
-> PFGLRendererRef {
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
&**resources,
*Box::from_raw(dest_framebuffer))))
*Box::from_raw(dest_framebuffer),
(*options).to_rust())))
}
#[no_mangle]
@ -296,11 +470,74 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG
&mut (*renderer).device
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I)
-> PFMetalDestFramebufferRef {
Box::into_raw(Box::new(DestFramebuffer::full_window((*window_size).to_rust())))
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDestFramebufferDestroy(dest_framebuffer:
PFMetalDestFramebufferRef) {
drop(Box::from_raw(dest_framebuffer))
}
/// Takes ownership of `device` and `dest_framebuffer`, but not `resources`.
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef,
resources: PFResourceLoaderRef,
dest_framebuffer: PFMetalDestFramebufferRef,
options: *const PFRendererOptions)
-> PFMetalRendererRef {
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
&**resources,
*Box::from_raw(dest_framebuffer),
(*options).to_rust())))
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalRendererDestroy(renderer: PFMetalRendererRef) {
drop(Box::from_raw(renderer))
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalRendererGetDevice(renderer: PFMetalRendererRef) -> PFMetalDeviceRef {
&mut (*renderer).device
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef,
renderer: PFGLRendererRef,
options: *const PFRenderOptions) {
(*scene_proxy).build_and_render(&mut *renderer, (*options).to_rust())
build_options: *const PFBuildOptions) {
(*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust())
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderMetal(scene_proxy: PFSceneProxyRef,
renderer: PFMetalRendererRef,
build_options: *const PFBuildOptions) {
(*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust())
}
// `metal`
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDeviceCreate(layer: *mut CAMetalLayer)
-> PFMetalDeviceRef {
Box::into_raw(Box::new(MetalDevice::new(CoreAnimationLayerRef::from_ptr(layer))))
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDeviceDestroy(device: PFMetalDeviceRef) {
drop(Box::from_raw(device))
}
// `renderer`
@ -321,7 +558,26 @@ pub unsafe extern "C" fn PFSceneProxyDestroy(scene_proxy: PFSceneProxyRef) {
drop(Box::from_raw(scene_proxy))
}
// Helpers for `geometry`
// Helpers for `canvas`
unsafe fn to_rust_string(ptr: &*const c_char, mut len: usize) -> &str {
if len == 0 {
len = libc::strlen(*ptr);
}
str::from_utf8(slice::from_raw_parts(*ptr as *const u8, len)).unwrap()
}
trait TextMetricsExt {
fn to_c(&self) -> PFTextMetrics;
}
impl TextMetricsExt for TextMetrics {
fn to_c(&self) -> PFTextMetrics {
PFTextMetrics { width: self.width }
}
}
// Helpers for `content`
impl PFColorF {
#[inline]
@ -330,6 +586,15 @@ impl PFColorF {
}
}
impl PFColorU {
#[inline]
pub fn to_rust(&self) -> ColorU {
ColorU { r: self.r, g: self.g, b: self.b, a: self.a }
}
}
// Helpers for `geometry`
impl PFRectF {
#[inline]
pub fn to_rust(&self) -> RectF {
@ -358,28 +623,14 @@ impl PFVector2I {
}
}
// Helpers for `gpu`
// Helpers for `renderer`
impl PFClearParams {
pub fn to_rust(&self) -> ClearParams {
ClearParams {
color: if (self.flags & PF_CLEAR_FLAGS_HAS_COLOR) != 0 {
Some(self.color.to_rust())
} else {
None
},
rect: if (self.flags & PF_CLEAR_FLAGS_HAS_RECT) != 0 {
Some(self.rect.to_rust())
} else {
None
},
depth: if (self.flags & PF_CLEAR_FLAGS_HAS_DEPTH) != 0 {
Some(self.depth)
} else {
None
},
stencil: if (self.flags & PF_CLEAR_FLAGS_HAS_STENCIL) != 0 {
Some(self.stencil)
impl PFRendererOptions {
pub fn to_rust(&self) -> RendererOptions {
let has_background_color = self.flags & PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR;
RendererOptions {
background_color: if has_background_color != 0 {
Some(self.background_color.to_rust())
} else {
None
},
@ -387,10 +638,8 @@ impl PFClearParams {
}
}
// Helpers for `renderer`
impl PFRenderOptions {
pub fn to_rust(&self) -> RenderOptions {
RenderOptions::default()
impl PFBuildOptions {
pub fn to_rust(&self) -> BuildOptions {
BuildOptions::default()
}
}

View File

@ -8,7 +8,10 @@ edition = "2018"
crate-type = ["rlib", "staticlib"]
[dependencies]
font-kit = "0.1"
font-kit = "0.2"
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"
@ -21,4 +24,4 @@ path = "../text"
[dependencies.skribo]
git = "https://github.com/linebender/skribo.git"
rev = "a89e9ca99e0d6736ea1b7754517f4df14fd96a2b"
rev = "a2d683856ba1f2d0095b12dd7823d1602a87614e"

View File

@ -11,24 +11,28 @@
//! A simple API for Pathfinder that mirrors a subset of HTML canvas.
use font_kit::family_name::FamilyName;
use font_kit::handle::Handle;
use font_kit::hinting::HintingOptions;
use font_kit::loaders::default::Font;
use font_kit::properties::Properties;
use font_kit::source::SystemSource;
use pathfinder_geometry::basic::line_segment::LineSegment2F;
use pathfinder_geometry::basic::vector::Vector2F;
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::basic::transform2d::Transform2DF;
use pathfinder_geometry::color::ColorU;
use pathfinder_geometry::dash::OutlineDash;
use pathfinder_geometry::outline::{ArcDirection, Contour, Outline};
use pathfinder_geometry::stroke::{LineCap, LineJoin as StrokeLineJoin};
use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle};
use font_kit::source::{Source, SystemSource};
use font_kit::sources::mem::MemSource;
use pathfinder_content::color::ColorU;
use pathfinder_content::dash::OutlineDash;
use pathfinder_content::outline::{ArcDirection, Contour, Outline};
use pathfinder_content::stroke::{LineCap, LineJoin as StrokeLineJoin};
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::vector::Vector2F;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_renderer::paint::{Paint, PaintId};
use pathfinder_renderer::scene::{PathObject, Scene};
use pathfinder_text::{SceneExt, TextRenderMode};
use skribo::{FontCollection, FontFamily, Layout, TextStyle};
use std::default::Default;
use std::f32::consts::PI;
use std::iter;
use std::mem;
use std::sync::Arc;
@ -170,6 +174,40 @@ impl CanvasRenderingContext2D {
// Text styles
#[inline]
pub fn set_font_collection(&mut self, font_collection: Arc<FontCollection>) {
self.current_state.font_collection = font_collection;
}
#[inline]
pub fn set_font_families<I>(&mut self, font_families: I) where I: Iterator<Item = FontFamily> {
let mut font_collection = FontCollection::new();
for font_family in font_families {
font_collection.add_family(font_family);
}
self.current_state.font_collection = Arc::new(font_collection);
}
/// A convenience method to set a single font family.
#[inline]
pub fn set_font_family(&mut self, font_family: FontFamily) {
self.set_font_families(iter::once(font_family))
}
/// A convenience method to set a single font family consisting of a single font.
#[inline]
pub fn set_font(&mut self, font: Font) {
self.set_font_family(FontFamily::new_from_font(font))
}
/// A convenience method to set a single font family consisting of a font
/// described by a PostScript name.
#[inline]
pub fn set_font_by_postscript_name(&mut self, postscript_name: &str) {
let font = self.font_context.font_source.select_by_postscript_name(postscript_name);
self.set_font(font.expect("Didn't find the font!").load().unwrap());
}
#[inline]
pub fn set_font_size(&mut self, new_font_size: f32) {
self.current_state.font_size = new_font_size;
@ -488,7 +526,7 @@ pub enum TextAlign {
Center,
}
// We duplicate `pathfinder_geometry::stroke::LineJoin` here because the HTML canvas API treats the
// We duplicate `pathfinder_content::stroke::LineJoin` here because the HTML canvas API treats the
// miter limit as part of the canvas state, while the native Pathfinder API treats the miter limit
// as part of the line join. Pathfinder's choice is more logical, because the miter limit is
// specific to miter joins. In this API, however, for compatibility we go with the HTML canvas
@ -509,29 +547,37 @@ pub struct TextMetrics {
#[derive(Clone)]
pub struct CanvasFontContext {
#[allow(dead_code)]
font_source: Arc<SystemSource>,
font_source: Arc<dyn Source>,
#[allow(dead_code)]
default_font_collection: Arc<FontCollection>,
}
impl CanvasFontContext {
pub fn new() -> CanvasFontContext {
let font_source = Arc::new(SystemSource::new());
pub fn new(font_source: Arc<dyn Source>) -> CanvasFontContext {
let mut default_font_collection = FontCollection::new();
let default_font =
font_source.select_best_match(&[FamilyName::SansSerif], &Properties::new())
.expect("Failed to select the default font!")
.load()
.expect("Failed to load the default font!");
default_font_collection.add_family(FontFamily::new_from_font(default_font));
let default_font_collection = Arc::new(default_font_collection);
if let Ok(default_font) = font_source.select_best_match(&[FamilyName::SansSerif],
&Properties::new()) {
if let Ok(default_font) = default_font.load() {
default_font_collection.add_family(FontFamily::new_from_font(default_font));
}
}
CanvasFontContext {
font_source,
default_font_collection,
default_font_collection: Arc::new(default_font_collection),
}
}
/// A convenience method to create a font context with the system source.
/// This allows usage of fonts installed on the system.
pub fn from_system_source() -> CanvasFontContext {
CanvasFontContext::new(Arc::new(SystemSource::new()))
}
/// A convenience method to create a font context with a set of in-memory fonts.
pub fn from_fonts<I>(fonts: I) -> CanvasFontContext where I: Iterator<Item = Handle> {
CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap()))
}
}
// Text layout utilities

17
content/Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "pathfinder_content"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[dependencies]
arrayvec = "0.4"
bitflags = "1.0"
log = "0.4"
smallvec = "0.6"
[dependencies.pathfinder_geometry]
path = "../geometry"
[dependencies.pathfinder_simd]
path = "../simd"

View File

@ -1,4 +1,4 @@
// pathfinder/geometry/src/clip.rs
// pathfinder/content/src/clip.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
@ -8,13 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::basic::line_segment::LineSegment2F;
use crate::basic::vector::{Vector2F, Vector4F};
use crate::basic::rect::RectF;
use crate::outline::{Contour, PointFlags, PushSegmentFlags};
use crate::segment::{CubicSegment, Segment};
use crate::util::lerp;
use arrayvec::ArrayVec;
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::util::lerp;
use pathfinder_geometry::vector::{Vector2F, Vector4F};
use smallvec::SmallVec;
use std::fmt::Debug;
use std::mem;

View File

@ -75,13 +75,18 @@ impl Debug for ColorU {
}
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default)]
pub struct ColorF(pub F32x4);
impl ColorF {
#[inline]
pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF {
ColorF(F32x4::new(r, g, b, a))
}
#[inline]
pub fn transparent_black() -> ColorF {
ColorF(F32x4::default())
ColorF::default()
}
#[inline]
@ -120,3 +125,16 @@ impl ColorF {
self.0[3]
}
}
impl Debug for ColorF {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(
formatter,
"rgba({}, {}, {}, {})",
self.r() * 255.0,
self.g() * 255.0,
self.b() * 255.0,
self.a()
)
}
}

View File

@ -1,4 +1,4 @@
// pathfinder/geometry/src/dilation.rs
// pathfinder/content/src/dilation.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::basic::vector::Vector2F;
use crate::orientation::Orientation;
use crate::outline::Contour;
use pathfinder_geometry::vector::Vector2F;
pub struct ContourDilator<'a> {
contour: &'a mut Contour,

View File

@ -1,4 +1,4 @@
// pathfinder/geometry/src/basic/mod.rs
// pathfinder/content/src/lib.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
@ -8,10 +8,22 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Basic geometry and linear algebra primitives, optimized with SIMD.
//! Pathfinder's representation of a vector scene.
//!
//! This module also contains various path utilities.
pub mod line_segment;
pub mod rect;
pub mod transform2d;
pub mod transform3d;
pub mod vector;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
pub mod clip;
pub mod color;
pub mod dash;
pub mod orientation;
pub mod outline;
pub mod segment;
pub mod stroke;
pub mod transform;
mod dilation;

View File

@ -1,4 +1,4 @@
// pathfinder/geometry/src/outline.rs
// pathfinder/content/src/outline.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
@ -10,16 +10,16 @@
//! A compressed in-memory representation of paths.
use crate::basic::line_segment::LineSegment2F;
use crate::basic::vector::Vector2F;
use crate::basic::rect::RectF;
use crate::basic::transform2d::Transform2DF;
use crate::basic::transform3d::Perspective;
use crate::clip::{self, ContourPolygonClipper, ContourRectClipper};
use crate::dilation::ContourDilator;
use crate::orientation::Orientation;
use crate::segment::{Segment, SegmentFlags, SegmentKind};
use crate::unit_vector::UnitVector;
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_geometry::transform3d::Perspective;
use pathfinder_geometry::unit_vector::UnitVector;
use pathfinder_geometry::vector::Vector2F;
use std::f32::consts::PI;
use std::fmt::{self, Debug, Formatter};
use std::mem;

View File

@ -1,4 +1,4 @@
// pathfinder/geometry/src/segment.rs
// pathfinder/content/src/segment.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
@ -10,10 +10,10 @@
//! Line or curve segments, optimized with SIMD.
use crate::basic::line_segment::LineSegment2F;
use crate::basic::vector::Vector2F;
use crate::basic::transform2d::Transform2DF;
use crate::util::{self, EPSILON};
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_geometry::util::{self, EPSILON};
use pathfinder_geometry::vector::Vector2F;
use pathfinder_simd::default::F32x4;
use std::f32::consts::SQRT_2;

View File

@ -1,4 +1,4 @@
// pathfinder/geometry/src/stroke.rs
// pathfinder/content/src/stroke.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
@ -10,12 +10,12 @@
//! Utilities for converting path strokes to fills.
use crate::basic::line_segment::LineSegment2F;
use crate::basic::vector::Vector2F;
use crate::basic::rect::RectF;
use crate::basic::transform2d::Transform2DF;
use crate::outline::{ArcDirection, Contour, Outline, PushSegmentFlags};
use crate::segment::Segment;
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_geometry::vector::Vector2F;
use std::f32;
const TOLERANCE: f32 = 0.01;

124
content/src/transform.rs Normal file
View File

@ -0,0 +1,124 @@
// pathfinder/content/src/transform.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Utilities for transforming paths.
use crate::segment::Segment;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_geometry::transform3d::Perspective;
/// Transforms a path with a SIMD 2D transform.
pub struct Transform2DFPathIter<I>
where
I: Iterator<Item = Segment>,
{
iter: I,
transform: Transform2DF,
}
impl<I> Iterator for Transform2DFPathIter<I>
where
I: Iterator<Item = Segment>,
{
type Item = Segment;
#[inline]
fn next(&mut self) -> Option<Segment> {
// TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD?
let mut segment = self.iter.next()?;
if !segment.is_none() {
segment
.baseline
.set_from(&self.transform.transform_point(segment.baseline.from()));
segment
.baseline
.set_to(&self.transform.transform_point(segment.baseline.to()));
if !segment.is_line() {
segment
.ctrl
.set_from(&self.transform.transform_point(segment.ctrl.from()));
if !segment.is_quadratic() {
segment
.ctrl
.set_to(&self.transform.transform_point(segment.ctrl.to()));
}
}
}
Some(segment)
}
}
impl<I> Transform2DFPathIter<I>
where
I: Iterator<Item = Segment>,
{
#[inline]
pub fn new(iter: I, transform: &Transform2DF) -> Transform2DFPathIter<I> {
Transform2DFPathIter {
iter,
transform: *transform,
}
}
}
/// Transforms a path with a perspective projection.
pub struct PerspectivePathIter<I>
where
I: Iterator<Item = Segment>,
{
iter: I,
perspective: Perspective,
}
impl<I> Iterator for PerspectivePathIter<I>
where
I: Iterator<Item = Segment>,
{
type Item = Segment;
#[inline]
fn next(&mut self) -> Option<Segment> {
let mut segment = self.iter.next()?;
if !segment.is_none() {
segment.baseline.set_from(
&self
.perspective
.transform_point_2d(&segment.baseline.from()),
);
segment
.baseline
.set_to(&self.perspective.transform_point_2d(&segment.baseline.to()));
if !segment.is_line() {
segment
.ctrl
.set_from(&self.perspective.transform_point_2d(&segment.ctrl.from()));
if !segment.is_quadratic() {
segment
.ctrl
.set_to(&self.perspective.transform_point_2d(&segment.ctrl.to()));
}
}
}
Some(segment)
}
}
impl<I> PerspectivePathIter<I>
where
I: Iterator<Item = Segment>,
{
#[inline]
pub fn new(iter: I, perspective: &Perspective) -> PerspectivePathIter<I> {
PerspectivePathIter {
iter,
perspective: *perspective,
}
}
}

View File

@ -16,8 +16,8 @@ use jni::{JNIEnv, JavaVM};
use pathfinder_demo::window::{Event, SVGPath, View, Window, WindowSize};
use pathfinder_demo::DemoApp;
use pathfinder_demo::Options;
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectI;
use pathfinder_gl::GLVersion;
use pathfinder_gpu::resources::ResourceLoader;
use std::cell::RefCell;

View File

@ -4,11 +4,14 @@ version = "0.1.0"
edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[features]
pf-gl = []
[dependencies]
clap = "2.32"
gl = "0.6"
rayon = "1.0"
usvg = "0.4"
usvg = "0.7"
[dependencies.image]
version = "0.21"
@ -19,6 +22,9 @@ features = ["png_codec"]
version = "0.4"
features = ["release_max_level_warn"]
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_geometry]
path = "../../geometry"
@ -39,3 +45,9 @@ path = "../../svg"
[dependencies.pathfinder_ui]
path = "../../ui"
[target.'cfg(target_os = "macos")'.dependencies]
metal = "0.14"
[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal]
path = "../../metal"

View File

@ -14,10 +14,10 @@
// proper.
use crate::window::{OcularTransform, View};
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I, Vector4F};
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::basic::transform2d::Transform2DF;
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF};
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F};
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_geometry::transform3d::{Perspective, Transform3DF};
use std::f32::consts::FRAC_PI_4;
const NEAR_CLIP_PLANE: f32 = 0.01;

View File

@ -63,20 +63,19 @@ where
) -> GroundVertexArray<D> {
let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&ground_program.program, "Position");
let position_attr = device.get_vertex_attr(&ground_program.program, "Position").unwrap();
device.bind_vertex_array(&vertex_array);
device.use_program(&ground_program.program);
device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor {
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Float,
attr_type: VertexAttrType::U8,
stride: 0,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: 4,
offset: 0,
divisor: 0,
buffer_index: 0,
});
device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index);
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
GroundVertexArray { vertex_array }
}

View File

@ -22,17 +22,17 @@ use crate::device::{GroundProgram, GroundVertexArray};
use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction};
use crate::window::{Event, Keycode, SVGPath, Window, WindowSize};
use clap::{App, Arg};
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::basic::transform2d::Transform2DF;
use pathfinder_geometry::basic::transform3d::Transform3DF;
use pathfinder_geometry::color::ColorU;
use pathfinder_gl::GLDevice;
use pathfinder_gpu::Device;
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_gpu::resources::ResourceLoader;
use pathfinder_gpu::Device;
use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy};
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderStats, RenderTime, Renderer};
use pathfinder_renderer::options::{RenderOptions, RenderTransform};
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::{RenderStats, RenderTime, Renderer};
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
use pathfinder_renderer::post::STEM_DARKENING_FACTORS;
use pathfinder_renderer::scene::Scene;
use pathfinder_svg::BuiltSVG;
@ -44,6 +44,11 @@ use std::thread;
use std::time::Duration;
use usvg::{Options as UsvgOptions, Tree};
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use pathfinder_gl::GLDevice as DeviceImpl;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice as DeviceImpl;
static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg";
const MOUSELOOK_ROTATION_SPEED: f32 = 0.007;
@ -112,22 +117,31 @@ pub struct DemoApp<W> where W: Window {
build_time: Option<Duration>,
ui_model: DemoUIModel,
ui_presenter: DemoUIPresenter<GLDevice>,
ui_presenter: DemoUIPresenter<DeviceImpl>,
scene_proxy: SceneProxy,
renderer: Renderer<GLDevice>,
renderer: Renderer<DeviceImpl>,
scene_framebuffer: Option<<GLDevice as Device>::Framebuffer>,
scene_framebuffer: Option<<DeviceImpl as Device>::Framebuffer>,
ground_program: GroundProgram<GLDevice>,
ground_vertex_array: GroundVertexArray<GLDevice>,
ground_program: GroundProgram<DeviceImpl>,
ground_vertex_array: GroundVertexArray<DeviceImpl>,
}
impl<W> DemoApp<W> where W: Window {
pub fn new(window: W, window_size: WindowSize, mut options: Options) -> DemoApp<W> {
let expire_message_event_id = window.create_user_event_id();
let device = GLDevice::new(window.gl_version(), window.gl_default_framebuffer());
let device;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
{
device = DeviceImpl::new(window.metal_layer());
}
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
{
device = DeviceImpl::new(window.gl_version(), window.gl_default_framebuffer());
}
let resources = window.resource_loader();
// Read command line options.
@ -144,8 +158,12 @@ impl<W> DemoApp<W> where W: Window {
viewport,
window_size: window_size.device_size(),
};
// FIXME(pcwalton)
let render_options = RendererOptions {
background_color: None,
};
let renderer = Renderer::new(device, resources, dest_framebuffer);
let renderer = Renderer::new(device, resources, dest_framebuffer, render_options);
let scene_metadata = SceneMetadata::new_clipping_view_box(&mut built_svg.scene,
viewport.size());
let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size());
@ -246,7 +264,7 @@ impl<W> DemoApp<W> where W: Window {
Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)),
};
let render_options = RenderOptions {
let build_options = BuildOptions {
transform: self.render_transform.clone().unwrap(),
dilation: if self.ui_model.stem_darkening_effect_enabled {
let font_size = APPROX_FONT_SIZE * self.window_size.backing_scale_factor;
@ -258,7 +276,7 @@ impl<W> DemoApp<W> where W: Window {
subpixel_aa_enabled: self.ui_model.subpixel_aa_effect_enabled,
};
self.render_command_stream = Some(self.scene_proxy.build_with_stream(render_options));
self.render_command_stream = Some(self.scene_proxy.build_with_stream(build_options));
}
fn handle_events(&mut self, events: Vec<Event>) -> Vec<UIEvent> {
@ -488,7 +506,9 @@ impl<W> DemoApp<W> where W: Window {
self.handle_ui_events(frame, &mut ui_action);
self.window.present();
self.renderer.device.end_commands();
self.window.present(&mut self.renderer.device);
self.frame_counter += 1;
}

View File

@ -14,11 +14,14 @@ use crate::camera::{Camera, Mode};
use crate::window::{View, Window};
use crate::{BackgroundColor, DemoApp, UIVisibility};
use image::ColorType;
use pathfinder_geometry::color::{ColorF, ColorU};
use pathfinder_gpu::{ClearParams, DepthFunc, DepthState, Device, Primitive, RenderState};
use pathfinder_gpu::{TextureFormat, UniformData};
use pathfinder_geometry::basic::transform3d::Transform3DF;
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderMode};
use pathfinder_content::color::{ColorF, ColorU};
use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions};
use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData};
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform3d::Transform3DF;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::RenderMode;
use pathfinder_renderer::gpu_data::RenderCommand;
use pathfinder_renderer::options::RenderTransform;
use pathfinder_renderer::post::DEFRINGING_KERNEL_CORE_GRAPHICS;
@ -42,13 +45,14 @@ const GRIDLINE_COUNT: i32 = 10;
impl<W> DemoApp<W> where W: Window {
pub fn prepare_frame_rendering(&mut self) -> u32 {
// Make the GL context current.
// Make the context current.
let view = self.ui_model.mode.view(0);
self.window.make_current(view);
// Set up framebuffers.
let window_size = self.window_size.device_size();
let scene_count = match self.camera.mode() {
let mode = self.camera.mode();
let scene_count = match mode {
Mode::VR => {
let viewport = self.window.viewport(View::Stereo(0));
if self.scene_framebuffer.is_none()
@ -82,49 +86,47 @@ impl<W> DemoApp<W> where W: Window {
}
};
// Begin drawing the scene.
self.renderer.bind_dest_framebuffer();
// Clear to the appropriate color.
let clear_color = if scene_count == 2 {
ColorF::transparent_black()
} else {
self.background_color().to_f32()
let clear_color = match mode {
Mode::TwoD => Some(self.background_color().to_f32()),
Mode::ThreeD => None,
Mode::VR => Some(ColorF::transparent_black()),
};
self.renderer.device.clear(&ClearParams {
color: Some(clear_color),
depth: Some(1.0),
stencil: Some(0),
..ClearParams::default()
});
self.renderer.set_options(RendererOptions { background_color: clear_color });
scene_count
}
pub fn draw_scene(&mut self) {
self.renderer.device.begin_commands();
let view = self.ui_model.mode.view(0);
self.window.make_current(view);
if self.camera.mode() != Mode::VR {
self.draw_environment();
self.draw_environment(0);
}
self.renderer.device.end_commands();
self.render_vector_scene();
// Reattach default framebuffer.
if self.camera.mode() != Mode::VR {
return;
if self.camera.mode() == Mode::VR {
if let DestFramebuffer::Other(scene_framebuffer) =
self.renderer
.replace_dest_framebuffer(DestFramebuffer::Default {
viewport: self.window.viewport(View::Mono),
window_size: self.window_size.device_size(),
})
{
self.scene_framebuffer = Some(scene_framebuffer);
}
}
}
if let DestFramebuffer::Other(scene_framebuffer) =
self.renderer
.replace_dest_framebuffer(DestFramebuffer::Default {
viewport: self.window.viewport(View::Mono),
window_size: self.window_size.device_size(),
})
{
self.scene_framebuffer = Some(scene_framebuffer);
}
pub fn begin_compositing(&mut self) {
self.renderer.device.begin_commands();
}
pub fn composite_scene(&mut self, render_scene_index: u32) {
@ -151,21 +153,12 @@ impl<W> DemoApp<W> where W: Window {
let viewport = self.window.viewport(View::Stereo(render_scene_index));
self.window.make_current(View::Stereo(render_scene_index));
self.renderer
.replace_dest_framebuffer(DestFramebuffer::Default {
viewport,
window_size: self.window_size.device_size(),
});
self.renderer.bind_draw_framebuffer();
self.renderer.device.clear(&ClearParams {
color: Some(self.background_color().to_f32()),
depth: Some(1.0),
stencil: Some(0),
rect: Some(viewport),
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
viewport,
window_size: self.window_size.device_size(),
});
self.draw_environment();
self.draw_environment(render_scene_index);
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
@ -207,7 +200,7 @@ impl<W> DemoApp<W> where W: Window {
}
// Draws the ground, if applicable.
fn draw_environment(&self) {
fn draw_environment(&self, render_scene_index: u32) {
let frame = &self.current_frame.as_ref().unwrap();
let perspective = match frame.transform {
@ -233,31 +226,35 @@ impl<W> DemoApp<W> where W: Window {
transform =
transform.post_mul(&Transform3DF::from_scale(ground_scale, 1.0, ground_scale));
let device = &self.renderer.device;
device.bind_vertex_array(&self.ground_vertex_array.vertex_array);
device.use_program(&self.ground_program.program);
device.set_uniform(
&self.ground_program.transform_uniform,
UniformData::from_transform_3d(&transform),
);
device.set_uniform(
&self.ground_program.ground_color_uniform,
UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0),
);
device.set_uniform(
&self.ground_program.gridline_color_uniform,
UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0),
);
device.set_uniform(&self.ground_program.gridline_count_uniform,
UniformData::Int(GRIDLINE_COUNT));
device.draw_elements(
Primitive::Triangles,
6,
&RenderState {
// Don't clear the first scene after drawing it.
let clear_color = if render_scene_index == 0 {
Some(self.background_color().to_f32())
} else {
None
};
self.renderer.device.draw_elements(6, &RenderState {
target: &self.renderer.draw_render_target(),
program: &self.ground_program.program,
vertex_array: &self.ground_vertex_array.vertex_array,
primitive: Primitive::Triangles,
textures: &[],
uniforms: &[
(&self.ground_program.transform_uniform,
UniformData::from_transform_3d(&transform)),
(&self.ground_program.ground_color_uniform,
UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0)),
(&self.ground_program.gridline_color_uniform,
UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0)),
(&self.ground_program.gridline_count_uniform, UniformData::Int(GRIDLINE_COUNT)),
],
viewport: self.renderer.draw_viewport(),
options: RenderOptions {
depth: Some(DepthState { func: DepthFunc::Less, write: true }),
..RenderState::default()
clear_ops: ClearOps { color: clear_color, depth: Some(1.0), stencil: Some(0) },
..RenderOptions::default()
},
);
});
}
fn render_vector_scene(&mut self) {
@ -305,10 +302,11 @@ impl<W> DemoApp<W> where W: Window {
pub fn take_raster_screenshot(&mut self, path: PathBuf) {
let drawable_size = self.window_size.device_size();
let pixels = self
.renderer
.device
.read_pixels_from_default_framebuffer(drawable_size);
let viewport = RectI::new(Vector2I::default(), drawable_size);
let pixels = match self.renderer.device.read_pixels(&RenderTarget::Default, viewport) {
TextureData::U8(pixels) => pixels,
TextureData::U16(_) => panic!("Unexpected pixel format for default framebuffer!"),
};
image::save_buffer(
path,
&pixels,

View File

@ -11,8 +11,8 @@
use crate::camera::Mode;
use crate::window::Window;
use crate::{BackgroundColor, Options};
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectI;
use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_gpu::Device;
use pathfinder_renderer::gpu::debug::DebugUIPresenter;
@ -500,9 +500,7 @@ where
Vector2I::new(widget_x, slider_track_y),
Vector2I::new(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT),
);
debug_ui_presenter
.ui_presenter
.draw_rect_outline(device, slider_track_rect, TEXT_COLOR);
debug_ui_presenter.ui_presenter.draw_rect_outline(device, slider_track_rect, TEXT_COLOR);
let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2;
let slider_knob_rect = RectI::new(
@ -528,7 +526,11 @@ where
let widget_origin = panel_position + Vector2I::new(0, widget_size.y() * index);
let widget_rect = RectI::new(widget_origin, widget_size);
if self.draw_menu_item(device, debug_ui_presenter, &text, widget_rect, false) {
if self.draw_menu_item(device,
debug_ui_presenter,
&text,
widget_rect,
false) {
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
// the contents of the file.
if let Ok(path) = window.run_save_dialog(screenshot_type.extension()) {
@ -554,7 +556,11 @@ where
let widget_rect = RectI::new(widget_origin, widget_size);
let selected = color == model.background_color;
if self.draw_menu_item(device, debug_ui_presenter, text, widget_rect, selected) {
if self.draw_menu_item(device,
debug_ui_presenter,
text,
widget_rect,
selected) {
model.background_color = color;
*action = UIAction::ModelChanged;
}

View File

@ -10,24 +10,38 @@
//! A minimal cross-platform windowing layer.
use gl::types::GLuint;
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF};
use pathfinder_gl::GLVersion;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform3d::{Perspective, Transform3DF};
use pathfinder_gpu::resources::ResourceLoader;
use rayon::ThreadPoolBuilder;
use std::path::PathBuf;
pub trait Window {
fn gl_version(&self) -> GLVersion;
fn gl_default_framebuffer(&self) -> GLuint {
0
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use metal::CoreAnimationLayerRef;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice;
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use gl::types::GLuint;
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use pathfinder_gl::{GLDevice, GLVersion};
pub trait Window {
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn gl_version(&self) -> GLVersion;
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn gl_default_framebuffer(&self) -> GLuint { 0 }
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn present(&mut self, device: &mut GLDevice);
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn metal_layer(&self) -> &CoreAnimationLayerRef;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn present(&mut self, device: &mut MetalDevice);
fn viewport(&self, view: View) -> RectI;
fn make_current(&mut self, view: View);
fn present(&mut self);
fn viewport(&self, view: View) -> RectI;
fn resource_loader(&self) -> &dyn ResourceLoader;
fn create_user_event_id(&self) -> u32;
fn push_user_event(message_type: u32, message_data: u32);

View File

@ -7,7 +7,7 @@ authors = ["Alan Jeffrey <ajeffrey@mozilla.com>"]
[dependencies]
gl = "0.6"
rayon = "1.0"
usvg = "0.4"
usvg = "0.7"
egl = "0.2"
log = "0.4"
smallvec = "0.6"
@ -20,6 +20,9 @@ crate-type = ["cdylib"]
[features]
mocked = ["glutin"]
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_demo]
path = "../common"

View File

@ -10,10 +10,10 @@
use std::error::Error;
use std::io;
use pathfinder_geometry::basic::point::Point2DI32;
use pathfinder_geometry::basic::rect::RectI32;
use pathfinder_geometry::basic::transform3d::Perspective;
use pathfinder_geometry::basic::transform3d::Transform3DF32;
use pathfinder_geometry::point::Point2DI32;
use pathfinder_geometry::rect::RectI32;
use pathfinder_geometry::transform3d::Perspective;
use pathfinder_geometry::transform3d::Transform3DF32;
use pathfinder_gl::GLVersion;
use pathfinder_gpu::resources::ResourceLoader;

View File

@ -25,10 +25,10 @@ use crate::display::Display;
use crate::display::DisplayCamera;
use crate::display::DisplayError;
use pathfinder_geometry::basic::point::Point2DI32;
use pathfinder_geometry::basic::rect::RectI32;
use pathfinder_geometry::basic::transform3d::Transform3DF32;
use pathfinder_geometry::basic::transform3d::Perspective;
use pathfinder_geometry::point::Point2DI32;
use pathfinder_geometry::rect::RectI32;
use pathfinder_geometry::transform3d::Transform3DF32;
use pathfinder_geometry::transform3d::Perspective;
use pathfinder_gl::GLVersion;
use pathfinder_gpu::resources::FilesystemResourceLoader;
use pathfinder_gpu::resources::ResourceLoader;

View File

@ -15,13 +15,13 @@ use pathfinder_demo::Camera;
use pathfinder_demo::CameraTransform3D;
use pathfinder_gl::GLDevice;
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_geometry::basic::point::Point2DI32;
use pathfinder_geometry::basic::point::Point2DF32;
use pathfinder_geometry::basic::point::Point3DF32;
use pathfinder_geometry::basic::rect::RectI32;
use pathfinder_geometry::basic::transform2d::Transform2DF32;
use pathfinder_geometry::basic::transform3d::Transform3DF32;
use pathfinder_geometry::basic::transform3d::Perspective;
use pathfinder_geometry::point::Point2DI32;
use pathfinder_geometry::point::Point2DF32;
use pathfinder_geometry::point::Point3DF32;
use pathfinder_geometry::rect::RectI32;
use pathfinder_geometry::transform2d::Transform2DF32;
use pathfinder_geometry::transform3d::Transform3DF32;
use pathfinder_geometry::transform3d::Perspective;
use pathfinder_gpu::Device;
use pathfinder_simd::default::F32x4;
use pathfinder_svg::BuiltSVG;

View File

@ -29,11 +29,11 @@ use pathfinder_demo::BackgroundColor;
use pathfinder_demo::Mode;
use pathfinder_demo::window::Event;
use pathfinder_demo::window::SVGPath;
use pathfinder_geometry::basic::vector::Vector2F;
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::basic::transform2d::Transform2DF;
use pathfinder_geometry::color::ColorF;
use pathfinder_geometry::vector::Vector2F;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_content::color::ColorF;
use pathfinder_gl::GLDevice;
use pathfinder_gl::GLVersion;
use pathfinder_gpu::ClearParams;
@ -113,6 +113,7 @@ pub unsafe extern "C" fn magicleap_pathfinder_demo_run(app: *mut c_void) {
}
let scene_count = app.demo.prepare_frame(events);
app.demo.draw_scene();
app.demo.begin_compositing();
for scene_index in 0..scene_count {
app.demo.composite_scene(scene_index);
}

View File

@ -48,12 +48,12 @@ use pathfinder_demo::window::OcularTransform;
use pathfinder_demo::window::View;
use pathfinder_demo::window::Window;
use pathfinder_demo::window::WindowSize;
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::vector::Vector2F;
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::basic::transform3d::Perspective;
use pathfinder_geometry::basic::transform3d::Transform3DF;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::vector::Vector2F;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform3d::Perspective;
use pathfinder_geometry::transform3d::Transform3DF;
use pathfinder_geometry::util;
use pathfinder_gl::GLVersion;
use pathfinder_gpu::resources::FilesystemResourceLoader;

View File

@ -5,6 +5,7 @@ edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[features]
pf-gl = ["pathfinder_demo/pf-gl"]
pf-no-simd = ["pathfinder_simd/pf-no-simd"]
[dependencies]
@ -30,5 +31,12 @@ path = "../../gpu"
[dependencies.pathfinder_simd]
path = "../../simd"
[target.'cfg(target_os = "macos")'.dependencies]
foreign-types = "0.3"
metal = "0.14"
[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal]
path = "../../metal"
[target.'cfg(not(windows))'.dependencies]
jemallocator = "0.1"

View File

@ -13,18 +13,35 @@
use nfd::Response;
use pathfinder_demo::window::{Event, Keycode, SVGPath, View, Window, WindowSize};
use pathfinder_demo::{DemoApp, Options};
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_gl::GLVersion;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectI;
use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader};
use sdl2::event::{Event as SDLEvent, WindowEvent};
use sdl2::keyboard::Keycode as SDLKeycode;
use sdl2::video::{GLContext, GLProfile, Window as SDLWindow};
use sdl2::video::Window as SDLWindow;
use sdl2::{EventPump, EventSubsystem, Sdl, VideoSubsystem};
use sdl2_sys::{SDL_Event, SDL_UserEvent};
use std::path::PathBuf;
use std::ptr;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use foreign_types::ForeignTypeRef;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use metal::{CAMetalLayer, CoreAnimationLayerRef};
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use sdl2::hint;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use sdl2::render::Canvas;
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use sdl2_sys::SDL_RenderGetMetalLayer;
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use pathfinder_gl::{GLDevice, GLVersion};
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use sdl2::video::{GLContext, GLProfile};
#[cfg(not(windows))]
use jemallocator;
@ -55,6 +72,7 @@ fn main() {
let scene_count = app.prepare_frame(events);
app.draw_scene();
app.begin_compositing();
for scene_index in 0..scene_count {
app.composite_scene(scene_index);
}
@ -69,22 +87,36 @@ thread_local! {
}
struct WindowImpl {
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
window: SDLWindow,
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
gl_context: GLContext,
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
canvas: Canvas<SDLWindow>,
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
metal_layer: *mut CAMetalLayer,
event_pump: EventPump,
#[allow(dead_code)]
gl_context: GLContext,
resource_loader: FilesystemResourceLoader,
selected_file: Option<PathBuf>,
open_svg_message_type: u32,
}
impl Window for WindowImpl {
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn gl_version(&self) -> GLVersion {
GLVersion::GL3
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn metal_layer(&self) -> &CoreAnimationLayerRef {
unsafe { CoreAnimationLayerRef::from_ptr(self.metal_layer) }
}
fn viewport(&self, view: View) -> RectI {
let (width, height) = self.window.drawable_size();
let (width, height) = self.window().drawable_size();
let mut width = width as i32;
let height = height as i32;
let mut x_offset = 0;
@ -95,12 +127,22 @@ impl Window for WindowImpl {
RectI::new(Vector2I::new(x_offset, 0), Vector2I::new(width, height))
}
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn make_current(&mut self, _view: View) {
self.window.gl_make_current(&self.gl_context).unwrap();
self.window().gl_make_current(&self.gl_context).unwrap();
}
fn present(&mut self) {
self.window.gl_swap_window();
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn make_current(&mut self, _: View) {}
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn present(&mut self, _: &mut GLDevice) {
self.window().gl_swap_window();
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn present(&mut self, device: &mut MetalDevice) {
device.present_drawable();
}
fn resource_loader(&self) -> &dyn ResourceLoader {
@ -141,6 +183,7 @@ impl Window for WindowImpl {
}
impl WindowImpl {
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn new() -> WindowImpl {
SDL_VIDEO.with(|sdl_video| {
SDL_EVENT.with(|sdl_event| {
@ -185,9 +228,55 @@ impl WindowImpl {
})
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn new() -> WindowImpl {
assert!(hint::set("SDL_RENDER_DRIVER", "metal"));
SDL_VIDEO.with(|sdl_video| {
SDL_EVENT.with(|sdl_event| {
let window = sdl_video
.window(
"Pathfinder Demo",
DEFAULT_WINDOW_WIDTH,
DEFAULT_WINDOW_HEIGHT,
)
.opengl()
.resizable()
.allow_highdpi()
.build()
.unwrap();
let canvas = window.into_canvas().present_vsync().build().unwrap();
let metal_layer = unsafe {
SDL_RenderGetMetalLayer(canvas.raw()) as *mut CAMetalLayer
};
let event_pump = SDL_CONTEXT.with(|sdl_context| sdl_context.event_pump().unwrap());
let resource_loader = FilesystemResourceLoader::locate();
let open_svg_message_type = unsafe { sdl_event.register_event().unwrap() };
WindowImpl {
event_pump,
canvas,
metal_layer,
resource_loader,
open_svg_message_type,
selected_file: None,
}
})
})
}
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
fn window(&self) -> &SDLWindow { &self.window }
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
fn window(&self) -> &SDLWindow { self.canvas.window() }
fn size(&self) -> WindowSize {
let (logical_width, logical_height) = self.window.size();
let (drawable_width, _) = self.window.drawable_size();
let (logical_width, logical_height) = self.window().size();
let (drawable_width, _) = self.window().drawable_size();
WindowSize {
logical_size: Vector2I::new(logical_width as i32, logical_height as i32),
backing_scale_factor: drawable_width as f32 / logical_width as f32,

View File

@ -5,7 +5,7 @@ RUST_TARGET_DIR?=../../target
RUST_SRC_DIR?=../../c
RUSTFLAGS?=-C target-cpu=native
CFLAGS?=-Wall -g -I../../c/include
CFLAGS?=-Wall -g -I../../c/build/include
LIBS?=-lpathfinder_c
MKDIR?=mkdir -p
RM?=rm
@ -15,7 +15,7 @@ UNAME=$(shell uname -s)
ifeq ($(UNAME),Darwin)
# FIXME(pcwalton): Don't link against HarfBuzz!!
LIBS+=-framework OpenGL -framework CoreFoundation -framework CoreGraphics -framework CoreText
LIBS+=-lharfbuzz
LIBS+=-framework Metal -lharfbuzz
else
LIBS+=-lGL
endif

View File

@ -58,15 +58,13 @@ int main(int argc, const char **argv) {
PFGLDestFramebufferCreateFullWindow(&(PFVector2I){640, 480});
PFGLRendererRef renderer = PFGLRendererCreate(PFGLDeviceCreate(PF_GL_VERSION_GL3, 0),
PFFilesystemResourceLoaderLocate(),
dest_framebuffer);
// Clear to white.
PFGLDeviceClear(PFGLRendererGetDevice(renderer), &(PFClearParams){
(PFColorF){1.0, 1.0, 1.0, 1.0}, 0.0, 0, {0}, PF_CLEAR_FLAGS_HAS_COLOR
dest_framebuffer,
&(PFRendererOptions){
(PFColorF){1.0, 1.0, 1.0, 1.0}, PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR
});
// Make a canvas. We're going to draw a house.
PFCanvasRef canvas = PFCanvasCreate(PFCanvasFontContextCreate(),
PFCanvasRef canvas = PFCanvasCreate(PFCanvasFontContextCreateWithSystemSource(),
&(PFVector2F){640.0f, 480.0f});
// Set line width.
@ -89,7 +87,7 @@ int main(int argc, const char **argv) {
// Render the canvas to screen.
PFSceneRef scene = PFCanvasCreateScene(canvas);
PFSceneProxyRef scene_proxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene);
PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFRenderOptions){0});
PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFBuildOptions){0});
SDL_GL_SwapWindow(window);
// Wait for a keypress.

View File

@ -0,0 +1,28 @@
[package]
name = "canvas_glutin_minimal"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[dependencies]
gl = "0.6"
glutin = "0.21"
[dependencies.pathfinder_canvas]
path = "../../canvas"
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_geometry]
path = "../../geometry"
[dependencies.pathfinder_gl]
path = "../../gl"
[dependencies.pathfinder_gpu]
path = "../../gpu"
[dependencies.pathfinder_renderer]
path = "../../renderer"

View File

@ -0,0 +1,96 @@
// pathfinder/examples/canvas_glutin_minimal/src/main.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Demonstrates how to use the Pathfinder canvas API with `glutin`.
use glutin::dpi::PhysicalSize;
use glutin::{ContextBuilder, ControlFlow, Event, EventsLoop, GlProfile, GlRequest, KeyboardInput};
use glutin::{VirtualKeyCode, WindowBuilder, WindowEvent};
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
use pathfinder_content::color::ColorF;
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_geometry::rect::RectF;
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::FilesystemResourceLoader;
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::options::BuildOptions;
fn main() {
// Calculate the right logical size of the window.
let mut event_loop = EventsLoop::new();
let hidpi_factor = event_loop.get_primary_monitor().get_hidpi_factor();
let window_size = Vector2I::new(640, 480);
let physical_window_size = PhysicalSize::new(window_size.x() as f64, window_size.y() as f64);
let logical_window_size = physical_window_size.to_logical(hidpi_factor);
// Open a window.
let window_builder = WindowBuilder::new().with_title("Minimal example")
.with_dimensions(logical_window_size);
// Create an OpenGL 3.x context for Pathfinder to use.
let gl_context = ContextBuilder::new().with_gl(GlRequest::Latest)
.with_gl_profile(GlProfile::Core)
.build_windowed(window_builder, &event_loop)
.unwrap();
// Load OpenGL, and make the context current.
let gl_context = unsafe { gl_context.make_current().unwrap() };
gl::load_with(|name| gl_context.get_proc_address(name) as *const _);
// Create a Pathfinder renderer.
let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0),
&FilesystemResourceLoader::locate(),
DestFramebuffer::full_window(window_size),
RendererOptions { background_color: Some(ColorF::white()) });
// Make a canvas. We're going to draw a house.
let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(),
window_size.to_f32());
// Set line width.
canvas.set_line_width(10.0);
// Draw walls.
canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0)));
// Draw door.
canvas.fill_rect(RectF::new(Vector2F::new(130.0, 190.0), Vector2F::new(40.0, 60.0)));
// Draw roof.
let mut path = Path2D::new();
path.move_to(Vector2F::new(50.0, 140.0));
path.line_to(Vector2F::new(150.0, 60.0));
path.line_to(Vector2F::new(250.0, 140.0));
path.close_path();
canvas.stroke_path(path);
// Render the canvas to screen.
let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor);
scene.build_and_render(&mut renderer, BuildOptions::default());
gl_context.swap_buffers().unwrap();
// Wait for a keypress.
event_loop.run_forever(|event| {
match event {
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } |
Event::WindowEvent {
event: WindowEvent::KeyboardInput {
input: KeyboardInput { virtual_keycode: Some(VirtualKeyCode::Escape), .. },
..
},
..
} => ControlFlow::Break,
_ => ControlFlow::Continue,
}
})
}

View File

@ -0,0 +1,34 @@
[package]
name = "canvas_metal_minimal"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[dependencies]
foreign-types = "0.3"
gl = "0.6"
metal = "0.14"
objc = "0.2"
sdl2 = "0.32"
sdl2-sys = "0.32"
[dependencies.pathfinder_canvas]
path = "../../canvas"
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_geometry]
path = "../../geometry"
[dependencies.pathfinder_gl]
path = "../../gl"
[dependencies.pathfinder_gpu]
path = "../../gpu"
[dependencies.pathfinder_metal]
path = "../../metal"
[dependencies.pathfinder_renderer]
path = "../../renderer"

View File

@ -0,0 +1,88 @@
// pathfinder/examples/canvas_metal_minimal/src/main.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use foreign_types::ForeignTypeRef;
use metal::{CAMetalLayer, CoreAnimationLayerRef};
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
use pathfinder_content::color::ColorF;
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_geometry::rect::RectF;
use pathfinder_gpu::resources::FilesystemResourceLoader;
use pathfinder_metal::MetalDevice;
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use sdl2::event::Event;
use sdl2::hint;
use sdl2::keyboard::Keycode;
use sdl2_sys::SDL_RenderGetMetalLayer;
fn main() {
// Set up SDL2.
assert!(hint::set("SDL_RENDER_DRIVER", "metal"));
let sdl_context = sdl2::init().unwrap();
let video = sdl_context.video().unwrap();
// Open a window.
let window_size = Vector2I::new(640, 480);
let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32)
.opengl()
.build()
.unwrap();
// Create a Metal context.
let canvas = window.into_canvas().present_vsync().build().unwrap();
let metal_layer = unsafe {
CoreAnimationLayerRef::from_ptr(SDL_RenderGetMetalLayer(canvas.raw()) as *mut CAMetalLayer)
};
// Create a Pathfinder renderer.
let mut renderer = Renderer::new(MetalDevice::new(metal_layer),
&FilesystemResourceLoader::locate(),
DestFramebuffer::full_window(window_size),
RendererOptions { background_color: Some(ColorF::white()) });
// Make a canvas. We're going to draw a house.
let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(),
window_size.to_f32());
// Set line width.
canvas.set_line_width(10.0);
// Draw walls.
canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0)));
// Draw door.
canvas.fill_rect(RectF::new(Vector2F::new(130.0, 190.0), Vector2F::new(40.0, 60.0)));
// Draw roof.
let mut path = Path2D::new();
path.move_to(Vector2F::new(50.0, 140.0));
path.line_to(Vector2F::new(150.0, 60.0));
path.line_to(Vector2F::new(250.0, 140.0));
path.close_path();
canvas.stroke_path(path);
// Render the canvas to screen.
let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor);
scene.build_and_render(&mut renderer, BuildOptions::default());
renderer.device.present_drawable();
// Wait for a keypress.
let mut event_pump = sdl_context.event_pump().unwrap();
loop {
match event_pump.wait_event() {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return,
_ => {}
}
}
}

View File

@ -12,6 +12,9 @@ sdl2-sys = "0.32"
[dependencies.pathfinder_canvas]
path = "../../canvas"
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_geometry]
path = "../../geometry"

View File

@ -9,16 +9,16 @@
// except according to those terms.
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::color::ColorF;
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_geometry::rect::RectF;
use pathfinder_content::color::ColorF;
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::FilesystemResourceLoader;
use pathfinder_gpu::{ClearParams, Device};
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer};
use pathfinder_renderer::options::RenderOptions;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;
@ -48,13 +48,12 @@ fn main() {
// Create a Pathfinder renderer.
let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0),
&FilesystemResourceLoader::locate(),
DestFramebuffer::full_window(window_size));
// Clear to white.
renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() });
DestFramebuffer::full_window(window_size),
RendererOptions { background_color: Some(ColorF::white()) });
// Make a canvas. We're going to draw a house.
let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32());
let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(),
window_size.to_f32());
// Set line width.
canvas.set_line_width(10.0);
@ -75,7 +74,7 @@ fn main() {
// Render the canvas to screen.
let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor);
scene.build_and_render(&mut renderer, RenderOptions::default());
scene.build_and_render(&mut renderer, BuildOptions::default());
window.gl_swap_window();
// Wait for a keypress.

View File

@ -12,6 +12,9 @@ sdl2-sys = "0.32"
[dependencies.pathfinder_canvas]
path = "../../canvas"
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_geometry]
path = "../../geometry"

View File

@ -9,15 +9,15 @@
// except according to those terms.
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, Path2D};
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::color::{ColorF, ColorU};
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_content::color::{ColorF, ColorU};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::FilesystemResourceLoader;
use pathfinder_gpu::{ClearParams, Device};
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer};
use pathfinder_renderer::options::RenderOptions;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;
@ -67,7 +67,8 @@ fn main() {
// Create our renderers.
let renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0),
&FilesystemResourceLoader::locate(),
DestFramebuffer::full_window(drawable_size));
DestFramebuffer::full_window(drawable_size),
RendererOptions { background_color: Some(ColorF::white()) });
let mut moire_renderer = MoireRenderer::new(renderer, window_size, drawable_size);
// Enter main render loop.
@ -99,7 +100,7 @@ impl MoireRenderer {
-> MoireRenderer {
MoireRenderer {
renderer,
font_context: CanvasFontContext::new(),
font_context: CanvasFontContext::from_system_source(),
scene: SceneProxy::new(RayonExecutor),
frame: 0,
window_size,
@ -124,10 +125,7 @@ impl MoireRenderer {
Vector2F::new(1.0, sin_time).scale(cos_time * INNER_RADIUS);
// Clear to background color.
self.renderer.device.clear(&ClearParams {
color: Some(background_color),
..ClearParams::default()
});
self.renderer.set_options(RendererOptions { background_color: Some(background_color) });
// Make a canvas.
let mut canvas = CanvasRenderingContext2D::new(self.font_context.clone(),
@ -142,7 +140,7 @@ impl MoireRenderer {
// Build and render scene.
self.scene.replace_scene(canvas.into_scene());
self.scene.build_and_render(&mut self.renderer, RenderOptions::default());
self.scene.build_and_render(&mut self.renderer, BuildOptions::default());
self.frame += 1;
}

View File

@ -5,6 +5,7 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[dependencies]
font-kit = "0.2"
gl = "0.6"
sdl2 = "0.32"
sdl2-sys = "0.32"
@ -12,6 +13,9 @@ sdl2-sys = "0.32"
[dependencies.pathfinder_canvas]
path = "../../canvas"
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_geometry]
path = "../../geometry"

View File

@ -8,19 +8,22 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use font_kit::handle::Handle;
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, TextAlign};
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::color::ColorF;
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_content::color::ColorF;
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::FilesystemResourceLoader;
use pathfinder_gpu::{ClearParams, Device};
use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader};
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer};
use pathfinder_renderer::options::RenderOptions;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;
use std::iter;
use std::sync::Arc;
fn main() {
// Set up SDL2.
@ -45,17 +48,22 @@ fn main() {
window.gl_make_current(&gl_context).unwrap();
// Create a Pathfinder renderer.
let resource_loader = FilesystemResourceLoader::locate();
let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0),
&FilesystemResourceLoader::locate(),
DestFramebuffer::full_window(window_size));
&resource_loader,
DestFramebuffer::full_window(window_size),
RendererOptions { background_color: Some(ColorF::white()) });
// Clear to white.
renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() });
// Load a font.
let font_data = Arc::new(resource_loader.slurp("fonts/overpass-regular.otf").unwrap());
let font = Handle::from_memory(font_data, 0);
let font_context = CanvasFontContext::from_fonts(iter::once(font));
// Make a canvas. We're going to draw some text.
let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32());
// Make a canvas.
let mut canvas = CanvasRenderingContext2D::new(font_context, window_size.to_f32());
// Draw the text.
canvas.set_font_by_postscript_name("Overpass-Regular");
canvas.set_font_size(32.0);
canvas.fill_text("Hello Pathfinder!", Vector2F::new(32.0, 48.0));
canvas.set_text_align(TextAlign::Right);
@ -63,7 +71,7 @@ fn main() {
// Render the canvas to screen.
let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor);
scene.build_and_render(&mut renderer, RenderOptions::default());
scene.build_and_render(&mut renderer, BuildOptions::default());
window.gl_swap_window();
// Wait for a keypress.

View File

@ -0,0 +1,28 @@
[package]
name = "swf_basic"
version = "0.1.0"
authors = ["Jon Hardie <jon@hardiesoft.com>"]
edition = "2018"
[dependencies]
gl = "0.6"
sdl2 = "0.32"
sdl2-sys = "0.32"
swf-parser = "0.7.0"
swf-tree = "0.7.0"
[dependencies.pathfinder_geometry]
path = "../../geometry"
[dependencies.pathfinder_gl]
path = "../../gl"
[dependencies.pathfinder_gpu]
path = "../../gpu"
[dependencies.pathfinder_renderer]
path = "../../renderer"
[dependencies.pathfinder_swf]
path = "../../swf"

View File

@ -0,0 +1,136 @@
// pathfinder/examples/swf_basic/src/main.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_geometry::rect::RectF;
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader};
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::options::{RenderTransform, BuildOptions};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;
use pathfinder_renderer::scene::Scene;
use pathfinder_swf::{draw_paths_into_scene, process_swf_tags};
use std::env;
use std::fs::read;
use pathfinder_geometry::transform2d::Transform2DF;
fn main() {
let resource_loader = FilesystemResourceLoader::locate();
let swf_bytes;
if let Some(path) = env::args().skip(1).next() {
match read(path) {
Ok(bytes) => {
swf_bytes = bytes;
},
Err(e) => panic!(e)
}
} else {
// NOTE(jon): This is a version of the ghostscript tiger graphic flattened to a single
// layer with no overlapping shapes. This is how artwork is 'natively' created in the Flash
// authoring tool when an artist just draws directly onto the canvas (without 'object' mode
// turned on, which is the default).
// Subsequent shapes with different fills will knock out existing fills where they overlap.
// A downside of this in current pathfinder is that cracks are visible between shape fills -
// especially obvious if you set the context clear color to #ff00ff or similar.
// Common speculation as to why the swf format stores vector graphics in this way says that
// it is to save on file-size bytes, however in the case of our tiger, it results in a
// larger file than the layered version, since the overlapping shapes and strokes create
// a lot more geometry. I think a more likely explanation for the choice is that it was
// done to reduce overdraw in the software rasterizer running on late 90's era hardware?
// Indeed, this mode gives pathfinders' occlusion culling pass nothing to do!
// NOTE(jon): This is a version of the same graphic cut and pasted into the Flash authoring
// tool from the SVG version loaded in Illustrator. When layered graphics are pasted
// into Flash, by default they retain their layering, expressed as groups.
// They are still presented as being on a single timeline layer.
// They will be drawn back to front in much the same way as the SVG version.
let default_tiger = resource_loader.slurp("swf/tiger.swf").unwrap();
swf_bytes = Vec::from(&default_tiger[..]);
}
let (_, movie): (_, swf_tree::Movie) = swf_parser::parsers::movie::parse_movie(&swf_bytes[..]).unwrap();
// Set up SDL2.
let sdl_context = sdl2::init().unwrap();
let video = sdl_context.video().unwrap();
// Make sure we have at least a GL 3.0 context. Pathfinder requires this.
let gl_attributes = video.gl_attr();
gl_attributes.set_context_profile(GLProfile::Core);
gl_attributes.set_context_version(3, 3);
// process swf scene
// TODO(jon): Since swf is a streaming format, this really wants to be a lazy iterator over
// swf frames eventually.
let (library, stage) = process_swf_tags(&movie);
// Open a window.
let window_size = Vector2I::new(stage.width(), stage.height());
let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32)
.opengl()
.allow_highdpi()
.build()
.unwrap();
let pixel_size = Vector2I::new(
window.drawable_size().0 as i32,
window.drawable_size().1 as i32
);
let device_pixel_ratio = pixel_size.x() as f32 / window_size.x() as f32;
// Create the GL context, and make it current.
let gl_context = window.gl_create_context().unwrap();
gl::load_with(|name| video.gl_get_proc_address(name) as *const _);
window.gl_make_current(&gl_context).unwrap();
// Create a Pathfinder renderer.
let mut renderer = Renderer::new(
GLDevice::new(GLVersion::GL3, 0),
&resource_loader,
DestFramebuffer::full_window(pixel_size),
RendererOptions { background_color: Some(stage.background_color()) }
);
// Clear to swf stage background color.
let mut scene = Scene::new();
scene.set_view_box(RectF::new(
Vector2F::default(),
Vector2F::new(
stage.width() as f32 * device_pixel_ratio,
stage.height() as f32 * device_pixel_ratio)
));
draw_paths_into_scene(&library, &mut scene);
// Render the canvas to screen.
let scene = SceneProxy::from_scene(scene, RayonExecutor);
let mut build_options = BuildOptions::default();
let scale_transform = Transform2DF::from_scale(
Vector2F::new(device_pixel_ratio, device_pixel_ratio)
);
build_options.transform = RenderTransform::Transform2D(scale_transform);
scene.build_and_render(&mut renderer, build_options);
window.gl_swap_window();
// Wait for a keypress.
let mut event_pump = sdl_context.event_pump().unwrap();
loop {
match event_pump.wait_event() {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return,
_ => {}
}
}
}

View File

@ -5,11 +5,6 @@ edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[dependencies]
arrayvec = "0.4"
bitflags = "1.0"
serde = "1.0"
serde_derive = "1.0"
smallvec = "0.6"
[dependencies.log]
version = "0.4"

View File

@ -8,24 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Utilities for Bézier curves.
//!
//! These may be merged into upstream Lyon eventually.
//! Basic geometry and linear algebra primitives, optimized with SIMD.
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
pub mod basic;
pub mod clip;
pub mod color;
pub mod dash;
pub mod orientation;
pub mod outline;
pub mod segment;
pub mod stroke;
pub mod line_segment;
pub mod rect;
pub mod transform2d;
pub mod transform3d;
pub mod unit_vector;
pub mod util;
mod dilation;
mod unit_vector;
pub mod vector;

View File

@ -10,8 +10,8 @@
//! Line segment types, optimized with SIMD.
use crate::basic::vector::Vector2F;
use crate::basic::transform2d::Matrix2x2F;
use crate::vector::Vector2F;
use crate::transform2d::Matrix2x2F;
use crate::util;
use pathfinder_simd::default::F32x4;
use std::ops::{Add, Sub};

View File

@ -10,7 +10,7 @@
//! 2D axis-aligned rectangles, optimized with SIMD.
use crate::basic::vector::{Vector2F, Vector2I};
use crate::vector::{Vector2F, Vector2I};
use pathfinder_simd::default::{F32x4, I32x4};
#[derive(Clone, Copy, Debug, PartialEq, Default)]

View File

@ -10,11 +10,10 @@
//! 2D affine transforms.
use crate::basic::line_segment::LineSegment2F;
use crate::basic::vector::Vector2F;
use crate::basic::rect::RectF;
use crate::basic::transform3d::Transform3DF;
use crate::segment::Segment;
use crate::line_segment::LineSegment2F;
use crate::vector::Vector2F;
use crate::rect::RectF;
use crate::transform3d::Transform3DF;
use crate::unit_vector::UnitVector;
use pathfinder_simd::default::F32x4;
use std::ops::Sub;
@ -295,57 +294,3 @@ impl Transform2DF {
Vector2F(self.matrix.0.zwxy()).length()
}
}
/// Transforms a path with a SIMD 2D transform.
pub struct Transform2DFPathIter<I>
where
I: Iterator<Item = Segment>,
{
iter: I,
transform: Transform2DF,
}
impl<I> Iterator for Transform2DFPathIter<I>
where
I: Iterator<Item = Segment>,
{
type Item = Segment;
#[inline]
fn next(&mut self) -> Option<Segment> {
// TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD?
let mut segment = self.iter.next()?;
if !segment.is_none() {
segment
.baseline
.set_from(&self.transform.transform_point(segment.baseline.from()));
segment
.baseline
.set_to(&self.transform.transform_point(segment.baseline.to()));
if !segment.is_line() {
segment
.ctrl
.set_from(&self.transform.transform_point(segment.ctrl.from()));
if !segment.is_quadratic() {
segment
.ctrl
.set_to(&self.transform.transform_point(segment.ctrl.to()));
}
}
}
Some(segment)
}
}
impl<I> Transform2DFPathIter<I>
where
I: Iterator<Item = Segment>,
{
#[inline]
pub fn new(iter: I, transform: &Transform2DF) -> Transform2DFPathIter<I> {
Transform2DFPathIter {
iter,
transform: *transform,
}
}
}

View File

@ -10,10 +10,9 @@
//! 3D transforms that can be applied to paths.
use crate::basic::vector::{Vector2F, Vector2I, Vector4F};
use crate::basic::rect::RectF;
use crate::basic::transform2d::Matrix2x2F;
use crate::segment::Segment;
use crate::vector::{Vector2F, Vector2I, Vector4F};
use crate::rect::RectF;
use crate::transform2d::Matrix2x2F;
use pathfinder_simd::default::F32x4;
use std::ops::{Add, Neg};
@ -372,65 +371,10 @@ impl Perspective {
}
}
/// Transforms a path with a perspective projection.
pub struct PerspectivePathIter<I>
where
I: Iterator<Item = Segment>,
{
iter: I,
perspective: Perspective,
}
impl<I> Iterator for PerspectivePathIter<I>
where
I: Iterator<Item = Segment>,
{
type Item = Segment;
#[inline]
fn next(&mut self) -> Option<Segment> {
let mut segment = self.iter.next()?;
if !segment.is_none() {
segment.baseline.set_from(
&self
.perspective
.transform_point_2d(&segment.baseline.from()),
);
segment
.baseline
.set_to(&self.perspective.transform_point_2d(&segment.baseline.to()));
if !segment.is_line() {
segment
.ctrl
.set_from(&self.perspective.transform_point_2d(&segment.ctrl.from()));
if !segment.is_quadratic() {
segment
.ctrl
.set_to(&self.perspective.transform_point_2d(&segment.ctrl.to()));
}
}
}
Some(segment)
}
}
impl<I> PerspectivePathIter<I>
where
I: Iterator<Item = Segment>,
{
#[inline]
pub fn new(iter: I, perspective: &Perspective) -> PerspectivePathIter<I> {
PerspectivePathIter {
iter,
perspective: *perspective,
}
}
}
#[cfg(test)]
mod test {
use crate::basic::vector::Vector4F;
use crate::basic::transform3d::Transform3DF;
use crate::vector::Vector4F;
use crate::transform3d::Transform3DF;
#[test]
fn test_post_mul() {

View File

@ -10,7 +10,7 @@
//! A utility module that allows unit vectors to be treated like angles.
use crate::basic::vector::Vector2F;
use crate::vector::Vector2F;
use pathfinder_simd::default::F32x4;
#[derive(Clone, Copy, Debug)]

View File

@ -14,13 +14,13 @@
extern crate log;
use gl::types::{GLboolean, GLchar, GLenum, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams};
use pathfinder_gpu::{DepthFunc, Device, Primitive, RenderState, ShaderKind, StencilFunc};
use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass};
use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType};
use pathfinder_gpu::{RenderTarget, BlendState, BufferData, BufferTarget, BufferUploadMode};
use pathfinder_gpu::{ClearOps, DepthFunc, Device, Primitive, RenderOptions, RenderState};
use pathfinder_gpu::{ShaderKind, StencilFunc, TextureData, TextureFormat, UniformData};
use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
use pathfinder_simd::default::F32x4;
use std::ffi::CString;
use std::mem;
@ -60,10 +60,32 @@ impl GLDevice {
}
}
fn set_render_state(&self, render_state: &RenderState) {
fn set_render_state(&self, render_state: &RenderState<GLDevice>) {
self.bind_render_target(render_state.target);
unsafe {
let (origin, size) = (render_state.viewport.origin(), render_state.viewport.size());
gl::Viewport(origin.x(), origin.y(), size.x(), size.y());
}
if render_state.options.clear_ops.has_ops() {
self.clear(&render_state.options.clear_ops);
}
self.use_program(render_state.program);
self.bind_vertex_array(render_state.vertex_array);
for (texture_unit, texture) in render_state.textures.iter().enumerate() {
self.bind_texture(texture, texture_unit as u32);
}
render_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data));
self.set_render_options(&render_state.options);
}
fn set_render_options(&self, render_options: &RenderOptions) {
unsafe {
// Set blend.
match render_state.blend {
match render_options.blend {
BlendState::Off => {
gl::Disable(gl::BLEND); ck();
}
@ -91,7 +113,7 @@ impl GLDevice {
}
// Set depth.
match render_state.depth {
match render_options.depth {
None => {
gl::Disable(gl::DEPTH_TEST); ck();
}
@ -103,7 +125,7 @@ impl GLDevice {
}
// Set stencil.
match render_state.stencil {
match render_options.stencil {
None => {
gl::Disable(gl::STENCIL_TEST); ck();
}
@ -123,14 +145,50 @@ impl GLDevice {
}
// Set color mask.
let color_mask = render_state.color_mask as GLboolean;
let color_mask = render_options.color_mask as GLboolean;
gl::ColorMask(color_mask, color_mask, color_mask, color_mask); ck();
}
}
fn reset_render_state(&self, render_state: &RenderState) {
fn set_uniform(&self, uniform: &GLUniform, data: &UniformData) {
unsafe {
match render_state.blend {
match *data {
UniformData::Int(value) => {
gl::Uniform1i(uniform.location, value); ck();
}
UniformData::Mat4(data) => {
assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4);
let data_ptr: *const F32x4 = data.as_ptr();
gl::UniformMatrix4fv(uniform.location,
1,
gl::FALSE,
data_ptr as *const GLfloat);
}
UniformData::Vec2(data) => {
gl::Uniform2f(uniform.location, data.x(), data.y()); ck();
}
UniformData::Vec4(data) => {
gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck();
}
UniformData::TextureUnit(unit) => {
gl::Uniform1i(uniform.location, unit as GLint); ck();
}
}
}
}
fn reset_render_state(&self, render_state: &RenderState<GLDevice>) {
self.reset_render_options(&render_state.options);
for texture_unit in 0..(render_state.textures.len() as u32) {
self.unbind_texture(texture_unit);
}
self.unuse_program();
self.unbind_vertex_array();
}
fn reset_render_options(&self, render_options: &RenderOptions) {
unsafe {
match render_options.blend {
BlendState::Off => {}
BlendState::RGBOneAlphaOneMinusSrcAlpha |
BlendState::RGBOneAlphaOne |
@ -139,11 +197,11 @@ impl GLDevice {
}
}
if render_state.depth.is_some() {
if render_options.depth.is_some() {
gl::Disable(gl::DEPTH_TEST); ck();
}
if render_state.stencil.is_some() {
if render_options.stencil.is_some() {
gl::StencilMask(!0); ck();
gl::Disable(gl::STENCIL_TEST); ck();
}
@ -165,37 +223,18 @@ impl Device for GLDevice {
type VertexAttr = GLVertexAttr;
fn create_texture(&self, format: TextureFormat, size: Vector2I) -> GLTexture {
let (gl_internal_format, gl_format, gl_type);
match format {
TextureFormat::R8 => {
gl_internal_format = gl::R8 as GLint;
gl_format = gl::RED;
gl_type = gl::UNSIGNED_BYTE;
}
TextureFormat::R16F => {
gl_internal_format = gl::R16F as GLint;
gl_format = gl::RED;
gl_type = gl::HALF_FLOAT;
}
TextureFormat::RGBA8 => {
gl_internal_format = gl::RGBA as GLint;
gl_format = gl::RGBA;
gl_type = gl::UNSIGNED_BYTE;
}
}
let mut texture = GLTexture { gl_texture: 0, size };
let mut texture = GLTexture { gl_texture: 0, size, format };
unsafe {
gl::GenTextures(1, &mut texture.gl_texture); ck();
self.bind_texture(&texture, 0);
gl::TexImage2D(gl::TEXTURE_2D,
0,
gl_internal_format,
format.gl_internal_format(),
size.x() as GLsizei,
size.y() as GLsizei,
0,
gl_format,
gl_type,
format.gl_format(),
format.gl_type(),
ptr::null()); ck();
}
@ -206,7 +245,7 @@ impl Device for GLDevice {
fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> GLTexture {
assert!(data.len() >= size.x() as usize * size.y() as usize);
let mut texture = GLTexture { gl_texture: 0, size };
let mut texture = GLTexture { gl_texture: 0, size, format: TextureFormat::R8 };
unsafe {
gl::GenTextures(1, &mut texture.gl_texture); ck();
self.bind_texture(&texture, 0);
@ -304,12 +343,16 @@ impl Device for GLDevice {
}
}
fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> GLVertexAttr {
fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option<GLVertexAttr> {
let name = CString::new(format!("a{}", name)).unwrap();
let attr = unsafe {
gl::GetAttribLocation(program.gl_program, name.as_ptr() as *const GLchar) as GLuint
gl::GetAttribLocation(program.gl_program, name.as_ptr() as *const GLchar)
}; ck();
GLVertexAttr { attr }
if attr < 0 {
None
} else {
Some(GLVertexAttr { attr: attr as GLuint })
}
}
fn get_uniform(&self, program: &GLProgram, name: &str) -> GLUniform {
@ -320,13 +363,14 @@ impl Device for GLDevice {
GLUniform { location }
}
fn use_program(&self, program: &Self::Program) {
unsafe {
gl::UseProgram(program.gl_program); ck();
}
}
fn configure_vertex_attr(&self,
vertex_array: &GLVertexArray,
attr: &GLVertexAttr,
descriptor: &VertexAttrDescriptor) {
debug_assert_ne!(descriptor.stride, 0);
self.bind_vertex_array(vertex_array);
fn configure_vertex_attr(&self, attr: &GLVertexAttr, descriptor: &VertexAttrDescriptor) {
unsafe {
let attr_type = descriptor.attr_type.to_gl_type();
match descriptor.class {
@ -355,41 +399,8 @@ impl Device for GLDevice {
gl::VertexAttribDivisor(attr.attr, descriptor.divisor); ck();
gl::EnableVertexAttribArray(attr.attr); ck();
}
}
fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData) {
unsafe {
match data {
UniformData::Int(value) => {
gl::Uniform1i(uniform.location, value); ck();
}
UniformData::Mat2(data) => {
assert_eq!(mem::size_of::<F32x4>(), 4 * 4);
let data_ptr: *const F32x4 = &data;
gl::UniformMatrix2fv(uniform.location,
1,
gl::FALSE,
data_ptr as *const GLfloat);
}
UniformData::Mat4(data) => {
assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4);
let data_ptr: *const F32x4 = data.as_ptr();
gl::UniformMatrix4fv(uniform.location,
1,
gl::FALSE,
data_ptr as *const GLfloat);
}
UniformData::Vec2(data) => {
gl::Uniform2f(uniform.location, data.x(), data.y()); ck();
}
UniformData::Vec4(data) => {
gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck();
}
UniformData::TextureUnit(unit) => {
gl::Uniform1i(uniform.location, unit as GLint); ck();
}
}
}
self.unbind_vertex_array();
}
fn create_framebuffer(&self, texture: GLTexture) -> GLFramebuffer {
@ -466,77 +477,67 @@ impl Device for GLDevice {
self.set_texture_parameters(texture);
}
fn read_pixels_from_default_framebuffer(&self, size: Vector2I) -> Vec<u8> {
let mut pixels = vec![0; size.x() as usize * size.y() as usize * 4];
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck();
gl::ReadPixels(0,
0,
size.x() as GLsizei,
size.y() as GLsizei,
gl::RGBA,
gl::UNSIGNED_BYTE,
pixels.as_mut_ptr() as *mut GLvoid); ck();
}
fn read_pixels(&self, render_target: &RenderTarget<GLDevice>, viewport: RectI) -> TextureData {
let (origin, size) = (viewport.origin(), viewport.size());
let format = self.render_target_format(render_target);
self.bind_render_target(render_target);
// Flip right-side-up.
let stride = size.x() as usize * 4;
for y in 0..(size.y() as usize / 2) {
let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride);
for offset in 0..stride {
pixels.swap(index_a + offset, index_b + offset);
match format {
TextureFormat::R8 | TextureFormat::RGBA8 => {
let channels = format.channels();
let mut pixels = vec![0; size.x() as usize * size.y() as usize * channels];
unsafe {
gl::ReadPixels(origin.x(),
origin.y(),
size.x() as GLsizei,
size.y() as GLsizei,
format.gl_format(),
format.gl_type(),
pixels.as_mut_ptr() as *mut GLvoid); ck();
}
flip_y(&mut pixels, size, channels);
TextureData::U8(pixels)
}
}
pixels
}
fn clear(&self, params: &ClearParams) {
unsafe {
if let Some(rect) = params.rect {
let (origin, size) = (rect.origin(), rect.size());
gl::Scissor(origin.x(), origin.y(), size.x(), size.y()); ck();
gl::Enable(gl::SCISSOR_TEST); ck();
}
let mut flags = 0;
if let Some(color) = params.color {
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck();
gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck();
flags |= gl::COLOR_BUFFER_BIT;
}
if let Some(depth) = params.depth {
gl::DepthMask(gl::TRUE); ck();
gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES
flags |= gl::DEPTH_BUFFER_BIT;
}
if let Some(stencil) = params.stencil {
gl::StencilMask(!0); ck();
gl::ClearStencil(stencil as GLint); ck();
flags |= gl::STENCIL_BUFFER_BIT;
}
if flags != 0 {
gl::Clear(flags); ck();
}
if params.rect.is_some() {
gl::Disable(gl::SCISSOR_TEST); ck();
TextureFormat::R16F => {
let mut pixels = vec![0; size.x() as usize * size.y() as usize];
unsafe {
gl::ReadPixels(origin.x(),
origin.y(),
size.x() as GLsizei,
size.y() as GLsizei,
format.gl_format(),
format.gl_type(),
pixels.as_mut_ptr() as *mut GLvoid); ck();
}
flip_y(&mut pixels, size, 1);
TextureData::U16(pixels)
}
}
}
fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) {
fn begin_commands(&self) {
// TODO(pcwalton): Add some checks in debug mode to make sure render commands are bracketed
// by these?
}
fn end_commands(&self) {
unsafe { gl::Flush(); }
}
fn draw_arrays(&self, index_count: u32, render_state: &RenderState<Self>) {
self.set_render_state(render_state);
unsafe {
gl::DrawArrays(primitive.to_gl_primitive(), 0, index_count as GLsizei); ck();
gl::DrawArrays(render_state.primitive.to_gl_primitive(),
0,
index_count as GLsizei); ck();
}
self.reset_render_state(render_state);
}
fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) {
fn draw_elements(&self, index_count: u32, render_state: &RenderState<Self>) {
self.set_render_state(render_state);
unsafe {
gl::DrawElements(primitive.to_gl_primitive(),
gl::DrawElements(render_state.primitive.to_gl_primitive(),
index_count as GLsizei,
gl::UNSIGNED_INT,
ptr::null()); ck();
@ -545,13 +546,12 @@ impl Device for GLDevice {
}
fn draw_elements_instanced(&self,
primitive: Primitive,
index_count: u32,
instance_count: u32,
render_state: &RenderState) {
render_state: &RenderState<Self>) {
self.set_render_state(render_state);
unsafe {
gl::DrawElementsInstanced(primitive.to_gl_primitive(),
gl::DrawElementsInstanced(render_state.primitive.to_gl_primitive(),
index_count as GLsizei,
gl::UNSIGNED_INT,
ptr::null(),
@ -584,66 +584,102 @@ impl Device for GLDevice {
}
#[inline]
fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool {
fn get_timer_query(&self, query: &Self::TimerQuery) -> Option<Duration> {
unsafe {
let mut result = 0;
gl::GetQueryObjectiv(query.gl_query, gl::QUERY_RESULT_AVAILABLE, &mut result); ck();
result != gl::FALSE as GLint
}
}
#[inline]
fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration {
unsafe {
if result == gl::FALSE as GLint {
return None;
}
let mut result = 0;
gl::GetQueryObjectui64v(query.gl_query, gl::QUERY_RESULT, &mut result); ck();
Duration::from_nanos(result)
Some(Duration::from_nanos(result))
}
}
#[inline]
fn bind_buffer(&self, vertex_array: &GLVertexArray, buffer: &GLBuffer, target: BufferTarget) {
self.bind_vertex_array(vertex_array);
unsafe {
gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck();
}
self.unbind_vertex_array();
}
#[inline]
fn create_shader(
&self,
resources: &dyn ResourceLoader,
name: &str,
kind: ShaderKind,
) -> Self::Shader {
let suffix = match kind {
ShaderKind::Vertex => 'v',
ShaderKind::Fragment => 'f',
};
let path = format!("shaders/gl3/{}.{}s.glsl", name, suffix);
self.create_shader_from_source(name, &resources.slurp(&path).unwrap(), kind)
}
}
impl GLDevice {
fn bind_render_target(&self, attachment: &RenderTarget<GLDevice>) {
match *attachment {
RenderTarget::Default => self.bind_default_framebuffer(),
RenderTarget::Framebuffer(framebuffer) => self.bind_framebuffer(framebuffer),
}
}
fn bind_vertex_array(&self, vertex_array: &GLVertexArray) {
unsafe {
gl::BindVertexArray(vertex_array.gl_vertex_array); ck();
}
}
#[inline]
fn bind_buffer(&self, buffer: &GLBuffer, target: BufferTarget) {
fn unbind_vertex_array(&self) {
unsafe {
gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck();
gl::BindVertexArray(0); ck();
}
}
#[inline]
fn bind_default_framebuffer(&self, viewport: RectI) {
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck();
gl::Viewport(viewport.origin().x(),
viewport.origin().y(),
viewport.size().x(),
viewport.size().y()); ck();
}
}
#[inline]
fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) {
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer); ck();
gl::Viewport(0, 0, framebuffer.texture.size.x(), framebuffer.texture.size.y()); ck();
}
}
#[inline]
fn bind_texture(&self, texture: &GLTexture, unit: u32) {
unsafe {
gl::ActiveTexture(gl::TEXTURE0 + unit); ck();
gl::BindTexture(gl::TEXTURE_2D, texture.gl_texture); ck();
}
}
}
impl GLDevice {
fn unbind_texture(&self, unit: u32) {
unsafe {
gl::ActiveTexture(gl::TEXTURE0 + unit); ck();
gl::BindTexture(gl::TEXTURE_2D, 0); ck();
}
}
fn use_program(&self, program: &GLProgram) {
unsafe {
gl::UseProgram(program.gl_program); ck();
}
}
fn unuse_program(&self) {
unsafe {
gl::UseProgram(0); ck();
}
}
fn bind_default_framebuffer(&self) {
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck();
}
}
fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) {
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer); ck();
}
}
fn preprocess(&self, output: &mut Vec<u8>, source: &[u8], version: &str) {
let mut index = 0;
while index < source.len() {
@ -665,6 +701,39 @@ impl GLDevice {
}
}
}
fn clear(&self, ops: &ClearOps) {
unsafe {
let mut flags = 0;
if let Some(color) = ops.color {
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck();
gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck();
flags |= gl::COLOR_BUFFER_BIT;
}
if let Some(depth) = ops.depth {
gl::DepthMask(gl::TRUE); ck();
gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES
flags |= gl::DEPTH_BUFFER_BIT;
}
if let Some(stencil) = ops.stencil {
gl::StencilMask(!0); ck();
gl::ClearStencil(stencil as GLint); ck();
flags |= gl::STENCIL_BUFFER_BIT;
}
if flags != 0 {
gl::Clear(flags); ck();
}
}
}
fn render_target_format(&self, render_target: &RenderTarget<GLDevice>) -> TextureFormat {
match *render_target {
RenderTarget::Default => TextureFormat::RGBA8,
RenderTarget::Framebuffer(ref framebuffer) => {
self.framebuffer_texture(framebuffer).format
}
}
}
}
pub struct GLVertexArray {
@ -749,7 +818,7 @@ impl Drop for GLBuffer {
#[derive(Debug)]
pub struct GLUniform {
pub location: GLint,
location: GLint,
}
pub struct GLProgram {
@ -783,6 +852,7 @@ impl Drop for GLShader {
pub struct GLTexture {
gl_texture: GLuint,
pub size: Vector2I,
pub format: TextureFormat,
}
pub struct GLTimerQuery {
@ -859,7 +929,36 @@ impl StencilFuncExt for StencilFunc {
match self {
StencilFunc::Always => gl::ALWAYS,
StencilFunc::Equal => gl::EQUAL,
StencilFunc::NotEqual => gl::NOTEQUAL,
}
}
}
trait TextureFormatExt {
fn gl_internal_format(self) -> GLint;
fn gl_format(self) -> GLuint;
fn gl_type(self) -> GLuint;
}
impl TextureFormatExt for TextureFormat {
fn gl_internal_format(self) -> GLint {
match self {
TextureFormat::R8 => gl::R8 as GLint,
TextureFormat::R16F => gl::R16F as GLint,
TextureFormat::RGBA8 => gl::RGBA as GLint,
}
}
fn gl_format(self) -> GLuint {
match self {
TextureFormat::R8 | TextureFormat::R16F => gl::RED,
TextureFormat::RGBA8 => gl::RGBA,
}
}
fn gl_type(self) -> GLuint {
match self {
TextureFormat::R8 | TextureFormat::RGBA8 => gl::UNSIGNED_BYTE,
TextureFormat::R16F => gl::HALF_FLOAT,
}
}
}
@ -925,4 +1024,15 @@ fn ck() {
#[cfg(not(debug_assertions))]
fn ck() {}
// Shader preprocessing
// Utilities
// Flips a buffer of image data upside-down.
fn flip_y<T>(pixels: &mut [T], size: Vector2I, channels: usize) {
let stride = size.x() as usize * channels;
for y in 0..(size.y() as usize / 2) {
let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride);
for offset in 0..stride {
pixels.swap(index_a + offset, index_b + offset);
}
}
}

View File

@ -11,6 +11,9 @@ version = "0.21"
default-features = false
features = ["png_codec"]
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"

View File

@ -12,16 +12,16 @@
use crate::resources::ResourceLoader;
use image::ImageFormat;
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::basic::transform3d::Transform3DF;
use pathfinder_geometry::color::ColorF;
use pathfinder_content::color::ColorF;
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform3d::Transform3DF;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_simd::default::F32x4;
use std::time::Duration;
pub mod resources;
pub trait Device {
pub trait Device: Sized {
type Buffer;
type Framebuffer;
type Program;
@ -34,6 +34,8 @@ pub trait Device {
fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture;
fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> Self::Texture;
fn create_shader(&self, resources: &dyn ResourceLoader, name: &str, kind: ShaderKind)
-> Self::Shader;
fn create_shader_from_source(&self, name: &str, source: &[u8], kind: ShaderKind)
-> Self::Shader;
fn create_vertex_array(&self) -> Self::VertexArray;
@ -44,11 +46,16 @@ pub trait Device {
vertex_shader: Self::Shader,
fragment_shader: Self::Shader,
) -> Self::Program;
fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Self::VertexAttr;
fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option<Self::VertexAttr>;
fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform;
fn use_program(&self, program: &Self::Program);
fn configure_vertex_attr(&self, attr: &Self::VertexAttr, descriptor: &VertexAttrDescriptor);
fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData);
fn bind_buffer(&self,
vertex_array: &Self::VertexArray,
buffer: &Self::Buffer,
target: BufferTarget);
fn configure_vertex_attr(&self,
vertex_array: &Self::VertexArray,
attr: &Self::VertexAttr,
descriptor: &VertexAttrDescriptor);
fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer;
fn create_buffer(&self) -> Self::Buffer;
fn allocate_buffer<T>(
@ -61,27 +68,19 @@ pub trait Device {
fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture;
fn texture_size(&self, texture: &Self::Texture) -> Vector2I;
fn upload_to_texture(&self, texture: &Self::Texture, size: Vector2I, data: &[u8]);
fn read_pixels_from_default_framebuffer(&self, size: Vector2I) -> Vec<u8>;
fn clear(&self, params: &ClearParams);
fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState);
fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState);
fn read_pixels(&self, target: &RenderTarget<Self>, viewport: RectI) -> TextureData;
fn begin_commands(&self);
fn end_commands(&self);
fn draw_arrays(&self, index_count: u32, render_state: &RenderState<Self>);
fn draw_elements(&self, index_count: u32, render_state: &RenderState<Self>);
fn draw_elements_instanced(&self,
primitive: Primitive,
index_count: u32,
instance_count: u32,
render_state: &RenderState);
render_state: &RenderState<Self>);
fn create_timer_query(&self) -> Self::TimerQuery;
fn begin_timer_query(&self, query: &Self::TimerQuery);
fn end_timer_query(&self, query: &Self::TimerQuery);
fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool;
fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration;
// TODO(pcwalton): Go bindless...
fn bind_vertex_array(&self, vertex_array: &Self::VertexArray);
fn bind_buffer(&self, buffer: &Self::Buffer, target: BufferTarget);
fn bind_default_framebuffer(&self, viewport: RectI);
fn bind_framebuffer(&self, framebuffer: &Self::Framebuffer);
fn bind_texture(&self, texture: &Self::Texture, unit: u32);
fn get_timer_query(&self, query: &Self::TimerQuery) -> Option<Duration>;
fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture {
let data = resources.slurp(&format!("textures/{}.png", name)).unwrap();
@ -92,20 +91,6 @@ pub trait Device {
self.create_texture_from_data(size, &image)
}
fn create_shader(
&self,
resources: &dyn ResourceLoader,
name: &str,
kind: ShaderKind,
) -> Self::Shader {
let suffix = match kind {
ShaderKind::Vertex => 'v',
ShaderKind::Fragment => 'f',
};
let source = resources.slurp(&format!("shaders/gl3/{}.{}s.glsl", name, suffix)).unwrap();
self.create_shader_from_source(name, &source, kind)
}
fn create_program_from_shader_names(
&self,
resources: &dyn ResourceLoader,
@ -124,7 +109,7 @@ pub trait Device {
}
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TextureFormat {
R8,
R16F,
@ -167,7 +152,6 @@ pub enum ShaderKind {
#[derive(Clone, Copy)]
pub enum UniformData {
Int(i32),
Mat2(F32x4),
Mat4([F32x4; 4]),
Vec2(F32x4),
Vec4(F32x4),
@ -180,23 +164,41 @@ pub enum Primitive {
Lines,
}
#[derive(Clone, Copy, Default)]
pub struct ClearParams {
#[derive(Clone)]
pub struct RenderState<'a, D> where D: Device {
pub target: &'a RenderTarget<'a, D>,
pub program: &'a D::Program,
pub vertex_array: &'a D::VertexArray,
pub primitive: Primitive,
pub uniforms: &'a [(&'a D::Uniform, UniformData)],
pub textures: &'a [&'a D::Texture],
pub viewport: RectI,
pub options: RenderOptions,
}
#[derive(Clone, Debug)]
pub struct RenderOptions {
pub blend: BlendState,
pub depth: Option<DepthState>,
pub stencil: Option<StencilState>,
pub clear_ops: ClearOps,
pub color_mask: bool,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct ClearOps {
pub color: Option<ColorF>,
pub rect: Option<RectI>,
pub depth: Option<f32>,
pub stencil: Option<u8>,
}
#[derive(Clone, Debug)]
pub struct RenderState {
pub blend: BlendState,
pub depth: Option<DepthState>,
pub stencil: Option<StencilState>,
pub color_mask: bool,
#[derive(Clone, Copy, Debug)]
pub enum RenderTarget<'a, D> where D: Device {
Default,
Framebuffer(&'a D::Framebuffer),
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BlendState {
Off,
RGBOneAlphaOne,
@ -228,16 +230,16 @@ pub struct StencilState {
pub enum StencilFunc {
Always,
Equal,
NotEqual,
}
impl Default for RenderState {
impl Default for RenderOptions {
#[inline]
fn default() -> RenderState {
RenderState {
fn default() -> RenderOptions {
RenderOptions {
blend: BlendState::default(),
depth: None,
stencil: None,
clear_ops: ClearOps::default(),
color_mask: true,
}
}
@ -276,6 +278,12 @@ impl Default for StencilFunc {
}
}
#[derive(Clone, Debug)]
pub enum TextureData {
U8(Vec<u8>),
U16(Vec<u16>),
}
impl UniformData {
#[inline]
pub fn from_transform_3d(transform: &Transform3DF) -> UniformData {
@ -291,6 +299,7 @@ pub struct VertexAttrDescriptor {
pub stride: usize,
pub offset: usize,
pub divisor: u32,
pub buffer_index: u32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
@ -299,3 +308,20 @@ pub enum VertexAttrClass {
FloatNorm,
Int,
}
impl TextureFormat {
#[inline]
pub fn channels(self) -> usize {
match self {
TextureFormat::R8 | TextureFormat::R16F => 1,
TextureFormat::RGBA8 => 4,
}
}
}
impl ClearOps {
#[inline]
pub fn has_ops(&self) -> bool {
self.color.is_some() || self.depth.is_some() || self.stencil.is_some()
}
}

24
metal/Cargo.toml Normal file
View File

@ -0,0 +1,24 @@
[package]
name = "pathfinder_metal"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[dependencies]
bitflags = "1.0"
byteorder = "1.3"
block = "0.1"
cocoa = "0.18"
core-foundation = "0.6"
foreign-types = "0.3"
metal = "0.14"
objc = "0.2"
[dependencies.pathfinder_geometry]
path = "../geometry"
[dependencies.pathfinder_gpu]
path = "../gpu"
[dependencies.pathfinder_simd]
path = "../simd"

1485
metal/src/lib.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@ edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[dependencies]
bitflags = "1.0"
byteorder = "1.2"
fixedbitset = "0.1"
hashbrown = "0.1"
@ -17,6 +18,9 @@ smallvec = "0.6"
version = "0.4"
features = ["release_max_level_warn"]
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"

View File

@ -12,14 +12,14 @@
use crate::concurrent::executor::Executor;
use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, FillBatchPrimitive, RenderCommand};
use crate::options::{PreparedRenderOptions, RenderCommandListener};
use crate::options::{PreparedBuildOptions, RenderCommandListener};
use crate::scene::Scene;
use crate::tile_map::DenseTileMap;
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler};
use crate::z_buffer::ZBuffer;
use pathfinder_geometry::basic::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::basic::rect::{RectF, RectI};
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::util;
use pathfinder_simd::default::{F32x4, I32x4};
use std::sync::atomic::{AtomicUsize, Ordering};
@ -28,7 +28,7 @@ use std::u16;
pub(crate) struct SceneBuilder<'a> {
scene: &'a Scene,
built_options: &'a PreparedRenderOptions,
built_options: &'a PreparedBuildOptions,
pub(crate) next_alpha_tile_index: AtomicUsize,
pub(crate) z_buffer: ZBuffer,
@ -38,7 +38,7 @@ pub(crate) struct SceneBuilder<'a> {
impl<'a> SceneBuilder<'a> {
pub(crate) fn new(
scene: &'a Scene,
built_options: &'a PreparedRenderOptions,
built_options: &'a PreparedBuildOptions,
listener: Box<dyn RenderCommandListener>,
) -> SceneBuilder<'a> {
let effective_view_box = scene.effective_view_box(built_options);
@ -76,7 +76,7 @@ impl<'a> SceneBuilder<'a> {
&self,
path_index: usize,
view_box: RectF,
built_options: &PreparedRenderOptions,
built_options: &PreparedBuildOptions,
scene: &Scene,
) -> Vec<AlphaTileBatchPrimitive> {
let path_object = &scene.paths[path_index];

View File

@ -22,9 +22,9 @@
use crate::concurrent::executor::Executor;
use crate::gpu::renderer::Renderer;
use crate::gpu_data::RenderCommand;
use crate::options::{RenderCommandListener, RenderOptions};
use crate::options::{BuildOptions, RenderCommandListener};
use crate::scene::Scene;
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::rect::RectF;
use pathfinder_gpu::Device;
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
@ -59,15 +59,15 @@ impl SceneProxy {
#[inline]
pub fn build_with_listener(&self,
options: RenderOptions,
options: BuildOptions,
listener: Box<dyn RenderCommandListener>) {
self.sender.send(MainToWorkerMsg::Build(options, listener)).unwrap();
}
#[inline]
pub fn build_with_stream(&self, options: RenderOptions) -> RenderCommandStream {
pub fn build_with_stream(&self, options: BuildOptions) -> RenderCommandStream {
let (sender, receiver) = mpsc::sync_channel(MAX_MESSAGES_IN_FLIGHT);
let listener = Box::new(move |command| sender.send(command).unwrap());
let listener = Box::new(move |command| drop(sender.send(command)));
self.build_with_listener(options, listener);
RenderCommandStream::new(receiver)
}
@ -81,11 +81,11 @@ impl SceneProxy {
/// renderer.render_command(&command)
/// }
#[inline]
pub fn build_and_render<D>(&self, renderer: &mut Renderer<D>, options: RenderOptions)
pub fn build_and_render<D>(&self, renderer: &mut Renderer<D>, build_options: BuildOptions)
where D: Device {
renderer.begin_scene();
for command in self.build_with_stream(options) {
renderer.render_command(&command)
for command in self.build_with_stream(build_options) {
renderer.render_command(&command);
}
renderer.end_scene();
}
@ -118,7 +118,7 @@ fn scene_thread<E>(mut scene: Scene,
enum MainToWorkerMsg {
ReplaceScene(Scene),
SetViewBox(RectF),
Build(RenderOptions, Box<dyn RenderCommandListener>),
Build(BuildOptions, Box<dyn RenderCommandListener>),
GetSVG(Sender<Vec<u8>>),
}

View File

@ -16,8 +16,8 @@
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
use crate::gpu::renderer::{RenderStats, RenderTime};
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectI;
use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_gpu::Device;
use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UIPresenter, WINDOW_COLOR};

View File

@ -11,4 +11,5 @@
//! The GPU renderer for Pathfinder 3.
pub mod debug;
pub mod options;
pub mod renderer;

View File

@ -0,0 +1,60 @@
// pathfinder/renderer/src/gpu/options.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_content::color::ColorF;
use pathfinder_gpu::Device;
/// Options that influence rendering.
#[derive(Default)]
pub struct RendererOptions {
pub background_color: Option<ColorF>,
}
#[derive(Clone)]
pub enum DestFramebuffer<D>
where
D: Device,
{
Default {
viewport: RectI,
window_size: Vector2I,
},
Other(D::Framebuffer),
}
impl<D> Default for DestFramebuffer<D> where D: Device {
#[inline]
fn default() -> DestFramebuffer<D> {
DestFramebuffer::Default { viewport: RectI::default(), window_size: Vector2I::default() }
}
}
impl<D> DestFramebuffer<D>
where
D: Device,
{
#[inline]
pub fn full_window(window_size: Vector2I) -> DestFramebuffer<D> {
let viewport = RectI::new(Vector2I::default(), window_size);
DestFramebuffer::Default { viewport, window_size }
}
#[inline]
pub fn window_size(&self, device: &D) -> Vector2I {
match *self {
DestFramebuffer::Default { window_size, .. } => window_size,
DestFramebuffer::Other(ref framebuffer) => {
device.texture_size(device.framebuffer_texture(framebuffer))
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -12,9 +12,9 @@
use crate::options::BoundingQuad;
use crate::tile_map::DenseTileMap;
use pathfinder_geometry::basic::line_segment::{LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectF;
use std::fmt::{Debug, Formatter, Result as DebugResult};
use std::time::Duration;
@ -75,6 +75,7 @@ pub struct SolidTileBatchPrimitive {
pub origin_u: u16,
pub origin_v: u16,
pub object_index: u16,
pub pad: u16,
}
#[derive(Clone, Copy, Debug, Default)]

View File

@ -10,6 +10,8 @@
//! The CPU portion of Pathfinder's renderer.
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;

View File

@ -11,11 +11,11 @@
//! Options that control how rendering is to be performed.
use crate::gpu_data::RenderCommand;
use pathfinder_geometry::basic::vector::{Vector2F, Vector4F};
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::basic::transform2d::Transform2DF;
use pathfinder_geometry::basic::transform3d::Perspective;
use pathfinder_geometry::clip::PolygonClipper3D;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_geometry::transform3d::Perspective;
use pathfinder_geometry::vector::{Vector2F, Vector4F};
use pathfinder_content::clip::PolygonClipper3D;
pub trait RenderCommandListener: Send + Sync {
fn send(&self, command: RenderCommand);
@ -31,16 +31,17 @@ where
}
}
/// Options that influence scene building.
#[derive(Clone, Default)]
pub struct RenderOptions {
pub struct BuildOptions {
pub transform: RenderTransform,
pub dilation: Vector2F,
pub subpixel_aa_enabled: bool,
}
impl RenderOptions {
pub(crate) fn prepare(self, bounds: RectF) -> PreparedRenderOptions {
PreparedRenderOptions {
impl BuildOptions {
pub(crate) fn prepare(self, bounds: RectF) -> PreparedBuildOptions {
PreparedBuildOptions {
transform: self.transform.prepare(bounds),
dilation: self.dilation,
subpixel_aa_enabled: self.subpixel_aa_enabled,
@ -119,13 +120,13 @@ impl RenderTransform {
}
}
pub(crate) struct PreparedRenderOptions {
pub(crate) struct PreparedBuildOptions {
pub(crate) transform: PreparedRenderTransform,
pub(crate) dilation: Vector2F,
pub(crate) subpixel_aa_enabled: bool,
}
impl PreparedRenderOptions {
impl PreparedBuildOptions {
#[inline]
pub(crate) fn bounding_quad(&self) -> BoundingQuad {
match self.transform {

View File

@ -10,8 +10,8 @@
use crate::gpu_data::PaintData;
use crate::scene::Scene;
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::color::ColorU;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_content::color::ColorU;
const PAINT_TEXTURE_WIDTH: i32 = 256;
const PAINT_TEXTURE_HEIGHT: i32 = 256;

View File

@ -12,15 +12,15 @@
use crate::builder::SceneBuilder;
use crate::concurrent::executor::Executor;
use crate::options::{PreparedRenderOptions, PreparedRenderTransform};
use crate::options::{RenderCommandListener, RenderOptions};
use crate::options::{BuildOptions, PreparedBuildOptions};
use crate::options::{PreparedRenderTransform, RenderCommandListener};
use crate::paint::{Paint, PaintId};
use hashbrown::HashMap;
use pathfinder_geometry::basic::vector::Vector2F;
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::basic::transform2d::Transform2DF;
use pathfinder_geometry::color::ColorU;
use pathfinder_geometry::outline::Outline;
use pathfinder_geometry::vector::Vector2F;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_content::color::ColorU;
use pathfinder_content::outline::Outline;
use std::io::{self, Write};
#[derive(Clone)]
@ -89,7 +89,7 @@ impl Scene {
pub(crate) fn apply_render_options(
&self,
original_outline: &Outline,
options: &PreparedRenderOptions,
options: &PreparedBuildOptions,
) -> Outline {
let effective_view_box = self.effective_view_box(options);
@ -156,7 +156,7 @@ impl Scene {
}
#[inline]
pub(crate) fn effective_view_box(&self, render_options: &PreparedRenderOptions) -> RectF {
pub(crate) fn effective_view_box(&self, render_options: &PreparedBuildOptions) -> RectF {
if render_options.subpixel_aa_enabled {
self.view_box.scale_xy(Vector2F::new(3.0, 1.0))
} else {
@ -166,7 +166,7 @@ impl Scene {
#[inline]
pub fn build<E>(&self,
options: RenderOptions,
options: BuildOptions,
listener: Box<dyn RenderCommandListener>,
executor: &E)
where E: Executor {

View File

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectI;
#[derive(Debug)]
pub struct DenseTileMap<T> {

View File

@ -12,11 +12,11 @@ use crate::builder::SceneBuilder;
use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, TileObjectPrimitive};
use crate::paint::{self, PaintId};
use crate::sorted_vector::SortedVector;
use pathfinder_geometry::basic::line_segment::LineSegment2F;
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::basic::rect::{RectF, RectI};
use pathfinder_geometry::outline::{Contour, Outline, PointIndex};
use pathfinder_geometry::segment::Segment;
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_content::outline::{Contour, Outline, PointIndex};
use pathfinder_content::segment::Segment;
use std::cmp::Ordering;
use std::mem;

View File

@ -15,8 +15,8 @@ use crate::paint;
use crate::scene::PathObject;
use crate::tile_map::DenseTileMap;
use crate::tiles;
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_geometry::rect::RectF;
use std::ops::Range;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
@ -91,6 +91,7 @@ impl SolidTileBatchPrimitive {
object_index: object_index,
origin_u: origin_uv.x() as u16,
origin_v: origin_uv.y() as u16,
pad: 0,
}
}
}

View File

@ -0,0 +1,49 @@
Copyright 2011 Red Hat, Inc.,
with Reserved Font Name OVERPASS.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -14,10 +16,10 @@ precision highp float;
uniform vec2 uFramebufferSize;
in vec2 aPosition;
in ivec2 aPosition;
void main(){
vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0;
vec2 position = vec2(aPosition)/ uFramebufferSize * 2.0 - 1.0;
gl_Position = vec4(position . x, - position . y, 0.0, 1.0);
}

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -15,14 +17,14 @@ precision highp float;
uniform vec2 uFramebufferSize;
uniform vec2 uTextureSize;
in vec2 aPosition;
in vec2 aTexCoord;
in ivec2 aPosition;
in ivec2 aTexCoord;
out vec2 vTexCoord;
void main(){
vTexCoord = aTexCoord / uTextureSize;
vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0;
vTexCoord = vec2(aTexCoord)/ uTextureSize;
vec2 position = vec2(aPosition)/ uFramebufferSize * 2.0 - 1.0;
gl_Position = vec4(position . x, - position . y, 0.0, 1.0);
}

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -15,12 +17,12 @@ precision highp float;
uniform mat4 uTransform;
uniform int uGridlineCount;
in vec2 aPosition;
in ivec2 aPosition;
out vec2 vTexCoord;
void main(){
vTexCoord = aPosition * float(uGridlineCount);
gl_Position = uTransform * vec4(aPosition . x, 0.0, aPosition . y, 1.0);
vTexCoord = vec2(aPosition * uGridlineCount);
gl_Position = uTransform * vec4(ivec4(aPosition . x, 0, aPosition . y, 1));
}

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -15,7 +17,7 @@ precision highp float;
uniform vec2 uFramebufferSize;
uniform vec2 uTileSize;
in vec2 aTessCoord;
in uvec2 aTessCoord;
in uint aFromPx;
in uint aToPx;
in vec2 aFromSubpx;
@ -27,7 +29,7 @@ out vec2 vTo;
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){
uint tilesPerRow = uint(stencilTextureWidth / uTileSize . x);
uvec2 tileOffset = uvec2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow);
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
return vec2(tileOffset)* uTileSize;
}
@ -38,11 +40,11 @@ void main(){
vec2 to = vec2(aToPx & 15u, aToPx >> 4u)+ aToSubpx;
vec2 position;
if(aTessCoord . x < 0.5)
if(aTessCoord . x == 0u)
position . x = floor(min(from . x, to . x));
else
position . x = ceil(max(from . x, to . x));
if(aTessCoord . y < 0.5)
if(aTessCoord . y == 0u)
position . y = floor(min(from . y, to . y));
else
position . y = uTileSize . y;
@ -50,6 +52,10 @@ void main(){
vFrom = from - position;
vTo = to - position;
gl_Position = vec4((tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0, 0.0, 1.0);
vec2 globalPosition =(tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0;
gl_Position = vec4(globalPosition, 0.0, 1.0);
}

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -12,12 +14,18 @@
precision highp float;
in vec2 aPosition;
in ivec2 aPosition;
out vec2 vTexCoord;
void main(){
vTexCoord = aPosition;
gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);
vec2 position = vec2(aPosition);
vTexCoord = position;
gl_Position = vec4(vec2(position)* 2.0 - 1.0, 0.0, 1.0);
}

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -14,12 +16,18 @@ precision highp float;
uniform mat4 uNewTransform;
in vec2 aPosition;
in ivec2 aPosition;
out vec2 vTexCoord;
void main(){
vTexCoord = aPosition;
gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0);
vec2 position = vec2(aPosition);
vTexCoord = position;
gl_Position = uNewTransform * vec4(position, 0.0, 1.0);
}

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -30,10 +32,10 @@ uniform vec2 uTileSize;
uniform vec2 uStencilTextureSize;
uniform vec2 uViewBoxOrigin;
in vec2 aTessCoord;
in uvec2 aTessCoord;
in uvec3 aTileOrigin;
in int aBackdrop;
in uint aTileIndex;
in int aTileIndex;
out vec2 vTexCoord;
out float vBackdrop;
@ -49,9 +51,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){
void computeVaryings(){
vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0;
vec2 pixelPosition =(origin + aTessCoord)* uTileSize + uViewBoxOrigin;
vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin;
vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0);
vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize . x);
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x);
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
vTexCoord = maskTexCoord / uStencilTextureSize;

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -30,10 +32,10 @@ uniform vec2 uTileSize;
uniform vec2 uStencilTextureSize;
uniform vec2 uViewBoxOrigin;
in vec2 aTessCoord;
in uvec2 aTessCoord;
in uvec3 aTileOrigin;
in int aBackdrop;
in uint aTileIndex;
in int aTileIndex;
out vec2 vTexCoord;
out float vBackdrop;
@ -49,9 +51,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){
void computeVaryings(){
vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0;
vec2 pixelPosition =(origin + aTessCoord)* uTileSize + uViewBoxOrigin;
vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin;
vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0);
vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize . x);
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x);
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
vTexCoord = maskTexCoord / uStencilTextureSize;

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -29,19 +31,18 @@ uniform vec2 uFramebufferSize;
uniform vec2 uTileSize;
uniform vec2 uViewBoxOrigin;
in vec2 aTessCoord;
in vec2 aTileOrigin;
in uvec2 aTessCoord;
in ivec2 aTileOrigin;
out vec4 vColor;
vec4 getColor();
void computeVaryings(){
vec2 pixelPosition =(aTileOrigin + aTessCoord)* uTileSize + uViewBoxOrigin;
vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin;
vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0);
vColor = getColor();
gl_Position = vec4(position, 0.0, 1.0);
}

View File

@ -1,4 +1,6 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
@ -29,19 +31,18 @@ uniform vec2 uFramebufferSize;
uniform vec2 uTileSize;
uniform vec2 uViewBoxOrigin;
in vec2 aTessCoord;
in vec2 aTileOrigin;
in uvec2 aTessCoord;
in ivec2 aTileOrigin;
out vec4 vColor;
vec4 getColor();
void computeVaryings(){
vec2 pixelPosition =(aTileOrigin + aTessCoord)* uTileSize + uViewBoxOrigin;
vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin;
vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0);
vColor = getColor();
gl_Position = vec4(position, 0.0, 1.0);
}

View File

@ -1,17 +1,23 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float4* uColor [[id(0)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
};
fragment main0_out main0(float4 uColor [[buffer(0)]])
fragment main0_out main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
out.oFragColor = float4(uColor.xyz, 1.0) * uColor.w;
out.oFragColor = float4((*spvDescriptorSet0.uColor).xyz, 1.0) * (*spvDescriptorSet0.uColor).w;
return out;
}

View File

@ -1,8 +1,14 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float2* uFramebufferSize [[id(0)]];
};
struct main0_out
{
float4 gl_Position [[position]];
@ -10,13 +16,13 @@ struct main0_out
struct main0_in
{
float2 aPosition [[attribute(0)]];
int2 aPosition [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]], float2 uFramebufferSize [[buffer(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float2 position = ((in.aPosition / uFramebufferSize) * 2.0) - float2(1.0);
float2 position = ((float2(in.aPosition) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0);
out.gl_Position = float4(position.x, -position.y, 0.0, 1.0);
return out;
}

View File

@ -1,8 +1,16 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uTexture [[id(0)]];
sampler uTextureSmplr [[id(1)]];
constant float4* uColor [[id(2)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
@ -13,11 +21,11 @@ struct main0_in
float2 vTexCoord [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], float4 uColor [[buffer(0)]], texture2d<float> uTexture [[texture(0)]], sampler uTextureSmplr [[sampler(0)]])
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float alpha = uTexture.sample(uTextureSmplr, in.vTexCoord).x * uColor.w;
out.oFragColor = float4(uColor.xyz, 1.0) * alpha;
float alpha = spvDescriptorSet0.uTexture.sample(spvDescriptorSet0.uTextureSmplr, in.vTexCoord).x * (*spvDescriptorSet0.uColor).w;
out.oFragColor = float4((*spvDescriptorSet0.uColor).xyz, 1.0) * alpha;
return out;
}

View File

@ -1,8 +1,15 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float2* uTextureSize [[id(0)]];
constant float2* uFramebufferSize [[id(1)]];
};
struct main0_out
{
float2 vTexCoord [[user(locn0)]];
@ -11,15 +18,15 @@ struct main0_out
struct main0_in
{
float2 aPosition [[attribute(0)]];
float2 aTexCoord [[attribute(1)]];
int2 aPosition [[attribute(0)]];
int2 aTexCoord [[attribute(1)]];
};
vertex main0_out main0(main0_in in [[stage_in]], float2 uTextureSize [[buffer(0)]], float2 uFramebufferSize [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
out.vTexCoord = in.aTexCoord / uTextureSize;
float2 position = ((in.aPosition / uFramebufferSize) * 2.0) - float2(1.0);
out.vTexCoord = float2(in.aTexCoord) / (*spvDescriptorSet0.uTextureSize);
float2 position = ((float2(in.aPosition) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0);
out.gl_Position = float4(position.x, -position.y, 0.0, 1.0);
return out;
}

View File

@ -1,8 +1,15 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float4* uGridlineColor [[id(0)]];
constant float4* uGroundColor [[id(1)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
@ -13,12 +20,12 @@ struct main0_in
float2 vTexCoord [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], float4 uGridlineColor [[buffer(0)]], float4 uGroundColor [[buffer(1)]])
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float2 texCoordPx = fract(in.vTexCoord) / fwidth(in.vTexCoord);
bool4 _33 = bool4(any(texCoordPx <= float2(1.0)));
out.oFragColor = float4(_33.x ? uGridlineColor.x : uGroundColor.x, _33.y ? uGridlineColor.y : uGroundColor.y, _33.z ? uGridlineColor.z : uGroundColor.z, _33.w ? uGridlineColor.w : uGroundColor.w);
out.oFragColor = float4(_33.x ? (*spvDescriptorSet0.uGridlineColor).x : (*spvDescriptorSet0.uGroundColor).x, _33.y ? (*spvDescriptorSet0.uGridlineColor).y : (*spvDescriptorSet0.uGroundColor).y, _33.z ? (*spvDescriptorSet0.uGridlineColor).z : (*spvDescriptorSet0.uGroundColor).z, _33.w ? (*spvDescriptorSet0.uGridlineColor).w : (*spvDescriptorSet0.uGroundColor).w);
return out;
}

View File

@ -1,8 +1,15 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant int* uGridlineCount [[id(0)]];
constant float4x4* uTransform [[id(1)]];
};
struct main0_out
{
float2 vTexCoord [[user(locn0)]];
@ -11,14 +18,14 @@ struct main0_out
struct main0_in
{
float2 aPosition [[attribute(0)]];
int2 aPosition [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]], int uGridlineCount [[buffer(0)]], float4x4 uTransform [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
out.vTexCoord = in.aPosition * float(uGridlineCount);
out.gl_Position = uTransform * float4(in.aPosition.x, 0.0, in.aPosition.y, 1.0);
out.vTexCoord = float2(in.aPosition * int2((*spvDescriptorSet0.uGridlineCount)));
out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(int4(in.aPosition.x, 0, in.aPosition.y, 1));
return out;
}

View File

@ -1,8 +1,15 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uAreaLUT [[id(0)]];
sampler uAreaLUTSmplr [[id(1)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
@ -14,7 +21,7 @@ struct main0_in
float2 vTo [[user(locn1)]];
};
fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uAreaLUT [[texture(0)]], sampler uAreaLUTSmplr [[sampler(0)]])
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float2 from = in.vFrom;
@ -29,7 +36,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uAreaLUT [[t
float y = mix(left.y, right.y, t);
float d = (right.y - left.y) / (right.x - left.x);
float dX = window.x - window.y;
out.oFragColor = float4(uAreaLUT.sample(uAreaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0))).x * dX);
out.oFragColor = float4(spvDescriptorSet0.uAreaLUT.sample(spvDescriptorSet0.uAreaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0))).x * dX);
return out;
}

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
@ -5,6 +6,12 @@
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float2* uTileSize [[id(0)]];
constant float2* uFramebufferSize [[id(1)]];
};
struct main0_out
{
float2 vFrom [[user(locn0)]];
@ -14,7 +21,7 @@ struct main0_out
struct main0_in
{
float2 aTessCoord [[attribute(0)]];
uint2 aTessCoord [[attribute(0)]];
uint aFromPx [[attribute(1)]];
uint aToPx [[attribute(2)]];
float2 aFromSubpx [[attribute(3)]];
@ -22,23 +29,23 @@ struct main0_in
uint aTileIndex [[attribute(5)]];
};
float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize, thread uint& aTileIndex)
float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize)
{
uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x);
uint2 tileOffset = uint2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow);
uint2 tileOffset = uint2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
return float2(tileOffset) * uTileSize;
}
vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uFramebufferSize [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
uint param = in.aTileIndex;
float param_1 = uFramebufferSize.x;
float2 tileOrigin = computeTileOffset(param, param_1, uTileSize, in.aTileIndex);
float param_1 = (*spvDescriptorSet0.uFramebufferSize).x;
float2 tileOrigin = computeTileOffset(param, param_1, (*spvDescriptorSet0.uTileSize));
float2 from = float2(float(in.aFromPx & 15u), float(in.aFromPx >> 4u)) + in.aFromSubpx;
float2 to = float2(float(in.aToPx & 15u), float(in.aToPx >> 4u)) + in.aToSubpx;
float2 position;
if (in.aTessCoord.x < 0.5)
if (in.aTessCoord.x == 0u)
{
position.x = floor(fast::min(from.x, to.x));
}
@ -46,17 +53,19 @@ vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]],
{
position.x = ceil(fast::max(from.x, to.x));
}
if (in.aTessCoord.y < 0.5)
if (in.aTessCoord.y == 0u)
{
position.y = floor(fast::min(from.y, to.y));
}
else
{
position.y = uTileSize.y;
position.y = (*spvDescriptorSet0.uTileSize).y;
}
out.vFrom = from - position;
out.vTo = to - position;
out.gl_Position = float4((((tileOrigin + position) / uFramebufferSize) * 2.0) - float2(1.0), 0.0, 1.0);
float2 globalPosition = (((tileOrigin + position) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0);
globalPosition.y = -globalPosition.y;
out.gl_Position = float4(globalPosition, 0.0, 1.0);
return out;
}

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
@ -5,6 +6,19 @@
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uGammaLUT [[id(0)]];
sampler uGammaLUTSmplr [[id(1)]];
constant float4* uKernel [[id(2)]];
texture2d<float> uSource [[id(3)]];
sampler uSourceSmplr [[id(4)]];
constant float2* uSourceSize [[id(5)]];
constant int* uGammaCorrectionEnabled [[id(6)]];
constant float4* uBGColor [[id(7)]];
constant float4* uFGColor [[id(8)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
@ -78,42 +92,42 @@ float3 gammaCorrect(thread const float3& bgColor, thread const float3& fgColor,
return float3(gammaCorrectChannel(param, param_1, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_2, param_3, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_4, param_5, uGammaLUT, uGammaLUTSmplr));
}
fragment main0_out main0(main0_in in [[stage_in]], int uGammaCorrectionEnabled [[buffer(2)]], float4 uKernel [[buffer(0)]], float2 uSourceSize [[buffer(1)]], float4 uBGColor [[buffer(3)]], float4 uFGColor [[buffer(4)]], texture2d<float> uGammaLUT [[texture(0)]], texture2d<float> uSource [[texture(0)]], sampler uGammaLUTSmplr [[sampler(0)]], sampler uSourceSmplr [[sampler(0)]])
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float3 alpha;
if (uKernel.w == 0.0)
if ((*spvDescriptorSet0.uKernel).w == 0.0)
{
alpha = uSource.sample(uSourceSmplr, in.vTexCoord).xxx;
alpha = spvDescriptorSet0.uSource.sample(spvDescriptorSet0.uSourceSmplr, in.vTexCoord).xxx;
}
else
{
float param_3 = 1.0 / uSourceSize.x;
float param_3 = 1.0 / (*spvDescriptorSet0.uSourceSize).x;
float4 param;
float param_1;
float4 param_2;
sample9Tap(param, param_1, param_2, param_3, uKernel, uSource, uSourceSmplr, in.vTexCoord);
sample9Tap(param, param_1, param_2, param_3, (*spvDescriptorSet0.uKernel), spvDescriptorSet0.uSource, spvDescriptorSet0.uSourceSmplr, in.vTexCoord);
float4 alphaLeft = param;
float alphaCenter = param_1;
float4 alphaRight = param_2;
float4 param_4 = alphaLeft;
float3 param_5 = float3(alphaCenter, alphaRight.xy);
float r = convolve7Tap(param_4, param_5, uKernel);
float r = convolve7Tap(param_4, param_5, (*spvDescriptorSet0.uKernel));
float4 param_6 = float4(alphaLeft.yzw, alphaCenter);
float3 param_7 = alphaRight.xyz;
float g = convolve7Tap(param_6, param_7, uKernel);
float g = convolve7Tap(param_6, param_7, (*spvDescriptorSet0.uKernel));
float4 param_8 = float4(alphaLeft.zw, alphaCenter, alphaRight.x);
float3 param_9 = alphaRight.yzw;
float b = convolve7Tap(param_8, param_9, uKernel);
float b = convolve7Tap(param_8, param_9, (*spvDescriptorSet0.uKernel));
alpha = float3(r, g, b);
}
if (uGammaCorrectionEnabled != 0)
if ((*spvDescriptorSet0.uGammaCorrectionEnabled) != 0)
{
float3 param_10 = uBGColor.xyz;
float3 param_10 = (*spvDescriptorSet0.uBGColor).xyz;
float3 param_11 = alpha;
alpha = gammaCorrect(param_10, param_11, uGammaLUT, uGammaLUTSmplr);
alpha = gammaCorrect(param_10, param_11, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr);
}
out.oFragColor = float4(mix(uBGColor.xyz, uFGColor.xyz, alpha), 1.0);
out.oFragColor = float4(mix((*spvDescriptorSet0.uBGColor).xyz, (*spvDescriptorSet0.uFGColor).xyz, alpha), 1.0);
return out;
}

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
@ -11,14 +12,16 @@ struct main0_out
struct main0_in
{
float2 aPosition [[attribute(0)]];
int2 aPosition [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
out.vTexCoord = in.aPosition;
out.gl_Position = float4((in.aPosition * 2.0) - float2(1.0), 0.0, 1.0);
float2 position = float2(in.aPosition);
out.vTexCoord = position;
position.y = 1.0 - position.y;
out.gl_Position = float4((float2(position) * 2.0) - float2(1.0), 0.0, 1.0);
return out;
}

View File

@ -1,8 +1,16 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float4x4* uOldTransform [[id(0)]];
texture2d<float> uTexture [[id(1)]];
sampler uTextureSmplr [[id(2)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
@ -13,12 +21,12 @@ struct main0_in
float2 vTexCoord [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], float4x4 uOldTransform [[buffer(0)]], texture2d<float> uTexture [[texture(0)]], sampler uTextureSmplr [[sampler(0)]])
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float4 normTexCoord = uOldTransform * float4(in.vTexCoord, 0.0, 1.0);
float4 normTexCoord = (*spvDescriptorSet0.uOldTransform) * float4(in.vTexCoord, 0.0, 1.0);
float2 texCoord = ((normTexCoord.xy / float2(normTexCoord.w)) + float2(1.0)) * 0.5;
out.oFragColor = uTexture.sample(uTextureSmplr, texCoord);
out.oFragColor = spvDescriptorSet0.uTexture.sample(spvDescriptorSet0.uTextureSmplr, texCoord);
return out;
}

View File

@ -1,8 +1,14 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float4x4* uNewTransform [[id(0)]];
};
struct main0_out
{
float2 vTexCoord [[user(locn0)]];
@ -11,14 +17,16 @@ struct main0_out
struct main0_in
{
float2 aPosition [[attribute(0)]];
int2 aPosition [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]], float4x4 uNewTransform [[buffer(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
out.vTexCoord = in.aPosition;
out.gl_Position = uNewTransform * float4(in.aPosition, 0.0, 1.0);
float2 position = float2(in.aPosition);
out.vTexCoord = position;
position.y = 1.0 - position.y;
out.gl_Position = (*spvDescriptorSet0.uNewTransform) * float4(position, 0.0, 1.0);
return out;
}

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
@ -13,7 +14,7 @@ struct main0_in
float3 aPosition [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
out.gl_Position = float4(in.aPosition, 1.0);

View File

@ -1,8 +1,15 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
@ -15,10 +22,10 @@ struct main0_in
float4 vColor [[user(locn2)]];
};
fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uStencilTexture [[texture(0)]], sampler uStencilTextureSmplr [[sampler(0)]])
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float coverage = abs(uStencilTexture.sample(uStencilTextureSmplr, in.vTexCoord).x + in.vBackdrop);
float coverage = abs(spvDescriptorSet0.uStencilTexture.sample(spvDescriptorSet0.uStencilTextureSmplr, in.vTexCoord).x + in.vBackdrop);
out.oFragColor = float4(in.vColor.xyz, in.vColor.w * coverage);
return out;
}

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
@ -5,6 +6,15 @@
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float2* uTileSize [[id(0)]];
constant float2* uViewBoxOrigin [[id(1)]];
constant float2* uFramebufferSize [[id(2)]];
constant float2* uStencilTextureSize [[id(3)]];
constant float4* uColor [[id(4)]];
};
struct main0_out
{
float2 vTexCoord [[user(locn0)]];
@ -15,10 +25,10 @@ struct main0_out
struct main0_in
{
float2 aTessCoord [[attribute(0)]];
uint2 aTessCoord [[attribute(0)]];
uint3 aTileOrigin [[attribute(1)]];
int aBackdrop [[attribute(2)]];
uint aTileIndex [[attribute(3)]];
int aTileIndex [[attribute(3)]];
};
float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize)
@ -33,25 +43,25 @@ float4 getColor(thread float4 uColor)
return uColor;
}
void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread float2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread uint& 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 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)
{
float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0);
float2 pixelPosition = ((origin + aTessCoord) * uTileSize) + uViewBoxOrigin;
float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin;
float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0);
uint param = aTileIndex;
uint param = uint(aTileIndex);
float param_1 = uStencilTextureSize.x;
float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize);
float2 maskTexCoord = maskTexCoordOrigin + (aTessCoord * uTileSize);
float2 maskTexCoord = maskTexCoordOrigin + (float2(aTessCoord) * uTileSize);
vTexCoord = maskTexCoord / uStencilTextureSize;
vBackdrop = float(aBackdrop);
vColor = getColor(uColor);
gl_Position = float4(position, 0.0, 1.0);
}
vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float2 uStencilTextureSize [[buffer(3)]], float4 uColor [[buffer(4)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
computeVaryings(uTileSize, in.aTileOrigin, in.aTessCoord, uViewBoxOrigin, uFramebufferSize, in.aTileIndex, uStencilTextureSize, out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, uColor);
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));
return out;
}

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
@ -5,6 +6,16 @@
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float2* uTileSize [[id(0)]];
constant float2* uViewBoxOrigin [[id(1)]];
constant float2* uFramebufferSize [[id(2)]];
constant float2* uStencilTextureSize [[id(3)]];
texture2d<float> uPaintTexture [[id(4)]];
sampler uPaintTextureSmplr [[id(5)]];
};
struct main0_out
{
float2 vTexCoord [[user(locn0)]];
@ -15,10 +26,10 @@ struct main0_out
struct main0_in
{
float2 aTessCoord [[attribute(0)]];
uint2 aTessCoord [[attribute(0)]];
uint3 aTileOrigin [[attribute(1)]];
int aBackdrop [[attribute(2)]];
uint aTileIndex [[attribute(3)]];
int aTileIndex [[attribute(3)]];
float2 aColorTexCoord [[attribute(4)]];
};
@ -34,25 +45,25 @@ float4 getColor(thread texture2d<float> uPaintTexture, thread const sampler uPai
return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0));
}
void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread float2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread uint& 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 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)
{
float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0);
float2 pixelPosition = ((origin + aTessCoord) * uTileSize) + uViewBoxOrigin;
float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin;
float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0);
uint param = aTileIndex;
uint param = uint(aTileIndex);
float param_1 = uStencilTextureSize.x;
float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize);
float2 maskTexCoord = maskTexCoordOrigin + (aTessCoord * uTileSize);
float2 maskTexCoord = maskTexCoordOrigin + (float2(aTessCoord) * uTileSize);
vTexCoord = maskTexCoord / uStencilTextureSize;
vBackdrop = float(aBackdrop);
vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord);
gl_Position = float4(position, 0.0, 1.0);
}
vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float2 uStencilTextureSize [[buffer(3)]], texture2d<float> uPaintTexture [[texture(0)]], sampler uPaintTextureSmplr [[sampler(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
computeVaryings(uTileSize, in.aTileOrigin, in.aTessCoord, uViewBoxOrigin, uFramebufferSize, in.aTileIndex, uStencilTextureSize, out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, uPaintTexture, uPaintTextureSmplr, in.aColorTexCoord);
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);
return out;
}

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
@ -5,6 +6,14 @@
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float2* uTileSize [[id(0)]];
constant float2* uViewBoxOrigin [[id(1)]];
constant float2* uFramebufferSize [[id(2)]];
constant float4* uColor [[id(3)]];
};
struct main0_out
{
float4 vColor [[user(locn0)]];
@ -13,8 +22,8 @@ struct main0_out
struct main0_in
{
float2 aTessCoord [[attribute(0)]];
float2 aTileOrigin [[attribute(1)]];
uint2 aTessCoord [[attribute(0)]];
int2 aTileOrigin [[attribute(1)]];
};
float4 getColor(thread float4 uColor)
@ -22,18 +31,18 @@ float4 getColor(thread float4 uColor)
return uColor;
}
void computeVaryings(thread float2& aTileOrigin, thread float2& 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 float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread float4 uColor)
{
float2 pixelPosition = ((aTileOrigin + aTessCoord) * uTileSize) + uViewBoxOrigin;
float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin;
float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0);
vColor = getColor(uColor);
gl_Position = float4(position, 0.0, 1.0);
}
vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float4 uColor [[buffer(3)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
computeVaryings(in.aTileOrigin, in.aTessCoord, uTileSize, uViewBoxOrigin, uFramebufferSize, out.vColor, out.gl_Position, uColor);
computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor));
return out;
}

View File

@ -1,3 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
@ -5,6 +6,15 @@
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float2* uTileSize [[id(0)]];
constant float2* uViewBoxOrigin [[id(1)]];
constant float2* uFramebufferSize [[id(2)]];
texture2d<float> uPaintTexture [[id(3)]];
sampler uPaintTextureSmplr [[id(4)]];
};
struct main0_out
{
float4 vColor [[user(locn0)]];
@ -13,8 +23,8 @@ struct main0_out
struct main0_in
{
float2 aTessCoord [[attribute(0)]];
float2 aTileOrigin [[attribute(1)]];
uint2 aTessCoord [[attribute(0)]];
int2 aTileOrigin [[attribute(1)]];
float2 aColorTexCoord [[attribute(2)]];
};
@ -23,18 +33,18 @@ float4 getColor(thread texture2d<float> uPaintTexture, thread const sampler uPai
return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0));
}
void computeVaryings(thread float2& aTileOrigin, thread float2& 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 float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord)
{
float2 pixelPosition = ((aTileOrigin + aTessCoord) * uTileSize) + uViewBoxOrigin;
float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin;
float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0);
vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord);
gl_Position = float4(position, 0.0, 1.0);
}
vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], texture2d<float> uPaintTexture [[texture(0)]], sampler uPaintTextureSmplr [[sampler(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]])
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
computeVaryings(in.aTileOrigin, in.aTessCoord, uTileSize, uViewBoxOrigin, uFramebufferSize, out.vColor, out.gl_Position, uPaintTexture, uPaintTextureSmplr, in.aColorTexCoord);
computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord);
return out;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
resources/swf/tiger.swf Normal file

Binary file not shown.

View File

@ -37,14 +37,20 @@ INCLUDES=\
OUT=\
$(SHADERS:%=$(TARGET_DIR)/gl3/%) \
$(SHADERS:%.glsl=$(TARGET_DIR)/metal/%.metal) \
$(SHADERS:%.glsl=build/metal/%.spv) \
$(EMPTY)
GLSL_VERSION=330
GLSLANGFLAGS=--auto-map-locations -I.
GLSLANGFLAGS_METAL=$(GLSLANGFLAGS) -DPF_ORIGIN_UPPER_LEFT=1
SPIRVCROSSFLAGS=--msl
SPIRVCROSS?=spirv-cross
SPIRVCROSSFLAGS=--msl --msl-version 020100 --msl-argument-buffers
SED_ARGS=-e "s/\#version 330/\#version \{\{version\}\}/" -e "s/\#line.*$$//"
GLSL_VERSION_HEADER="\#version {{version}}"
HEADER="// Automatically generated from files in pathfinder/shaders/. Do not edit!"
GLSL_SED_ARGS=-e "s/\#version 330//" -e "s/\#line.*$$//"
all: $(OUT)
@ -53,17 +59,17 @@ all: $(OUT)
clean:
rm -f $(OUT)
$(TARGET_DIR)/spirv/%.fs.spv: %.fs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/spirv && glslangValidator $(GLSLANGFLAGS) -G$(GLSL_VERSION) -S frag -o $@ $<
build/metal/%.fs.spv: %.fs.glsl $(INCLUDES)
mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S frag -o $@ $<
$(TARGET_DIR)/gl3/%.fs.glsl: %.fs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/gl3 && glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(SED_ARGS) > $@
mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
$(TARGET_DIR)/spirv/%.vs.spv: %.vs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/spirv && glslangValidator $(GLSLANGFLAGS) -G$(GLSL_VERSION) -S vert -o $@ $<
build/metal/%.vs.spv: %.vs.glsl $(INCLUDES)
mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S vert -o $@ $<
$(TARGET_DIR)/gl3/%.vs.glsl: %.vs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/gl3 && glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(SED_ARGS) > $@
mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
$(TARGET_DIR)/metal/%.metal: $(TARGET_DIR)/spirv/%.spv
mkdir -p $(TARGET_DIR)/metal && spirv-cross $(SPIRVCROSSFLAGS) --output $@ $<
$(TARGET_DIR)/metal/%.metal: build/metal/%.spv
mkdir -p $(TARGET_DIR)/metal && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< | sed $(METAL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )

View File

@ -14,9 +14,9 @@ precision highp float;
uniform vec2 uFramebufferSize;
in vec2 aPosition;
in ivec2 aPosition;
void main() {
vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0;
vec2 position = vec2(aPosition) / uFramebufferSize * 2.0 - 1.0;
gl_Position = vec4(position.x, -position.y, 0.0, 1.0);
}

View File

@ -15,13 +15,13 @@ precision highp float;
uniform vec2 uFramebufferSize;
uniform vec2 uTextureSize;
in vec2 aPosition;
in vec2 aTexCoord;
in ivec2 aPosition;
in ivec2 aTexCoord;
out vec2 vTexCoord;
void main() {
vTexCoord = aTexCoord / uTextureSize;
vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0;
vTexCoord = vec2(aTexCoord) / uTextureSize;
vec2 position = vec2(aPosition) / uFramebufferSize * 2.0 - 1.0;
gl_Position = vec4(position.x, -position.y, 0.0, 1.0);
}

View File

@ -15,11 +15,11 @@ precision highp float;
uniform mat4 uTransform;
uniform int uGridlineCount;
in vec2 aPosition;
in ivec2 aPosition;
out vec2 vTexCoord;
void main() {
vTexCoord = aPosition * float(uGridlineCount);
gl_Position = uTransform * vec4(aPosition.x, 0.0, aPosition.y, 1.0);
vTexCoord = vec2(aPosition * uGridlineCount);
gl_Position = uTransform * vec4(ivec4(aPosition.x, 0, aPosition.y, 1));
}

View File

@ -1,6 +1,6 @@
#version 330
// pathfinder/resources/fill.vs.glsl
// pathfinder/shaders/fill.vs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//
@ -15,7 +15,7 @@ precision highp float;
uniform vec2 uFramebufferSize;
uniform vec2 uTileSize;
in vec2 aTessCoord;
in uvec2 aTessCoord;
in uint aFromPx;
in uint aToPx;
in vec2 aFromSubpx;
@ -27,7 +27,7 @@ out vec2 vTo;
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x);
uvec2 tileOffset = uvec2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow);
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
return vec2(tileOffset) * uTileSize;
}
@ -38,11 +38,11 @@ void main() {
vec2 to = vec2(aToPx & 15u, aToPx >> 4u) + aToSubpx;
vec2 position;
if (aTessCoord.x < 0.5)
if (aTessCoord.x == 0u)
position.x = floor(min(from.x, to.x));
else
position.x = ceil(max(from.x, to.x));
if (aTessCoord.y < 0.5)
if (aTessCoord.y == 0u)
position.y = floor(min(from.y, to.y));
else
position.y = uTileSize.y;
@ -50,5 +50,9 @@ void main() {
vFrom = from - position;
vTo = to - position;
gl_Position = vec4((tileOrigin + position) / uFramebufferSize * 2.0 - 1.0, 0.0, 1.0);
vec2 globalPosition = (tileOrigin + position) / uFramebufferSize * 2.0 - 1.0;
#ifdef PF_ORIGIN_UPPER_LEFT
globalPosition.y = -globalPosition.y;
#endif
gl_Position = vec4(globalPosition, 0.0, 1.0);
}

View File

@ -12,11 +12,17 @@
precision highp float;
in vec2 aPosition;
in ivec2 aPosition;
out vec2 vTexCoord;
void main() {
vTexCoord = aPosition;
gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);
vec2 position = vec2(aPosition);
vTexCoord = position;
#ifdef PF_ORIGIN_UPPER_LEFT
// FIXME(pcwalton): This is wrong.
position.y = 1.0 - position.y;
#endif
gl_Position = vec4(vec2(position) * 2.0 - 1.0, 0.0, 1.0);
}

View File

@ -14,11 +14,17 @@ precision highp float;
uniform mat4 uNewTransform;
in vec2 aPosition;
in ivec2 aPosition;
out vec2 vTexCoord;
void main() {
vTexCoord = aPosition;
gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0);
vec2 position = vec2(aPosition);
vTexCoord = position;
#ifdef PF_ORIGIN_UPPER_LEFT
// FIXME(pcwalton): This is wrong.
position.y = 1.0 - position.y;
#endif
gl_Position = uNewTransform * vec4(position, 0.0, 1.0);
}

View File

@ -13,10 +13,10 @@ uniform vec2 uTileSize;
uniform vec2 uStencilTextureSize;
uniform vec2 uViewBoxOrigin;
in vec2 aTessCoord;
in uvec2 aTessCoord;
in uvec3 aTileOrigin;
in int aBackdrop;
in uint aTileIndex;
in int aTileIndex;
out vec2 vTexCoord;
out float vBackdrop;
@ -32,9 +32,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
void computeVaryings() {
vec2 origin = vec2(aTileOrigin.xy) + vec2(aTileOrigin.z & 15u, aTileOrigin.z >> 4u) * 256.0;
vec2 pixelPosition = (origin + aTessCoord) * uTileSize + uViewBoxOrigin;
vec2 pixelPosition = (origin + vec2(aTessCoord)) * uTileSize + uViewBoxOrigin;
vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0);
vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize.x);
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize.x);
vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize;
vTexCoord = maskTexCoord / uStencilTextureSize;

View File

@ -12,18 +12,17 @@ uniform vec2 uFramebufferSize;
uniform vec2 uTileSize;
uniform vec2 uViewBoxOrigin;
in vec2 aTessCoord;
in vec2 aTileOrigin;
in uvec2 aTessCoord;
in ivec2 aTileOrigin;
out vec4 vColor;
vec4 getColor();
void computeVaryings() {
vec2 pixelPosition = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin;
vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord)) * uTileSize + uViewBoxOrigin;
vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0);
vColor = getColor();
//vColor = vec4(1.0, 0.0, 0.0, 1.0);
gl_Position = vec4(position, 0.0, 1.0);
}

View File

@ -6,7 +6,10 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[dependencies]
bitflags = "1.0"
usvg = "0.4"
usvg = "0.7"
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"

View File

@ -13,14 +13,15 @@
#[macro_use]
extern crate bitflags;
use pathfinder_geometry::basic::line_segment::LineSegment2F;
use pathfinder_geometry::basic::vector::Vector2F;
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::basic::transform2d::{Transform2DF, Transform2DFPathIter};
use pathfinder_geometry::color::ColorU;
use pathfinder_geometry::outline::Outline;
use pathfinder_geometry::segment::{Segment, SegmentFlags};
use pathfinder_geometry::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle};
use pathfinder_content::color::ColorU;
use pathfinder_content::outline::Outline;
use pathfinder_content::segment::{Segment, SegmentFlags};
use pathfinder_content::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle};
use pathfinder_content::transform::Transform2DFPathIter;
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_geometry::vector::Vector2F;
use pathfinder_renderer::paint::Paint;
use pathfinder_renderer::scene::{PathObject, Scene};
use std::fmt::{Display, Formatter, Result as FormatResult};
@ -104,10 +105,6 @@ impl BuiltSVG {
self.result_flags
.insert(BuildResultFlags::UNSUPPORTED_MASK_ATTR);
}
if group.opacity.is_some() {
self.result_flags
.insert(BuildResultFlags::UNSUPPORTED_OPACITY_ATTR);
}
for kid in node.children() {
self.process_node(&kid, &transform)
@ -140,7 +137,7 @@ impl BuiltSVG {
line_width: f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH),
line_cap: LineCap::from_usvg_line_cap(stroke.linecap),
line_join: LineJoin::from_usvg_line_join(stroke.linejoin,
stroke.miterlimit as f32),
stroke.miterlimit.value() as f32),
};
let path = UsvgPathToSegments::new(path.segments.iter().cloned());
@ -194,10 +191,6 @@ impl BuiltSVG {
self.result_flags
.insert(BuildResultFlags::UNSUPPORTED_NESTED_SVG_NODE);
}
NodeKind::Text(..) => {
self.result_flags
.insert(BuildResultFlags::UNSUPPORTED_TEXT_NODE);
}
}
}
}
@ -268,8 +261,8 @@ impl PaintExt for Paint {
fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> RectF {
RectF::new(
Vector2F::new(rect.x as f32, rect.y as f32),
Vector2F::new(rect.width as f32, rect.height as f32),
Vector2F::new(rect.x() as f32, rect.y() as f32),
Vector2F::new(rect.width() as f32, rect.height() as f32),
)
}

24
swf/Cargo.toml Normal file
View File

@ -0,0 +1,24 @@
[package]
name = "pathfinder_swf"
version = "0.1.0"
authors = ["Jon Hardie <jon@hardiesoft.com>"]
edition = "2018"
[dependencies]
swf-parser = "0.7.0"
swf-tree = "0.7.0"
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"
[dependencies.pathfinder_renderer]
path = "../renderer"
[dependencies.pathfinder_gl]
path = "../gl"
[dependencies.pathfinder_gpu]
path = "../gpu"

206
swf/src/lib.rs Normal file
View File

@ -0,0 +1,206 @@
// pathfinder/swf/src/lib.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ops::Add;
use pathfinder_content::color::{ColorU, ColorF};
use pathfinder_content::outline::{Outline, Contour};
use pathfinder_geometry::vector::Vector2F;
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
use pathfinder_renderer::scene::{PathObject, Scene};
use swf_tree;
use swf_tree::tags::SetBackgroundColor;
use swf_tree::{Tag, SRgb8, Movie};
use crate::shapes::{GraphicLayers, PaintOrLine};
mod shapes;
type SymbolId = u16;
// In swf, most values are specified in a fixed point format known as "twips" or twentieths of
// a pixel. We store twips in their integer form, as if we were to convert them to floating point
// at the beginning of the pipeline it's easy to start running into precision errors when we add
// coordinate deltas and then try and compare coords for equality.
#[derive(Copy, Clone, Debug, PartialEq)]
struct Twips(i32);
impl Twips {
// Divide twips by 20 to get the f32 value, just to be used once all processing
// of the swf coords is completed and we want to output.
fn as_f32(&self) -> f32 {
self.0 as f32 / 20.0
}
}
impl Add for Twips {
type Output = Twips;
fn add(self, rhs: Twips) -> Self {
Twips(self.0 + rhs.0)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
struct Point2<T> {
x: T,
y: T
}
impl Point2<Twips> {
fn as_f32(self: Point2<Twips>) -> Point2<f32> {
Point2 {
x: self.x.as_f32(),
y: self.y.as_f32(),
}
}
}
impl Add for Point2<Twips> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Point2 { x: self.x + rhs.x, y: self.y + rhs.y }
}
}
enum Symbol {
Graphic(GraphicLayers),
// Timeline, // TODO(jon)
}
pub struct Stage {
// TODO(jon): Support some kind of lazy frames iterator.
// frames: Timeline,
background_color: SRgb8,
width: i32,
height: i32,
}
impl Stage {
pub fn width(&self) -> i32 {
self.width
}
pub fn height(&self) -> i32 {
self.height
}
pub fn background_color(&self) -> ColorF {
ColorU {
r: self.background_color.r,
g: self.background_color.g,
b: self.background_color.b,
a: 255,
}.to_f32()
}
}
pub struct SymbolLibrary(Vec<Symbol>);
impl SymbolLibrary {
fn add_symbol(&mut self, symbol: Symbol) {
self.0.push(symbol);
}
fn symbols(&self) -> &Vec<Symbol> {
&self.0
}
}
pub fn process_swf_tags(movie: &Movie) -> (SymbolLibrary, Stage) {
let mut symbol_library = SymbolLibrary(Vec::new());
let stage_width = Twips(movie.header.frame_size.x_max);
let stage_height = Twips(movie.header.frame_size.y_max);
// let num_frames = movie.header.frame_count;
let mut stage = Stage {
// frames: Timeline(Vec::new()), // TODO(jon)
background_color: SRgb8 {
r: 255,
g: 255,
b: 255
},
width: stage_width.as_f32() as i32,
height: stage_height.as_f32() as i32,
};
for tag in &movie.tags {
match tag {
Tag::SetBackgroundColor(SetBackgroundColor { color }) => {
stage.background_color = *color;
},
Tag::DefineShape(shape) => {
symbol_library.add_symbol(Symbol::Graphic(shapes::decode_shape(&shape)));
// We will assume that symbol ids just go up, and are 1 based.
let symbol_id: SymbolId = shape.id;
debug_assert!(symbol_id as usize == symbol_library.0.len());
}
_ => ()
}
}
(symbol_library, stage)
}
#[allow(irrefutable_let_patterns)]
pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) {
for symbol in library.symbols() {
// NOTE: Right now symbols only contain graphics.
if let Symbol::Graphic(graphic) = symbol {
for style_layer in graphic.layers() {
let mut path = Outline::new();
let paint_id = scene.push_paint(&style_layer.fill());
for shape in style_layer.shapes() {
let mut contour = Contour::new();
let Point2 { x, y } = shape.outline.first().unwrap().from.as_f32();
contour.push_endpoint(Vector2F::new(x, y));
for segment in &shape.outline {
let Point2 { x, y } = segment.to.as_f32();
match segment.ctrl {
Some(ctrl) => {
let Point2 { x: ctrl_x, y: ctrl_y } = ctrl.as_f32();
contour.push_quadratic(
Vector2F::new(ctrl_x, ctrl_y),
Vector2F::new(x, y)
);
}
None => {
contour.push_endpoint(Vector2F::new(x, y));
},
}
}
if shape.is_closed() {
// NOTE: I'm not sure if this really does anything in this context,
// since all our closed shapes already have coincident start and end points.
contour.close();
}
path.push_contour(contour);
}
if let PaintOrLine::Line(line) = style_layer.kind() {
let mut stroke_to_fill = OutlineStrokeToFill::new(&path, StrokeStyle {
line_width: line.width.as_f32(),
line_cap: line.cap,
line_join: line.join,
});
stroke_to_fill.offset();
path = stroke_to_fill.into_outline();
}
scene.push_path(PathObject::new(
path,
paint_id,
String::new()
));
}
}
}
}

625
swf/src/shapes.rs Normal file
View File

@ -0,0 +1,625 @@
// pathfinder/swf/src/shapes.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use pathfinder_renderer::paint::Paint;
use pathfinder_content::stroke::{LineJoin, LineCap};
use crate::{Twips, Point2};
use std::mem;
use std::cmp::Ordering;
use swf_tree::{
FillStyle,
StraightSRgba8,
LineStyle,
fill_styles,
JoinStyle,
CapStyle,
join_styles,
ShapeRecord,
shape_records,
Vector2D
};
use pathfinder_content::color::ColorU;
use swf_tree::tags::DefineShape;
#[derive(Clone, Copy, Debug)]
pub(crate) struct LineSegment {
pub(crate) from: Point2<Twips>,
pub(crate) to: Point2<Twips>,
pub(crate) ctrl: Option<Point2<Twips>>,
}
impl LineSegment {
fn reverse(&mut self) {
let tmp = self.from;
self.from = self.to;
self.to = tmp;
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub(crate) enum LineDirection {
Left,
Right,
}
impl LineDirection {
fn reverse(&mut self) {
*self = match self {
LineDirection::Right => LineDirection::Left,
LineDirection::Left => LineDirection::Right
};
}
}
#[derive(Clone, Debug)]
pub(crate) struct Shape {
pub(crate) outline: Vec<LineSegment>, // Could be Vec<(start, end)>
direction: LineDirection,
reversed: bool,
}
impl Shape {
pub fn new_with_direction(direction: LineDirection) -> Shape {
Shape {
direction,
outline: Vec::new(),
reversed: false,
}
}
fn prepend_shape(&mut self, shape: &mut Shape) {
shape.append_shape(&self);
mem::swap(&mut self.outline, &mut shape.outline);
}
fn append_shape(&mut self, shape: &Shape) {
self.outline.extend_from_slice(&shape.outline);
}
fn add_line_segment(&mut self, segment: LineSegment) {
self.outline.push(segment);
}
#[inline]
fn len(&self) -> usize {
self.outline.len()
}
#[inline]
fn first(&self) -> &LineSegment {
&self.outline.first().unwrap()
}
#[inline]
fn last(&self) -> &LineSegment {
&self.outline.last().unwrap()
}
#[inline]
fn comes_before(&self, other: &Shape) -> bool {
self.last().to == other.first().from
}
#[inline]
fn comes_after(&self, other: &Shape) -> bool {
self.first().from == other.last().to
}
#[inline]
pub(crate) fn is_closed(&self) -> bool {
self.len() > 1 && self.comes_after(self)
}
fn reverse(&mut self) {
self.reversed = !self.reversed;
self.direction.reverse();
for segment in &mut self.outline {
segment.reverse();
}
self.outline.reverse();
}
}
pub(crate) struct SwfLineStyle {
color: Paint,
pub(crate) width: Twips,
pub(crate) join: LineJoin,
pub(crate) cap: LineCap,
}
pub(crate) enum PaintOrLine {
Paint(Paint),
Line(SwfLineStyle),
}
pub(crate) struct StyleLayer {
fill: PaintOrLine,
// TODO(jon): Maybe shapes are actually slices into a single buffer, then we don't
// need to realloc anything, we're just shuffling shapes around?
shapes: Vec<Shape>,
}
impl StyleLayer {
pub(crate) fn kind(&self) -> &PaintOrLine {
&self.fill
}
fn is_fill(&self) -> bool {
match &self.fill {
PaintOrLine::Paint(_) => true,
PaintOrLine::Line(_) => false,
}
}
pub(crate) fn fill(&self) -> Paint {
match &self.fill {
PaintOrLine::Paint(paint) => *paint,
PaintOrLine::Line(line) => line.color,
}
}
fn push_new_shape(&mut self, direction: LineDirection) {
if let Some(prev_shape) = self.shapes.last_mut() {
// Check that the previous shape was actually used, otherwise reuse it.
if prev_shape.len() != 0 {
self.shapes.push(Shape::new_with_direction(direction))
} else {
prev_shape.direction = direction;
}
} else {
self.shapes.push(Shape::new_with_direction(direction))
}
}
pub(crate) fn shapes(&self) -> &Vec<Shape> {
&self.shapes
}
fn shapes_mut(&mut self) -> &mut Vec<Shape> {
&mut self.shapes
}
fn current_shape_mut(&mut self) -> &mut Shape {
self.shapes.last_mut().unwrap()
}
fn consolidate_edges(&mut self) {
// Reverse left fill shape fragments in place.
{
self.shapes
.iter_mut()
.filter(|frag| frag.direction == LineDirection::Left)
.for_each(|frag| frag.reverse());
}
// Sort shapes into [closed...open]
if self.is_fill() {
// I think sorting is only necessary when we want to have closed shapes,
// lines don't really need this?
self.shapes.sort_unstable_by(|a, b| {
match (a.is_closed(), b.is_closed()) {
(true, true) | (false, false) => Ordering::Equal,
(true, false) => Ordering::Less,
(false, true) => Ordering::Greater,
}
});
}
// A cursor at the index of the first unclosed shape, if any.
let first_open_index = self.shapes
.iter()
.position(|frag| !frag.is_closed());
if let Some(first_open_index) = first_open_index {
if self.shapes.len() - first_open_index >= 2 {
// TODO(jon): This might be sped up by doing it in a way that we don't have
// to allocate more vecs?
// Also, maybe avoid path reversal, and just flag the path as reversed and iterate it
// backwards.
let unmatched_pieces = find_matches(first_open_index, &mut self.shapes, false);
if let Some(mut unmatched_pieces) = unmatched_pieces {
if self.is_fill() {
// If they didn't match before, they're probably parts of inner shapes
// and should be reversed again so they have correct winding
let unclosed = find_matches(0, &mut unmatched_pieces, true);
// If it's a shape we should always be able to close it.
debug_assert!(unclosed.is_none());
}
for dropped in &mut unmatched_pieces {
dropped.reverse();
}
self.shapes.extend_from_slice(&unmatched_pieces);
}
// FIXME(jon): Sometimes we don't get the correct winding of internal closed shapes,
// need to figure out why this happens.
}
}
}
}
fn get_new_styles<'a>(
fills: &'a Vec<FillStyle>,
lines: &'a Vec<LineStyle>
) -> impl Iterator<Item=PaintOrLine> + 'a {
// This enforces the order that fills and line groupings are added in.
// Fills always come first.
fills.iter().filter_map(|fill_style| {
match fill_style {
FillStyle::Solid(
fill_styles::Solid {
color: StraightSRgba8 {
r,
g,
b,
a
}
}
) => {
Some(PaintOrLine::Paint(Paint {
color: ColorU {
r: *r,
g: *g,
b: *b,
a: *a
}
}))
},
_ => unimplemented!("Unimplemented fill style")
}
}).chain(
lines.iter().filter_map(|LineStyle {
width,
fill,
join,
start_cap,
end_cap: _,
/*
TODO(jon): Handle these cases?
pub no_h_scale: bool,
pub no_v_scale: bool,
pub no_close: bool,
pub pixel_hinting: bool,
*/
..
}| {
if let FillStyle::Solid(fill_styles::Solid {
color: StraightSRgba8 {
r,
g,
b,
a
}
}) = fill {
// NOTE: PathFinder doesn't support different cap styles for start and end of
// strokes, so lets assume that they're always the same for the inputs we care about.
// Alternately, we split a line in two with a diff cap style for each.
// assert_eq!(start_cap, end_cap);
Some(PaintOrLine::Line(SwfLineStyle {
width: Twips(*width as i32),
color: Paint { color: ColorU { r: *r, g: *g, b: *b, a: *a } },
join: match join {
JoinStyle::Bevel => LineJoin::Bevel,
JoinStyle::Round => LineJoin::Round,
JoinStyle::Miter(join_styles::Miter { limit }) => {
LineJoin::Miter(*limit as f32)
},
},
cap: match start_cap {
CapStyle::None => LineCap::Butt,
CapStyle::Square => LineCap::Square,
CapStyle::Round => LineCap::Round,
},
}))
} else {
unimplemented!("unimplemented line fill style");
}
})
)
}
pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
let DefineShape {
shape,
// id,
// has_fill_winding, NOTE(jon): Could be important for some inputs?
// has_non_scaling_strokes,
// has_scaling_strokes,
..
} = shape;
let mut graphic = GraphicLayers::new();
let mut current_line_style = None;
let mut current_left_fill = None;
let mut current_right_fill = None;
let mut prev_pos = None;
let mut some_fill_set = false;
let mut both_fills_set;
let mut both_fills_same = false;
let mut both_fills_set_and_same = false;
// Create style groups for initially specified fills and lines.
for fills_or_line in get_new_styles(&shape.initial_styles.fill, &shape.initial_styles.line) {
match fills_or_line {
PaintOrLine::Paint(fill) => graphic.begin_fill_style(fill),
PaintOrLine::Line(line) => graphic.begin_line_style(line),
}
}
for record in &shape.records {
match record {
ShapeRecord::StyleChange(
shape_records::StyleChange {
move_to,
new_styles,
line_style,
left_fill,
right_fill,
}
) => {
// Start a whole new style grouping.
if let Some(new_style) = new_styles {
// Consolidate current style grouping and begin a new one.
graphic.end_style_group();
graphic.begin_style_group();
for fills_or_line in get_new_styles(&new_style.fill, &new_style.line) {
match fills_or_line {
PaintOrLine::Paint(fill) => graphic.begin_fill_style(fill),
PaintOrLine::Line(line) => graphic.begin_line_style(line),
}
}
}
// If there's a change in right fill
if let Some(fill_id) = right_fill {
if *fill_id == 0 {
current_right_fill = None;
} else {
current_right_fill = Some(*fill_id);
graphic
.with_fill_style_mut(*fill_id)
.unwrap()
.push_new_shape(LineDirection::Right);
}
}
// If there's a change in left fill
if let Some(fill_id) = left_fill {
if *fill_id == 0 {
current_left_fill = None;
} else {
current_left_fill = Some(*fill_id);
graphic
.with_fill_style_mut(*fill_id)
.unwrap()
.push_new_shape(LineDirection::Left);
}
}
some_fill_set = current_left_fill.is_some() || current_right_fill.is_some();
both_fills_set = current_left_fill.is_some() && current_right_fill.is_some();
both_fills_same = current_left_fill == current_right_fill;
both_fills_set_and_same = both_fills_set && both_fills_same;
// If there's a change in line style
if let Some(style_id) = line_style {
if *style_id == 0 {
current_line_style = None;
} else {
current_line_style = Some(*style_id);
graphic
.with_line_style_mut(*style_id)
.unwrap()
.push_new_shape(LineDirection::Right);
}
}
// Move to, start new shape fragments with the current styles.
if let Some(Vector2D { x, y }) = move_to {
let to: Point2<Twips> = Point2 { x: Twips(*x), y: Twips(*y) };
prev_pos = Some(to);
// If we didn't start a new shape for the current fill due to a fill
// style change earlier, we definitely want to start a new shape now,
// since each move_to command indicates a new shape fragment.
if let Some(current_right_fill) = current_right_fill {
graphic
.with_fill_style_mut(current_right_fill)
.unwrap()
.push_new_shape(LineDirection::Right);
}
if let Some(current_left_fill) = current_left_fill {
graphic
.with_fill_style_mut(current_left_fill)
.unwrap()
.push_new_shape(LineDirection::Left);
}
if let Some(current_line_style) = current_line_style {
// TODO(jon): Does the direction of this line depend on the current
// fill directions?
graphic
.with_line_style_mut(current_line_style)
.unwrap()
.push_new_shape(LineDirection::Right);
}
}
},
ShapeRecord::Edge(
shape_records::Edge {
delta,
control_delta,
}
) => {
let from = prev_pos.unwrap();
let to = Point2 {
x: from.x + Twips(delta.x),
y: from.y + Twips(delta.y)
};
prev_pos = Some(to);
let new_segment = LineSegment {
from,
to,
ctrl: control_delta.map(|Vector2D { x, y }| {
Point2 {
x: from.x + Twips(x),
y: from.y + Twips(y),
}
}),
};
if some_fill_set && !both_fills_same {
for fill_id in [
current_right_fill,
current_left_fill
].iter() {
if let Some(fill_id) = fill_id {
graphic
.with_fill_style_mut(*fill_id)
.unwrap()
.current_shape_mut()
.add_line_segment(new_segment);
}
}
} else if both_fills_set_and_same {
for (fill_id, direction) in [
(current_right_fill, LineDirection::Right),
(current_left_fill, LineDirection::Left)
].iter() {
// NOTE: If both left and right fill are set the same,
// then we don't record the edge as part of the current shape;
// it's will just be an internal stroke inside an otherwise solid
// shape, and recording these edges as part of the shape means that
// we can't determine the closed shape outline later.
if let Some(fill_id) = fill_id {
graphic
.with_fill_style_mut(*fill_id)
.unwrap()
.push_new_shape(*direction);
}
}
}
if let Some(current_line_style) = current_line_style {
graphic
.with_line_style_mut(current_line_style)
.unwrap()
.current_shape_mut()
.add_line_segment(new_segment);
}
}
}
}
// NOTE: Consolidate current group of styles, joining edges of shapes/strokes where
// possible and forming closed shapes. In swf, all filled shapes should always be closed,
// so there will always be a solution for joining shape line segments together so that
// the start point and end point are coincident.
graphic.end_style_group();
graphic
}
fn find_matches(
mut first_open_index: usize,
shapes: &mut Vec<Shape>,
reverse: bool
) -> Option<Vec<Shape>> {
let mut dropped_pieces = None;
while first_open_index < shapes.len() {
// Take the last unclosed value, and try to join it onto
// one of the other unclosed values.
let mut last = shapes.pop().unwrap();
if reverse {
last.reverse();
}
let mut found_match = false;
for i in first_open_index..shapes.len() {
let fragment = &mut shapes[i];
if last.comes_after(fragment) {
// NOTE(jon): We do realloc quite a bit here, I wonder if it's worth trying
// to avoid that? Could do it with another level of indirection, where an outline
// is a list of fragments.
// println!("app ({}, {})", last.reversed, fragment.reversed);
fragment.append_shape(&last);
found_match = true;
} else if last.comes_before(fragment) {
// println!("pre ({}, {})", last.reversed, fragment.reversed);
fragment.prepend_shape(&mut last);
found_match = true;
}
if found_match {
if fragment.is_closed() {
// Move the shape that was just closed to the left side of the current slice,
// and advance the cursor.
shapes.swap(first_open_index, i);
first_open_index += 1;
}
break;
}
}
if !found_match {
// Have we tried matching a reversed version of this segment?
// move last back onto the array, it will never be closed, presumably because
// it's a set of line segments rather than a shape that needs to be closed.
let dropped_pieces: &mut Vec<Shape> = dropped_pieces.get_or_insert(Vec::new());
dropped_pieces.push(last);
}
}
dropped_pieces
}
pub(crate) struct GraphicLayers {
style_layers: Vec<StyleLayer>,
base_layer_offset: usize,
stroke_layer_offset: Option<usize>,
}
impl GraphicLayers {
fn new() -> GraphicLayers {
GraphicLayers { style_layers: Vec::new(), stroke_layer_offset: None, base_layer_offset: 0 }
}
fn begin_style_group(&mut self) {
self.stroke_layer_offset = None;
self.base_layer_offset = self.style_layers.len();
}
fn begin_fill_style(&mut self, fill: Paint) {
self.style_layers.push(StyleLayer { fill: PaintOrLine::Paint(fill), shapes: Vec::new() })
}
fn begin_line_style(&mut self, line: SwfLineStyle) {
if self.stroke_layer_offset.is_none() {
self.stroke_layer_offset = Some(self.style_layers.len());
}
self.style_layers.push(StyleLayer { fill: PaintOrLine::Line(line), shapes: Vec::new() })
}
fn with_fill_style_mut(&mut self, fill_id: usize) -> Option<&mut StyleLayer> {
self.style_layers.get_mut(self.base_layer_offset + fill_id - 1)
}
fn with_line_style_mut(&mut self, line_id: usize) -> Option<&mut StyleLayer> {
self.style_layers.get_mut((self.stroke_layer_offset.unwrap() + line_id) - 1)
}
pub(crate) fn layers(&self) -> &Vec<StyleLayer> {
&self.style_layers
}
fn end_style_group(&mut self) {
for style_layer in &mut self.style_layers[self.base_layer_offset..] {
// There can be an unused style group at the end of each layer, which we should remove.
if let Some(last) = style_layer.shapes().last() {
if last.len() == 0 {
style_layer.shapes_mut().pop();
}
}
style_layer.consolidate_edges();
}
}
}

42
swf/src/timeline.rs Normal file
View File

@ -0,0 +1,42 @@
// pathfinder/swf/src/timeline.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct PlacementInfo {
symbol_id: u32,
translate_x: Twips,
translate_y: Twips,
}
struct Timeline(Vec<Frame>);
impl Timeline {
fn first(&self) -> &Frame {
&self.0[0]
}
fn last(&self) -> &Frame {
&self.0[self.0.len() - 1]
}
fn first_mut(&mut self) -> &mut Frame {
&mut self.0[0]
}
fn last_mut(&mut self) -> &mut Frame {
let last = self.0.len() - 1;
&mut self.0[last]
}
}
struct Frame {
duration_frames_initial: u16,
duration_remaining_frames: u16,
placements: Vec<PlacementInfo>
}

View File

@ -6,9 +6,12 @@ edition = "2018"
[dependencies]
euclid = "0.19"
font-kit = "0.1"
font-kit = "0.2"
lyon_path = "0.12"
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"
@ -17,4 +20,4 @@ path = "../renderer"
[dependencies.skribo]
git = "https://github.com/linebender/skribo.git"
rev = "a89e9ca99e0d6736ea1b7754517f4df14fd96a2b"
rev = "a2d683856ba1f2d0095b12dd7823d1602a87614e"

View File

@ -13,10 +13,10 @@ use font_kit::error::GlyphLoadingError;
use font_kit::hinting::HintingOptions;
use font_kit::loader::Loader;
use lyon_path::builder::{FlatPathBuilder, PathBuilder};
use pathfinder_geometry::basic::vector::Vector2F;
use pathfinder_geometry::basic::transform2d::Transform2DF;
use pathfinder_geometry::outline::{Contour, Outline};
use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle};
use pathfinder_content::outline::{Contour, Outline};
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
use pathfinder_geometry::transform2d::Transform2DF;
use pathfinder_geometry::vector::Vector2F;
use pathfinder_renderer::paint::PaintId;
use pathfinder_renderer::scene::{PathObject, Scene};
use skribo::{FontCollection, Layout, TextStyle};

View File

@ -13,6 +13,9 @@ serde_json = "1.0"
version = "0.1"
features = ["serde"]
[dependencies.pathfinder_content]
path = "../content"
[dependencies.pathfinder_geometry]
path = "../geometry"

View File

@ -17,12 +17,12 @@
extern crate serde_derive;
use hashbrown::HashMap;
use pathfinder_geometry::basic::vector::{Vector2F, Vector2I};
use pathfinder_geometry::basic::rect::RectI;
use pathfinder_geometry::color::ColorU;
use pathfinder_content::color::ColorU;
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, Device, Primitive};
use pathfinder_gpu::{RenderState, UniformData, VertexAttrClass};
use pathfinder_gpu::{RenderOptions, RenderState, RenderTarget, UniformData, VertexAttrClass};
use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType};
use pathfinder_simd::default::F32x4;
use serde_json;
@ -131,7 +131,11 @@ impl<D> UIPresenter<D> where D: Device {
self.draw_rect(device, rect, color, false);
}
fn draw_rect(&self, device: &D, rect: RectI, color: ColorU, filled: bool) {
fn draw_rect(&self,
device: &D,
rect: RectI,
color: ColorU,
filled: bool) {
let vertex_data = [
DebugSolidVertex::new(rect.origin()),
DebugSolidVertex::new(rect.upper_right()),
@ -160,8 +164,6 @@ impl<D> UIPresenter<D> where D: Device {
index_data: &[u32],
color: ColorU,
filled: bool) {
device.bind_vertex_array(&self.solid_vertex_array.vertex_array);
device.allocate_buffer(&self.solid_vertex_array.vertex_buffer,
BufferData::Memory(vertex_data),
BufferTarget::Vertex,
@ -171,15 +173,23 @@ impl<D> UIPresenter<D> where D: Device {
BufferTarget::Index,
BufferUploadMode::Dynamic);
device.use_program(&self.solid_program.program);
device.set_uniform(&self.solid_program.framebuffer_size_uniform,
UniformData::Vec2(self.framebuffer_size.0.to_f32x4()));
set_color_uniform(device, &self.solid_program.color_uniform, color);
let primitive = if filled { Primitive::Triangles } else { Primitive::Lines };
device.draw_elements(primitive, index_data.len() as u32, &RenderState {
blend: BlendState::RGBOneAlphaOneMinusSrcAlpha,
..RenderState::default()
device.draw_elements(index_data.len() as u32, &RenderState {
target: &RenderTarget::Default,
program: &self.solid_program.program,
vertex_array: &self.solid_vertex_array.vertex_array,
primitive,
uniforms: &[
(&self.solid_program.framebuffer_size_uniform,
UniformData::Vec2(self.framebuffer_size.0.to_f32x4())),
(&self.solid_program.color_uniform, get_color_uniform(color)),
],
textures: &[],
viewport: RectI::new(Vector2I::default(), self.framebuffer_size),
options: RenderOptions {
blend: BlendState::RGBOneAlphaOneMinusSrcAlpha,
..RenderOptions::default()
},
});
}
@ -396,19 +406,25 @@ impl<D> UIPresenter<D> where D: Device {
BufferTarget::Index,
BufferUploadMode::Dynamic);
device.bind_vertex_array(&self.texture_vertex_array.vertex_array);
device.use_program(&self.texture_program.program);
device.set_uniform(&self.texture_program.framebuffer_size_uniform,
UniformData::Vec2(self.framebuffer_size.0.to_f32x4()));
device.set_uniform(&self.texture_program.texture_size_uniform,
UniformData::Vec2(device.texture_size(&texture).0.to_f32x4()));
set_color_uniform(device, &self.texture_program.color_uniform, color);
device.bind_texture(texture, 0);
device.set_uniform(&self.texture_program.texture_uniform, UniformData::TextureUnit(0));
device.draw_elements(Primitive::Triangles, index_data.len() as u32, &RenderState {
blend: BlendState::RGBOneAlphaOneMinusSrcAlpha,
..RenderState::default()
device.draw_elements(index_data.len() as u32, &RenderState {
target: &RenderTarget::Default,
program: &self.texture_program.program,
vertex_array: &self.texture_vertex_array.vertex_array,
primitive: Primitive::Triangles,
textures: &[&texture],
uniforms: &[
(&self.texture_program.framebuffer_size_uniform,
UniformData::Vec2(self.framebuffer_size.0.to_f32x4())),
(&self.texture_program.color_uniform, get_color_uniform(color)),
(&self.texture_program.texture_uniform, UniformData::TextureUnit(0)),
(&self.texture_program.texture_size_uniform,
UniformData::Vec2(device.texture_size(&texture).0.to_f32x4()))
],
viewport: RectI::new(Vector2I::default(), self.framebuffer_size),
options: RenderOptions {
blend: BlendState::RGBOneAlphaOneMinusSrcAlpha,
..RenderOptions::default()
},
});
}
@ -508,9 +524,9 @@ impl<D> UIPresenter<D> where D: Device {
let highlight_size = Vector2I::new(SEGMENT_SIZE, BUTTON_HEIGHT);
let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1);
self.draw_solid_rounded_rect(device,
RectI::new(origin + Vector2I::new(x_offset, 0),
RectI::new(origin + Vector2I::new(x_offset, 0),
highlight_size),
TEXT_COLOR);
TEXT_COLOR);
}
let mut segment_origin = origin + Vector2I::new(SEGMENT_SIZE + 1, 0);
@ -520,9 +536,9 @@ impl<D> UIPresenter<D> where D: Device {
Some(value) if value == prev_segment_index || value == next_segment_index => {}
_ => {
self.draw_line(device,
segment_origin,
segment_origin + Vector2I::new(0, BUTTON_HEIGHT),
TEXT_COLOR);
segment_origin,
segment_origin + Vector2I::new(0, BUTTON_HEIGHT),
TEXT_COLOR);
}
}
segment_origin = segment_origin + Vector2I::new(SEGMENT_SIZE + 1, 0);
@ -585,28 +601,30 @@ impl<D> DebugTextureVertexArray<D> where D: Device {
let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer());
let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position");
let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord");
let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position")
.unwrap();
let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord")
.unwrap();
device.bind_vertex_array(&vertex_array);
device.use_program(&debug_texture_program.program);
device.bind_buffer(&vertex_buffer, BufferTarget::Vertex);
device.bind_buffer(&index_buffer, BufferTarget::Index);
device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor {
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index);
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Float,
attr_type: VertexAttrType::U16,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: DEBUG_TEXTURE_VERTEX_SIZE,
offset: 0,
divisor: 0,
buffer_index: 0,
});
device.configure_vertex_attr(&tex_coord_attr, &VertexAttrDescriptor {
device.configure_vertex_attr(&vertex_array, &tex_coord_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Float,
attr_type: VertexAttrType::U16,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: DEBUG_TEXTURE_VERTEX_SIZE,
offset: 4,
divisor: 0,
buffer_index: 0,
});
DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer }
@ -624,18 +642,18 @@ impl<D> DebugSolidVertexArray<D> where D: Device {
let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer());
let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&debug_solid_program.program, "Position");
device.bind_vertex_array(&vertex_array);
device.use_program(&debug_solid_program.program);
device.bind_buffer(&vertex_buffer, BufferTarget::Vertex);
device.bind_buffer(&index_buffer, BufferTarget::Index);
device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor {
let position_attr =
device.get_vertex_attr(&debug_solid_program.program, "Position").unwrap();
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index);
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Float,
attr_type: VertexAttrType::U16,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: DEBUG_SOLID_VERTEX_SIZE,
offset: 0,
divisor: 0,
buffer_index: 0,
});
DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer }
@ -711,9 +729,9 @@ impl CornerRects {
}
}
fn set_color_uniform<D>(device: &D, uniform: &D::Uniform, color: ColorU) where D: Device {
fn get_color_uniform(color: ColorU) -> UniformData {
let color = F32x4::new(color.r as f32, color.g as f32, color.b as f32, color.a as f32);
device.set_uniform(uniform, UniformData::Vec4(color * F32x4::splat(1.0 / 255.0)));
UniformData::Vec4(color * F32x4::splat(1.0 / 255.0))
}
#[derive(Clone, Copy)]

View File

@ -5,4 +5,4 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[dependencies]
usvg = "0.4"
usvg = "0.7"