Improve C API
I ran `cargo fmt` on the project, which in hindsight was a poor choice. I'm not correcting it right now.
This commit is contained in:
parent
ca750dda7b
commit
5e41738e4c
|
@ -68,8 +68,10 @@ default-members = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
font-kit = { git = "https://git.pfaff.dev/michael/font-kit" }
|
||||||
pathfinder_geometry = { path = "geometry" }
|
pathfinder_geometry = { path = "geometry" }
|
||||||
pathfinder_simd = { path = "simd" }
|
pathfinder_simd = { path = "simd" }
|
||||||
|
skribo = { git = "https://git.pfaff.dev/michael/skribo" }
|
||||||
|
|
||||||
[patch."https://github.com/servo/pathfinder"]
|
[patch."https://github.com/servo/pathfinder"]
|
||||||
pathfinder_content = { path = "content" }
|
pathfinder_content = { path = "content" }
|
||||||
|
|
|
@ -6,18 +6,18 @@ edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
metal = ["dep:core-foundation", "dep:io-surface", "dep:metal", "dep:pathfinder_metal"]
|
metal = ["dep:core-foundation", "dep:io-surface", "dep:metal", "dep:pathfinder_metal"]
|
||||||
|
svg = ["dep:pathfinder_svg", "dep:usvg"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["staticlib", "cdylib"]
|
crate-type = ["staticlib", "cdylib"]
|
||||||
name = "pathfinder"
|
name = "pathfinder"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
font-kit = "0.6"
|
font-kit = "0.13"
|
||||||
foreign-types = "0.3"
|
foreign-types = "0.3"
|
||||||
gl = "0.14"
|
gl = "0.14"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
simple_logger = "4.3"
|
simple_logger = "4.3"
|
||||||
usvg = "0.9"
|
|
||||||
|
|
||||||
[dependencies.log]
|
[dependencies.log]
|
||||||
version = "0.4"
|
version = "0.4"
|
||||||
|
@ -53,6 +53,11 @@ path = "../simd"
|
||||||
|
|
||||||
[dependencies.pathfinder_svg]
|
[dependencies.pathfinder_svg]
|
||||||
path = "../svg"
|
path = "../svg"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[dependencies.usvg]
|
||||||
|
version = "0.10"
|
||||||
|
optional = true
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies.core-foundation]
|
[target.'cfg(target_os = "macos")'.dependencies.core-foundation]
|
||||||
version = "0.6"
|
version = "0.6"
|
||||||
|
|
550
c/src/lib.rs
550
c/src/lib.rs
File diff suppressed because it is too large
Load Diff
|
@ -13,7 +13,7 @@ keywords = ["pathfinder", "canvas", "vector", "graphics", "gpu"]
|
||||||
crate-type = ["rlib", "staticlib"]
|
crate-type = ["rlib", "staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
font-kit = { version = "0.6", optional = true }
|
font-kit = { version = "0.13", optional = true }
|
||||||
|
|
||||||
[dependencies.pathfinder_color]
|
[dependencies.pathfinder_color]
|
||||||
path = "../color"
|
path = "../color"
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
|
|
||||||
//! A simple API for Pathfinder that mirrors a subset of HTML canvas.
|
//! A simple API for Pathfinder that mirrors a subset of HTML canvas.
|
||||||
|
|
||||||
pub use pathfinder_color::{ColorF, ColorU, rgbaf, rgbau, rgbf, rgbu};
|
|
||||||
pub use pathfinder_color::{color_slice_to_u8_slice, u8_slice_to_color_slice, u8_vec_to_color_vec};
|
pub use pathfinder_color::{color_slice_to_u8_slice, u8_slice_to_color_slice, u8_vec_to_color_vec};
|
||||||
|
pub use pathfinder_color::{rgbaf, rgbau, rgbf, rgbu, ColorF, ColorU};
|
||||||
pub use pathfinder_content::fill::FillRule;
|
pub use pathfinder_content::fill::FillRule;
|
||||||
pub use pathfinder_content::stroke::LineCap;
|
|
||||||
pub use pathfinder_content::outline::ArcDirection;
|
pub use pathfinder_content::outline::ArcDirection;
|
||||||
|
pub use pathfinder_content::stroke::LineCap;
|
||||||
pub use pathfinder_geometry::rect::{RectF, RectI};
|
pub use pathfinder_geometry::rect::{RectF, RectI};
|
||||||
pub use pathfinder_geometry::transform2d::Transform2F;
|
pub use pathfinder_geometry::transform2d::Transform2F;
|
||||||
pub use pathfinder_geometry::vector::{IntoVector2F, Vector2F, Vector2I, vec2f, vec2i};
|
pub use pathfinder_geometry::vector::{vec2f, vec2i, IntoVector2F, Vector2F, Vector2I};
|
||||||
|
|
||||||
use pathfinder_content::dash::OutlineDash;
|
use pathfinder_content::dash::OutlineDash;
|
||||||
use pathfinder_content::effects::{BlendMode, BlurDirection, PatternFilter};
|
use pathfinder_content::effects::{BlendMode, BlurDirection, PatternFilter};
|
||||||
|
@ -25,25 +25,25 @@ use pathfinder_content::gradient::Gradient;
|
||||||
use pathfinder_content::outline::{Contour, Outline};
|
use pathfinder_content::outline::{Contour, Outline};
|
||||||
use pathfinder_content::pattern::{Image, Pattern};
|
use pathfinder_content::pattern::{Image, Pattern};
|
||||||
use pathfinder_content::render_target::RenderTargetId;
|
use pathfinder_content::render_target::RenderTargetId;
|
||||||
use pathfinder_content::stroke::{LineJoin as StrokeLineJoin};
|
use pathfinder_content::stroke::LineJoin as StrokeLineJoin;
|
||||||
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_renderer::paint::{Paint, PaintCompositeOp};
|
use pathfinder_renderer::paint::{Paint, PaintCompositeOp};
|
||||||
use pathfinder_renderer::scene::{ClipPath, ClipPathId, DrawPath, RenderTarget, Scene};
|
use pathfinder_renderer::scene::{ClipPath, ClipPathId, DrawPath, RenderTarget, Scene};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::f32::consts::PI;
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
use std::f32::consts::PI;
|
||||||
use std::fmt::{Debug, Error as FmtError, Formatter};
|
use std::fmt::{Debug, Error as FmtError, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use text::CanvasFontContext;
|
pub use text::CanvasFontContext;
|
||||||
|
|
||||||
#[cfg(feature = "pf-text")]
|
|
||||||
use skribo::FontCollection;
|
|
||||||
#[cfg(not(feature = "pf-text"))]
|
#[cfg(not(feature = "pf-text"))]
|
||||||
use crate::text::FontCollection;
|
use crate::text::FontCollection;
|
||||||
|
#[cfg(feature = "pf-text")]
|
||||||
|
use skribo::FontCollection;
|
||||||
|
|
||||||
#[cfg(feature = "pf-text")]
|
#[cfg(feature = "pf-text")]
|
||||||
pub use text::TextMetrics;
|
pub use text::TextMetrics;
|
||||||
|
@ -108,11 +108,16 @@ impl Canvas {
|
||||||
self.scene
|
self.scene
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_context_2d(self, canvas_font_context: CanvasFontContext)
|
pub fn get_context_2d(
|
||||||
-> CanvasRenderingContext2D {
|
self,
|
||||||
|
canvas_font_context: CanvasFontContext,
|
||||||
|
) -> CanvasRenderingContext2D {
|
||||||
#[cfg(feature = "pf-text")]
|
#[cfg(feature = "pf-text")]
|
||||||
let default_font_collection =
|
let default_font_collection = canvas_font_context
|
||||||
canvas_font_context.0.borrow().default_font_collection.clone();
|
.0
|
||||||
|
.borrow()
|
||||||
|
.default_font_collection
|
||||||
|
.clone();
|
||||||
#[cfg(not(feature = "pf-text"))]
|
#[cfg(not(feature = "pf-text"))]
|
||||||
let default_font_collection = Arc::new(FontCollection);
|
let default_font_collection = Arc::new(FontCollection);
|
||||||
CanvasRenderingContext2D {
|
CanvasRenderingContext2D {
|
||||||
|
@ -131,7 +136,8 @@ impl Canvas {
|
||||||
/// This resets the canvas' bounds. Do not call this mid-draw.
|
/// This resets the canvas' bounds. Do not call this mid-draw.
|
||||||
pub fn set_size(&mut self, new_size: Vector2F) {
|
pub fn set_size(&mut self, new_size: Vector2F) {
|
||||||
self.scene.set_bounds(RectF::default());
|
self.scene.set_bounds(RectF::default());
|
||||||
self.scene.set_view_box(RectF::new(Vector2F::zero(), new_size));
|
self.scene
|
||||||
|
.set_view_box(RectF::new(Vector2F::zero(), new_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,12 +278,18 @@ impl CanvasRenderingContext2D {
|
||||||
// Fill and stroke styles
|
// Fill and stroke styles
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fill_style<FS>(&mut self, new_fill_style: FS) where FS: Into<FillStyle> {
|
pub fn set_fill_style<FS>(&mut self, new_fill_style: FS)
|
||||||
|
where
|
||||||
|
FS: Into<FillStyle>,
|
||||||
|
{
|
||||||
self.current_state.fill_paint = new_fill_style.into().into_paint();
|
self.current_state.fill_paint = new_fill_style.into().into_paint();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_stroke_style<FS>(&mut self, new_stroke_style: FS) where FS: Into<FillStyle> {
|
pub fn set_stroke_style<FS>(&mut self, new_stroke_style: FS)
|
||||||
|
where
|
||||||
|
FS: Into<FillStyle>,
|
||||||
|
{
|
||||||
self.current_state.stroke_paint = new_stroke_style.into().into_paint();
|
self.current_state.stroke_paint = new_stroke_style.into().into_paint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,9 +348,11 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
let mut outline = path.into_outline();
|
let mut outline = path.into_outline();
|
||||||
if !self.current_state.line_dash.is_empty() {
|
if !self.current_state.line_dash.is_empty() {
|
||||||
let mut dash = OutlineDash::new(&outline,
|
let mut dash = OutlineDash::new(
|
||||||
|
&outline,
|
||||||
&self.current_state.line_dash,
|
&self.current_state.line_dash,
|
||||||
self.current_state.line_dash_offset);
|
self.current_state.line_dash_offset,
|
||||||
|
);
|
||||||
dash.dash();
|
dash.dash();
|
||||||
outline = dash.into_outline();
|
outline = dash.into_outline();
|
||||||
}
|
}
|
||||||
|
@ -373,23 +387,29 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
let transform = self.current_state.transform;
|
let transform = self.current_state.transform;
|
||||||
let clip_path = self.current_state.clip_path;
|
let clip_path = self.current_state.clip_path;
|
||||||
let blend_mode = self.current_state.global_composite_operation.to_blend_mode();
|
let blend_mode = self
|
||||||
|
.current_state
|
||||||
|
.global_composite_operation
|
||||||
|
.to_blend_mode();
|
||||||
|
|
||||||
outline.transform(&transform);
|
outline.transform(&transform);
|
||||||
|
|
||||||
if !self.current_state.shadow_color.is_fully_transparent() {
|
if !self.current_state.shadow_color.is_fully_transparent() {
|
||||||
let mut outline = outline.clone();
|
let mut outline = outline.clone();
|
||||||
outline.transform(&Transform2F::from_translation(self.current_state.shadow_offset));
|
outline.transform(&Transform2F::from_translation(
|
||||||
|
self.current_state.shadow_offset,
|
||||||
|
));
|
||||||
|
|
||||||
let shadow_blur_info =
|
let shadow_blur_info = push_shadow_blur_render_targets_if_needed(
|
||||||
push_shadow_blur_render_targets_if_needed(&mut self.canvas.scene,
|
&mut self.canvas.scene,
|
||||||
&self.current_state,
|
&self.current_state,
|
||||||
outline.bounds());
|
outline.bounds(),
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(ref shadow_blur_info) = shadow_blur_info {
|
if let Some(ref shadow_blur_info) = shadow_blur_info {
|
||||||
outline.transform(&Transform2F::from_translation(-shadow_blur_info.bounds
|
outline.transform(&Transform2F::from_translation(
|
||||||
.origin()
|
-shadow_blur_info.bounds.origin().to_f32(),
|
||||||
.to_f32()));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per spec the shadow must respect the alpha of the shadowed path, but otherwise have
|
// Per spec the shadow must respect the alpha of the shadowed path, but otherwise have
|
||||||
|
@ -412,9 +432,11 @@ impl CanvasRenderingContext2D {
|
||||||
path.set_blend_mode(blend_mode);
|
path.set_blend_mode(blend_mode);
|
||||||
self.canvas.scene.push_draw_path(path);
|
self.canvas.scene.push_draw_path(path);
|
||||||
|
|
||||||
composite_shadow_blur_render_targets_if_needed(&mut self.canvas.scene,
|
composite_shadow_blur_render_targets_if_needed(
|
||||||
|
&mut self.canvas.scene,
|
||||||
shadow_blur_info,
|
shadow_blur_info,
|
||||||
clip_path);
|
clip_path,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut path = DrawPath::new(outline, paint_id);
|
let mut path = DrawPath::new(outline, paint_id);
|
||||||
|
@ -423,10 +445,11 @@ impl CanvasRenderingContext2D {
|
||||||
path.set_blend_mode(blend_mode);
|
path.set_blend_mode(blend_mode);
|
||||||
self.canvas.scene.push_draw_path(path);
|
self.canvas.scene.push_draw_path(path);
|
||||||
|
|
||||||
fn push_shadow_blur_render_targets_if_needed(scene: &mut Scene,
|
fn push_shadow_blur_render_targets_if_needed(
|
||||||
|
scene: &mut Scene,
|
||||||
current_state: &State,
|
current_state: &State,
|
||||||
outline_bounds: RectF)
|
outline_bounds: RectF,
|
||||||
-> Option<ShadowBlurRenderTargetInfo> {
|
) -> Option<ShadowBlurRenderTargetInfo> {
|
||||||
if current_state.shadow_blur == 0.0 {
|
if current_state.shadow_blur == 0.0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -447,9 +470,11 @@ impl CanvasRenderingContext2D {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn composite_shadow_blur_render_targets_if_needed(scene: &mut Scene,
|
fn composite_shadow_blur_render_targets_if_needed(
|
||||||
|
scene: &mut Scene,
|
||||||
info: Option<ShadowBlurRenderTargetInfo>,
|
info: Option<ShadowBlurRenderTargetInfo>,
|
||||||
clip_path: Option<ClipPathId>) {
|
clip_path: Option<ClipPathId>,
|
||||||
|
) {
|
||||||
let info = match info {
|
let info = match info {
|
||||||
None => return,
|
None => return,
|
||||||
Some(info) => info,
|
Some(info) => info,
|
||||||
|
@ -460,15 +485,21 @@ impl CanvasRenderingContext2D {
|
||||||
paint_y.apply_transform(Transform2F::from_translation(info.bounds.origin().to_f32()));
|
paint_y.apply_transform(Transform2F::from_translation(info.bounds.origin().to_f32()));
|
||||||
|
|
||||||
let sigma = info.sigma;
|
let sigma = info.sigma;
|
||||||
paint_x.set_filter(Some(PatternFilter::Blur { direction: BlurDirection::X, sigma }));
|
paint_x.set_filter(Some(PatternFilter::Blur {
|
||||||
paint_y.set_filter(Some(PatternFilter::Blur { direction: BlurDirection::Y, sigma }));
|
direction: BlurDirection::X,
|
||||||
|
sigma,
|
||||||
|
}));
|
||||||
|
paint_y.set_filter(Some(PatternFilter::Blur {
|
||||||
|
direction: BlurDirection::Y,
|
||||||
|
sigma,
|
||||||
|
}));
|
||||||
|
|
||||||
let paint_id_x = scene.push_paint(&Paint::from_pattern(paint_x));
|
let paint_id_x = scene.push_paint(&Paint::from_pattern(paint_x));
|
||||||
let paint_id_y = scene.push_paint(&Paint::from_pattern(paint_y));
|
let paint_id_y = scene.push_paint(&Paint::from_pattern(paint_y));
|
||||||
|
|
||||||
// TODO(pcwalton): Apply clip as necessary.
|
// TODO(pcwalton): Apply clip as necessary.
|
||||||
let outline_x = Outline::from_rect(RectF::new(vec2f(0.0, 0.0),
|
let outline_x =
|
||||||
info.bounds.size().to_f32()));
|
Outline::from_rect(RectF::new(vec2f(0.0, 0.0), info.bounds.size().to_f32()));
|
||||||
let path_x = DrawPath::new(outline_x, paint_id_x);
|
let path_x = DrawPath::new(outline_x, paint_id_x);
|
||||||
let outline_y = Outline::from_rect(info.bounds.to_f32());
|
let outline_y = Outline::from_rect(info.bounds.to_f32());
|
||||||
let mut path_y = DrawPath::new(outline_y, paint_id_y);
|
let mut path_y = DrawPath::new(outline_y, paint_id_y);
|
||||||
|
@ -479,7 +510,6 @@ impl CanvasRenderingContext2D {
|
||||||
scene.pop_render_target();
|
scene.pop_render_target();
|
||||||
scene.push_draw_path(path_y);
|
scene.push_draw_path(path_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformations
|
// Transformations
|
||||||
|
@ -490,7 +520,10 @@ impl CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale<S>(&mut self, scale: S) where S: IntoVector2F {
|
pub fn scale<S>(&mut self, scale: S)
|
||||||
|
where
|
||||||
|
S: IntoVector2F,
|
||||||
|
{
|
||||||
self.current_state.transform *= Transform2F::from_scale(scale)
|
self.current_state.transform *= Transform2F::from_scale(scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,14 +573,20 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn draw_image<I, L>(&mut self, image: I, dest_location: L)
|
pub fn draw_image<I, L>(&mut self, image: I, dest_location: L)
|
||||||
where I: CanvasImageSource, L: CanvasImageDestLocation {
|
where
|
||||||
|
I: CanvasImageSource,
|
||||||
|
L: CanvasImageDestLocation,
|
||||||
|
{
|
||||||
let pattern = image.to_pattern(self, Transform2F::default());
|
let pattern = image.to_pattern(self, Transform2F::default());
|
||||||
let src_rect = RectF::new(vec2f(0.0, 0.0), pattern.size().to_f32());
|
let src_rect = RectF::new(vec2f(0.0, 0.0), pattern.size().to_f32());
|
||||||
self.draw_subimage(pattern, src_rect, dest_location)
|
self.draw_subimage(pattern, src_rect, dest_location)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_subimage<I, L>(&mut self, image: I, src_location: RectF, dest_location: L)
|
pub fn draw_subimage<I, L>(&mut self, image: I, src_location: RectF, dest_location: L)
|
||||||
where I: CanvasImageSource, L: CanvasImageDestLocation {
|
where
|
||||||
|
I: CanvasImageSource,
|
||||||
|
L: CanvasImageDestLocation,
|
||||||
|
{
|
||||||
let dest_size = dest_location.size().unwrap_or(src_location.size());
|
let dest_size = dest_location.size().unwrap_or(src_location.size());
|
||||||
let scale = dest_size / src_location.size();
|
let scale = dest_size / src_location.size();
|
||||||
let offset = dest_location.origin() - src_location.origin() * scale;
|
let offset = dest_location.origin() - src_location.origin() * scale;
|
||||||
|
@ -563,7 +602,9 @@ impl CanvasRenderingContext2D {
|
||||||
// Pixel manipulation
|
// Pixel manipulation
|
||||||
|
|
||||||
pub fn put_image_data<L>(&mut self, image_data: ImageData, dest_location: L)
|
pub fn put_image_data<L>(&mut self, image_data: ImageData, dest_location: L)
|
||||||
where L: CanvasImageDestLocation {
|
where
|
||||||
|
L: CanvasImageDestLocation,
|
||||||
|
{
|
||||||
let origin = dest_location.origin();
|
let origin = dest_location.origin();
|
||||||
let size = dest_location.size().unwrap_or(image_data.size.to_f32());
|
let size = dest_location.size().unwrap_or(image_data.size.to_f32());
|
||||||
let pattern = Pattern::from_image(image_data.into_image());
|
let pattern = Pattern::from_image(image_data.into_image());
|
||||||
|
@ -610,8 +651,11 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
// Extensions
|
// Extensions
|
||||||
|
|
||||||
pub fn create_pattern_from_canvas(&mut self, canvas: Canvas, transform: Transform2F)
|
pub fn create_pattern_from_canvas(
|
||||||
-> Pattern {
|
&mut self,
|
||||||
|
canvas: Canvas,
|
||||||
|
transform: Transform2F,
|
||||||
|
) -> Pattern {
|
||||||
let subscene_size = canvas.size();
|
let subscene_size = canvas.size();
|
||||||
let subscene = canvas.into_scene();
|
let subscene = canvas.into_scene();
|
||||||
let render_target = RenderTarget::new(subscene_size, String::new());
|
let render_target = RenderTarget::new(subscene_size, String::new());
|
||||||
|
@ -724,7 +768,10 @@ pub struct Path2D {
|
||||||
impl Path2D {
|
impl Path2D {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Path2D {
|
pub fn new() -> Path2D {
|
||||||
Path2D { outline: Outline::new(), current_contour: Contour::new() }
|
Path2D {
|
||||||
|
outline: Outline::new(),
|
||||||
|
current_contour: Contour::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -754,14 +801,17 @@ impl Path2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn arc(&mut self,
|
pub fn arc(
|
||||||
|
&mut self,
|
||||||
center: Vector2F,
|
center: Vector2F,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
start_angle: f32,
|
start_angle: f32,
|
||||||
end_angle: f32,
|
end_angle: f32,
|
||||||
direction: ArcDirection) {
|
direction: ArcDirection,
|
||||||
|
) {
|
||||||
let transform = Transform2F::from_scale(radius).translate(center);
|
let transform = Transform2F::from_scale(radius).translate(center);
|
||||||
self.current_contour.push_arc(&transform, start_angle, end_angle, direction);
|
self.current_contour
|
||||||
|
.push_arc(&transform, start_angle, end_angle, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -778,7 +828,8 @@ impl Path2D {
|
||||||
let chord = LineSegment2F::new(vu0.yx() * vec2f(-1.0, 1.0), vu1.yx() * vec2f(1.0, -1.0));
|
let chord = LineSegment2F::new(vu0.yx() * vec2f(-1.0, 1.0), vu1.yx() * vec2f(1.0, -1.0));
|
||||||
|
|
||||||
// FIXME(pcwalton): Is clockwise direction correct?
|
// FIXME(pcwalton): Is clockwise direction correct?
|
||||||
self.current_contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW);
|
self.current_contour
|
||||||
|
.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rect(&mut self, rect: RectF) {
|
pub fn rect(&mut self, rect: RectF) {
|
||||||
|
@ -790,17 +841,23 @@ impl Path2D {
|
||||||
self.current_contour.close();
|
self.current_contour.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ellipse<A>(&mut self,
|
pub fn ellipse<A>(
|
||||||
|
&mut self,
|
||||||
center: Vector2F,
|
center: Vector2F,
|
||||||
axes: A,
|
axes: A,
|
||||||
rotation: f32,
|
rotation: f32,
|
||||||
start_angle: f32,
|
start_angle: f32,
|
||||||
end_angle: f32)
|
end_angle: f32,
|
||||||
where A: IntoVector2F {
|
) where
|
||||||
|
A: IntoVector2F,
|
||||||
|
{
|
||||||
self.flush_current_contour();
|
self.flush_current_contour();
|
||||||
|
|
||||||
let transform = Transform2F::from_scale(axes).rotate(rotation).translate(center);
|
let transform = Transform2F::from_scale(axes)
|
||||||
self.current_contour.push_arc(&transform, start_angle, end_angle, ArcDirection::CW);
|
.rotate(rotation)
|
||||||
|
.translate(center);
|
||||||
|
self.current_contour
|
||||||
|
.push_arc(&transform, start_angle, end_angle, ArcDirection::CW);
|
||||||
|
|
||||||
if end_angle - start_angle >= 2.0 * PI {
|
if end_angle - start_angle >= 2.0 * PI {
|
||||||
self.current_contour.close();
|
self.current_contour.close();
|
||||||
|
@ -826,7 +883,8 @@ impl Path2D {
|
||||||
|
|
||||||
fn flush_current_contour(&mut self) {
|
fn flush_current_contour(&mut self) {
|
||||||
if !self.current_contour.is_empty() {
|
if !self.current_contour.is_empty() {
|
||||||
self.outline.push_contour(mem::replace(&mut self.current_contour, Contour::new()));
|
self.outline
|
||||||
|
.push_contour(mem::replace(&mut self.current_contour, Contour::new()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -948,8 +1006,11 @@ pub enum ImageSmoothingQuality {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CanvasImageSource {
|
pub trait CanvasImageSource {
|
||||||
fn to_pattern(self, dest_context: &mut CanvasRenderingContext2D, transform: Transform2F)
|
fn to_pattern(
|
||||||
-> Pattern;
|
self,
|
||||||
|
dest_context: &mut CanvasRenderingContext2D,
|
||||||
|
transform: Transform2F,
|
||||||
|
) -> Pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CanvasImageDestLocation {
|
pub trait CanvasImageDestLocation {
|
||||||
|
@ -967,8 +1028,11 @@ impl CanvasImageSource for Pattern {
|
||||||
|
|
||||||
impl CanvasImageSource for Canvas {
|
impl CanvasImageSource for Canvas {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_pattern(self, dest_context: &mut CanvasRenderingContext2D, transform: Transform2F)
|
fn to_pattern(
|
||||||
-> Pattern {
|
self,
|
||||||
|
dest_context: &mut CanvasRenderingContext2D,
|
||||||
|
transform: Transform2F,
|
||||||
|
) -> Pattern {
|
||||||
dest_context.create_pattern_from_canvas(self, transform)
|
dest_context.create_pattern_from_canvas(self, transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1003,7 +1067,10 @@ pub struct ImageData {
|
||||||
impl ImageData {
|
impl ImageData {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(size: Vector2I) -> ImageData {
|
pub fn new(size: Vector2I) -> ImageData {
|
||||||
ImageData { data: vec![ColorU::transparent_black(); size.area() as usize], size }
|
ImageData {
|
||||||
|
data: vec![ColorU::transparent_black(); size.area() as usize],
|
||||||
|
size,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
// For this file only, any copyright is dedicated to the Public Domain.
|
// For this file only, any copyright is dedicated to the Public Domain.
|
||||||
// https://creativecommons.org/publicdomain/zero/1.0/
|
// https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
|
||||||
use super::Path2D;
|
use super::Path2D;
|
||||||
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_path2d_formatting() {
|
pub fn test_path2d_formatting() {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use crate::{CanvasRenderingContext2D, State, TextAlign, TextBaseline};
|
use crate::{CanvasRenderingContext2D, State, TextAlign, TextBaseline};
|
||||||
use font_kit::canvas::RasterizationOptions;
|
use font_kit::canvas::RasterizationOptions;
|
||||||
use font_kit::error::{GlyphLoadingError, FontLoadingError, SelectionError};
|
use font_kit::error::{FontLoadingError, GlyphLoadingError, SelectionError};
|
||||||
use font_kit::family_name::FamilyName;
|
use font_kit::family_name::FamilyName;
|
||||||
use font_kit::handle::Handle;
|
use font_kit::handle::Handle;
|
||||||
use font_kit::hinting::HintingOptions;
|
use font_kit::hinting::HintingOptions;
|
||||||
|
@ -20,7 +20,7 @@ use font_kit::source::{Source, SystemSource};
|
||||||
use font_kit::sources::mem::MemSource;
|
use font_kit::sources::mem::MemSource;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::util;
|
use pathfinder_geometry::util;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
use pathfinder_renderer::paint::PaintId;
|
use pathfinder_renderer::paint::PaintId;
|
||||||
use pathfinder_text::{FontContext, FontRenderOptions, TextRenderMode};
|
use pathfinder_text::{FontContext, FontRenderOptions, TextRenderMode};
|
||||||
use skribo::{FontCollection, FontFamily, FontRef, Layout as SkriboLayout, TextStyle};
|
use skribo::{FontCollection, FontFamily, FontRef, Layout as SkriboLayout, TextStyle};
|
||||||
|
@ -36,8 +36,13 @@ impl CanvasRenderingContext2D {
|
||||||
/// fill the text that you passed into `measure_text()` with the layout-related style
|
/// fill the text that you passed into `measure_text()` with the layout-related style
|
||||||
/// properties set at the time you called that function. This allows Pathfinder to skip having
|
/// properties set at the time you called that function. This allows Pathfinder to skip having
|
||||||
/// to lay out the text again.
|
/// to lay out the text again.
|
||||||
pub fn fill_text<T>(&mut self, text: &T, position: Vector2F) -> Result<(), GlyphLoadingError> where T: ToTextLayout + ?Sized {
|
pub fn fill_text<T>(&mut self, text: &T, position: Vector2F) -> Result<(), GlyphLoadingError>
|
||||||
let paint = self.current_state.resolve_paint(&self.current_state.fill_paint);
|
where
|
||||||
|
T: ToTextLayout + ?Sized,
|
||||||
|
{
|
||||||
|
let paint = self
|
||||||
|
.current_state
|
||||||
|
.resolve_paint(&self.current_state.fill_paint);
|
||||||
let paint_id = self.canvas.scene.push_paint(&paint);
|
let paint_id = self.canvas.scene.push_paint(&paint);
|
||||||
self.fill_or_stroke_text(text, position, paint_id, TextRenderMode::Fill)
|
self.fill_or_stroke_text(text, position, paint_id, TextRenderMode::Fill)
|
||||||
}
|
}
|
||||||
|
@ -48,8 +53,13 @@ impl CanvasRenderingContext2D {
|
||||||
/// stroke the text that you passed into `measure_text()` with the layout-related style
|
/// stroke the text that you passed into `measure_text()` with the layout-related style
|
||||||
/// properties set at the time you called that function. This allows Pathfinder to skip having
|
/// properties set at the time you called that function. This allows Pathfinder to skip having
|
||||||
/// to lay out the text again.
|
/// to lay out the text again.
|
||||||
pub fn stroke_text<T>(&mut self, text: &T, position: Vector2F) -> Result<(), GlyphLoadingError> where T: ToTextLayout + ?Sized {
|
pub fn stroke_text<T>(&mut self, text: &T, position: Vector2F) -> Result<(), GlyphLoadingError>
|
||||||
let paint = self.current_state.resolve_paint(&self.current_state.stroke_paint);
|
where
|
||||||
|
T: ToTextLayout + ?Sized,
|
||||||
|
{
|
||||||
|
let paint = self
|
||||||
|
.current_state
|
||||||
|
.resolve_paint(&self.current_state.stroke_paint);
|
||||||
let paint_id = self.canvas.scene.push_paint(&paint);
|
let paint_id = self.canvas.scene.push_paint(&paint);
|
||||||
let render_mode = TextRenderMode::Stroke(self.current_state.resolve_stroke_style());
|
let render_mode = TextRenderMode::Stroke(self.current_state.resolve_stroke_style());
|
||||||
self.fill_or_stroke_text(text, position, paint_id, render_mode)
|
self.fill_or_stroke_text(text, position, paint_id, render_mode)
|
||||||
|
@ -60,20 +70,30 @@ impl CanvasRenderingContext2D {
|
||||||
/// As an extension, the returned `TextMetrics` object contains all the layout data for the
|
/// As an extension, the returned `TextMetrics` object contains all the layout data for the
|
||||||
/// string and can be used in its place when calling `fill_text()` and `stroke_text()` to avoid
|
/// string and can be used in its place when calling `fill_text()` and `stroke_text()` to avoid
|
||||||
/// needlessly performing layout multiple times.
|
/// needlessly performing layout multiple times.
|
||||||
pub fn measure_text<T>(&self, text: &T) -> TextMetrics where T: ToTextLayout + ?Sized {
|
pub fn measure_text<T>(&self, text: &T) -> TextMetrics
|
||||||
|
where
|
||||||
|
T: ToTextLayout + ?Sized,
|
||||||
|
{
|
||||||
text.layout(CanvasState(&self.current_state)).into_owned()
|
text.layout(CanvasState(&self.current_state)).into_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_or_stroke_text<T>(&mut self,
|
fn fill_or_stroke_text<T>(
|
||||||
|
&mut self,
|
||||||
text: &T,
|
text: &T,
|
||||||
mut position: Vector2F,
|
mut position: Vector2F,
|
||||||
paint_id: PaintId,
|
paint_id: PaintId,
|
||||||
render_mode: TextRenderMode) -> Result<(), GlyphLoadingError>
|
render_mode: TextRenderMode,
|
||||||
where T: ToTextLayout + ?Sized {
|
) -> Result<(), GlyphLoadingError>
|
||||||
|
where
|
||||||
|
T: ToTextLayout + ?Sized,
|
||||||
|
{
|
||||||
let layout = text.layout(CanvasState(&self.current_state));
|
let layout = text.layout(CanvasState(&self.current_state));
|
||||||
|
|
||||||
let clip_path = self.current_state.clip_path;
|
let clip_path = self.current_state.clip_path;
|
||||||
let blend_mode = self.current_state.global_composite_operation.to_blend_mode();
|
let blend_mode = self
|
||||||
|
.current_state
|
||||||
|
.global_composite_operation
|
||||||
|
.to_blend_mode();
|
||||||
|
|
||||||
position += layout.text_origin();
|
position += layout.text_origin();
|
||||||
let transform = self.current_state.transform * Transform2F::from_translation(position);
|
let transform = self.current_state.transform * Transform2F::from_translation(position);
|
||||||
|
@ -82,9 +102,12 @@ impl CanvasRenderingContext2D {
|
||||||
.0
|
.0
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.font_context
|
.font_context
|
||||||
.push_layout(&mut self.canvas.scene,
|
.push_layout(
|
||||||
|
&mut self.canvas.scene,
|
||||||
&layout.skribo_layout,
|
&layout.skribo_layout,
|
||||||
&TextStyle { size: layout.font_size },
|
&TextStyle {
|
||||||
|
size: layout.font_size,
|
||||||
|
},
|
||||||
&FontRenderOptions {
|
&FontRenderOptions {
|
||||||
transform,
|
transform,
|
||||||
render_mode,
|
render_mode,
|
||||||
|
@ -92,7 +115,8 @@ impl CanvasRenderingContext2D {
|
||||||
clip_path,
|
clip_path,
|
||||||
blend_mode,
|
blend_mode,
|
||||||
paint_id,
|
paint_id,
|
||||||
})?;
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -105,7 +129,10 @@ impl CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_font<FC>(&mut self, font_collection: FC) -> Result<(), FontError> where FC: IntoFontCollection {
|
pub fn set_font<FC>(&mut self, font_collection: FC) -> Result<(), FontError>
|
||||||
|
where
|
||||||
|
FC: IntoFontCollection,
|
||||||
|
{
|
||||||
let font_collection = font_collection.into_font_collection(&self.canvas_font_context)?;
|
let font_collection = font_collection.into_font_collection(&self.canvas_font_context)?;
|
||||||
self.current_state.font_collection = font_collection;
|
self.current_state.font_collection = font_collection;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -155,7 +182,13 @@ pub trait ToTextLayout {
|
||||||
|
|
||||||
impl ToTextLayout for str {
|
impl ToTextLayout for str {
|
||||||
fn layout(&self, state: CanvasState) -> Cow<TextMetrics> {
|
fn layout(&self, state: CanvasState) -> Cow<TextMetrics> {
|
||||||
Cow::Owned(TextMetrics::layout(self, &state.0.font_collection, state.0.font_size, state.0.text_align, state.0.text_baseline))
|
Cow::Owned(TextMetrics::layout(
|
||||||
|
self,
|
||||||
|
&state.0.font_collection,
|
||||||
|
state.0.font_size,
|
||||||
|
state.0.text_align,
|
||||||
|
state.0.text_baseline,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,10 +201,12 @@ impl ToTextLayout for String {
|
||||||
|
|
||||||
impl ToTextLayout for Rc<SkriboLayout> {
|
impl ToTextLayout for Rc<SkriboLayout> {
|
||||||
fn layout(&self, state: CanvasState) -> Cow<TextMetrics> {
|
fn layout(&self, state: CanvasState) -> Cow<TextMetrics> {
|
||||||
Cow::Owned(TextMetrics::new((*self).clone(),
|
Cow::Owned(TextMetrics::new(
|
||||||
|
(*self).clone(),
|
||||||
state.0.font_size,
|
state.0.font_size,
|
||||||
state.0.text_align,
|
state.0.text_align,
|
||||||
state.0.text_baseline))
|
state.0.text_baseline,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,8 +238,9 @@ pub(super) struct CanvasFontContextData {
|
||||||
impl CanvasFontContext {
|
impl CanvasFontContext {
|
||||||
pub fn new(font_source: Arc<dyn Source>) -> CanvasFontContext {
|
pub fn new(font_source: Arc<dyn Source>) -> CanvasFontContext {
|
||||||
let mut default_font_collection = FontCollection::new();
|
let mut default_font_collection = FontCollection::new();
|
||||||
if let Ok(default_font) = font_source.select_best_match(&[FamilyName::SansSerif],
|
if let Ok(default_font) =
|
||||||
&Properties::new()) {
|
font_source.select_best_match(&[FamilyName::SansSerif], &Properties::new())
|
||||||
|
{
|
||||||
if let Ok(default_font) = default_font.load() {
|
if let Ok(default_font) = default_font.load() {
|
||||||
default_font_collection.add_family(FontFamily::new_from_font(default_font));
|
default_font_collection.add_family(FontFamily::new_from_font(default_font));
|
||||||
}
|
}
|
||||||
|
@ -224,7 +260,10 @@ impl CanvasFontContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience method to create a font context with a set of in-memory fonts.
|
/// 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> {
|
pub fn from_fonts<I>(fonts: I) -> CanvasFontContext
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Handle>,
|
||||||
|
{
|
||||||
CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap()))
|
CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +275,8 @@ impl CanvasFontContext {
|
||||||
this.font_source
|
this.font_source
|
||||||
.select_by_postscript_name(postscript_name)
|
.select_by_postscript_name(postscript_name)
|
||||||
.map_err(FontError::NotFound)?
|
.map_err(FontError::NotFound)?
|
||||||
.load().map_err(FontError::LoadError)
|
.load()
|
||||||
|
.map_err(FontError::LoadError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,11 +338,12 @@ struct VerticalMetrics {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextMetrics {
|
impl TextMetrics {
|
||||||
pub fn new(skribo_layout: Rc<SkriboLayout>,
|
pub fn new(
|
||||||
|
skribo_layout: Rc<SkriboLayout>,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
align: TextAlign,
|
align: TextAlign,
|
||||||
baseline: TextBaseline)
|
baseline: TextBaseline,
|
||||||
-> TextMetrics {
|
) -> TextMetrics {
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
skribo_layout,
|
skribo_layout,
|
||||||
font_size,
|
font_size,
|
||||||
|
@ -317,10 +358,18 @@ impl TextMetrics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout(string: &str, font_collection: &FontCollection, font_size: f32, text_align: TextAlign, text_baseline: TextBaseline) -> TextMetrics {
|
pub fn layout(
|
||||||
let skribo_layout = Rc::new(skribo::layout(&TextStyle { size: font_size },
|
string: &str,
|
||||||
|
font_collection: &FontCollection,
|
||||||
|
font_size: f32,
|
||||||
|
text_align: TextAlign,
|
||||||
|
text_baseline: TextBaseline,
|
||||||
|
) -> TextMetrics {
|
||||||
|
let skribo_layout = Rc::new(skribo::layout(
|
||||||
|
&TextStyle { size: font_size },
|
||||||
font_collection,
|
font_collection,
|
||||||
string));
|
string,
|
||||||
|
));
|
||||||
TextMetrics::new(skribo_layout, font_size, text_align, text_baseline)
|
TextMetrics::new(skribo_layout, font_size, text_align, text_baseline)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,11 +391,11 @@ impl TextMetrics {
|
||||||
self.text_y_offset.set(Some(match self.baseline {
|
self.text_y_offset.set(Some(match self.baseline {
|
||||||
TextBaseline::Alphabetic => 0.0,
|
TextBaseline::Alphabetic => 0.0,
|
||||||
TextBaseline::Top => vertical_metrics.em_height_ascent,
|
TextBaseline::Top => vertical_metrics.em_height_ascent,
|
||||||
TextBaseline::Middle => {
|
TextBaseline::Middle => util::lerp(
|
||||||
util::lerp(vertical_metrics.em_height_ascent,
|
vertical_metrics.em_height_ascent,
|
||||||
vertical_metrics.em_height_descent,
|
vertical_metrics.em_height_descent,
|
||||||
0.5)
|
0.5,
|
||||||
}
|
),
|
||||||
TextBaseline::Bottom => vertical_metrics.em_height_descent,
|
TextBaseline::Bottom => vertical_metrics.em_height_descent,
|
||||||
TextBaseline::Ideographic => vertical_metrics.ideographic_baseline,
|
TextBaseline::Ideographic => vertical_metrics.ideographic_baseline,
|
||||||
TextBaseline::Hanging => vertical_metrics.hanging_baseline,
|
TextBaseline::Hanging => vertical_metrics.hanging_baseline,
|
||||||
|
@ -368,39 +417,56 @@ impl TextMetrics {
|
||||||
let font_metrics = last_glyph.font.font.metrics();
|
let font_metrics = last_glyph.font.font.metrics();
|
||||||
let scale_factor = self.skribo_layout.size / font_metrics.units_per_em as f32;
|
let scale_factor = self.skribo_layout.size / font_metrics.units_per_em as f32;
|
||||||
let glyph_rect = last_glyph.font.font.typographic_bounds(glyph_id).unwrap();
|
let glyph_rect = last_glyph.font.font.typographic_bounds(glyph_id).unwrap();
|
||||||
self.width.set(Some(last_glyph.offset.x() +
|
self.width.set(Some(
|
||||||
glyph_rect.max_x() * scale_factor));
|
last_glyph.offset.x() + glyph_rect.max_x() * scale_factor,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
self.width.get().unwrap()
|
self.width.get().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn populate_vertical_metrics_if_necessary(&self) {
|
fn populate_vertical_metrics_if_necessary(&self) {
|
||||||
if self.vertical_metrics.get().is_none() {
|
if self.vertical_metrics.get().is_none() {
|
||||||
self.vertical_metrics.set(Some(VerticalMetrics::measure(&self.skribo_layout)));
|
self.vertical_metrics
|
||||||
|
.set(Some(VerticalMetrics::measure(&self.skribo_layout)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn font_bounding_box_ascent(&self) -> f32 {
|
pub fn font_bounding_box_ascent(&self) -> f32 {
|
||||||
self.populate_vertical_metrics_if_necessary();
|
self.populate_vertical_metrics_if_necessary();
|
||||||
self.vertical_metrics.get().unwrap().font_bounding_box_ascent - self.text_y_offset()
|
self.vertical_metrics
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.font_bounding_box_ascent
|
||||||
|
- self.text_y_offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn font_bounding_box_descent(&self) -> f32 {
|
pub fn font_bounding_box_descent(&self) -> f32 {
|
||||||
self.populate_vertical_metrics_if_necessary();
|
self.populate_vertical_metrics_if_necessary();
|
||||||
self.vertical_metrics.get().unwrap().font_bounding_box_descent - self.text_y_offset()
|
self.vertical_metrics
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.font_bounding_box_descent
|
||||||
|
- self.text_y_offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn actual_bounding_box_ascent(&self) -> f32 {
|
pub fn actual_bounding_box_ascent(&self) -> f32 {
|
||||||
self.populate_vertical_metrics_if_necessary();
|
self.populate_vertical_metrics_if_necessary();
|
||||||
self.vertical_metrics.get().unwrap().actual_bounding_box_ascent - self.text_y_offset()
|
self.vertical_metrics
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.actual_bounding_box_ascent
|
||||||
|
- self.text_y_offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn actual_bounding_box_descent(&self) -> f32 {
|
pub fn actual_bounding_box_descent(&self) -> f32 {
|
||||||
self.populate_vertical_metrics_if_necessary();
|
self.populate_vertical_metrics_if_necessary();
|
||||||
self.vertical_metrics.get().unwrap().actual_bounding_box_descent - self.text_y_offset()
|
self.vertical_metrics
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.actual_bounding_box_descent
|
||||||
|
- self.text_y_offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn em_height_ascent(&self) -> f32 {
|
pub fn em_height_ascent(&self) -> f32 {
|
||||||
|
@ -421,14 +487,20 @@ impl TextMetrics {
|
||||||
let glyph_id = first_glyph.glyph_id;
|
let glyph_id = first_glyph.glyph_id;
|
||||||
let font_metrics = first_glyph.font.font.metrics();
|
let font_metrics = first_glyph.font.font.metrics();
|
||||||
let scale_factor = self.skribo_layout.size / font_metrics.units_per_em as f32;
|
let scale_factor = self.skribo_layout.size / font_metrics.units_per_em as f32;
|
||||||
let glyph_rect = first_glyph.font.font.raster_bounds(
|
let glyph_rect = first_glyph
|
||||||
|
.font
|
||||||
|
.font
|
||||||
|
.raster_bounds(
|
||||||
glyph_id,
|
glyph_id,
|
||||||
font_metrics.units_per_em as f32,
|
font_metrics.units_per_em as f32,
|
||||||
Transform2F::default(),
|
Transform2F::default(),
|
||||||
HintingOptions::None,
|
HintingOptions::None,
|
||||||
RasterizationOptions::GrayscaleAa).unwrap();
|
RasterizationOptions::GrayscaleAa,
|
||||||
self.actual_left_extent.set(Some(first_glyph.offset.x() +
|
)
|
||||||
glyph_rect.min_x() as f32 * scale_factor));
|
.unwrap();
|
||||||
|
self.actual_left_extent.set(Some(
|
||||||
|
first_glyph.offset.x() + glyph_rect.min_x() as f32 * scale_factor,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,14 +515,20 @@ impl TextMetrics {
|
||||||
let glyph_id = last_glyph.glyph_id;
|
let glyph_id = last_glyph.glyph_id;
|
||||||
let font_metrics = last_glyph.font.font.metrics();
|
let font_metrics = last_glyph.font.font.metrics();
|
||||||
let scale_factor = self.skribo_layout.size / font_metrics.units_per_em as f32;
|
let scale_factor = self.skribo_layout.size / font_metrics.units_per_em as f32;
|
||||||
let glyph_rect = last_glyph.font.font.raster_bounds(
|
let glyph_rect = last_glyph
|
||||||
|
.font
|
||||||
|
.font
|
||||||
|
.raster_bounds(
|
||||||
glyph_id,
|
glyph_id,
|
||||||
font_metrics.units_per_em as f32,
|
font_metrics.units_per_em as f32,
|
||||||
Transform2F::default(),
|
Transform2F::default(),
|
||||||
HintingOptions::None,
|
HintingOptions::None,
|
||||||
RasterizationOptions::GrayscaleAa).unwrap();
|
RasterizationOptions::GrayscaleAa,
|
||||||
self.actual_right_extent.set(Some(last_glyph.offset.x() +
|
)
|
||||||
glyph_rect.max_x() as f32 * scale_factor));
|
.unwrap();
|
||||||
|
self.actual_right_extent.set(Some(
|
||||||
|
last_glyph.offset.x() + glyph_rect.max_x() as f32 * scale_factor,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,7 +549,6 @@ impl TextMetrics {
|
||||||
self.populate_vertical_metrics_if_necessary();
|
self.populate_vertical_metrics_if_necessary();
|
||||||
self.vertical_metrics.get().unwrap().ideographic_baseline - self.text_y_offset()
|
self.vertical_metrics.get().unwrap().ideographic_baseline - self.text_y_offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerticalMetrics {
|
impl VerticalMetrics {
|
||||||
|
@ -498,28 +575,30 @@ impl VerticalMetrics {
|
||||||
let font_metrics = font.metrics();
|
let font_metrics = font.metrics();
|
||||||
let scale_factor = skribo_layout.size / font_metrics.units_per_em as f32;
|
let scale_factor = skribo_layout.size / font_metrics.units_per_em as f32;
|
||||||
vertical_metrics.em_height_ascent =
|
vertical_metrics.em_height_ascent =
|
||||||
(font_metrics.ascent *
|
(font_metrics.ascent * scale_factor).max(vertical_metrics.em_height_ascent);
|
||||||
scale_factor).max(vertical_metrics.em_height_ascent);
|
vertical_metrics.em_height_descent = (font_metrics.descent * scale_factor)
|
||||||
vertical_metrics.em_height_descent =
|
.min(vertical_metrics.em_height_descent);
|
||||||
(font_metrics.descent *
|
vertical_metrics.font_bounding_box_ascent = (font_metrics.bounding_box.max_y()
|
||||||
scale_factor).min(vertical_metrics.em_height_descent);
|
* scale_factor)
|
||||||
vertical_metrics.font_bounding_box_ascent =
|
.max(vertical_metrics.font_bounding_box_ascent);
|
||||||
(font_metrics.bounding_box.max_y() *
|
|
||||||
scale_factor).max(vertical_metrics.font_bounding_box_ascent);
|
|
||||||
vertical_metrics.font_bounding_box_descent =
|
vertical_metrics.font_bounding_box_descent =
|
||||||
(font_metrics.bounding_box.min_y() *
|
(font_metrics.bounding_box.min_y() * scale_factor)
|
||||||
scale_factor).min(vertical_metrics.font_bounding_box_descent);
|
.min(vertical_metrics.font_bounding_box_descent);
|
||||||
|
|
||||||
last_font = Some(font);
|
last_font = Some(font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let font = last_font.as_ref().unwrap();
|
let font = last_font.as_ref().unwrap();
|
||||||
let glyph_rect = font.raster_bounds(glyph.glyph_id,
|
let glyph_rect = font
|
||||||
|
.raster_bounds(
|
||||||
|
glyph.glyph_id,
|
||||||
skribo_layout.size,
|
skribo_layout.size,
|
||||||
Transform2F::default(),
|
Transform2F::default(),
|
||||||
HintingOptions::None,
|
HintingOptions::None,
|
||||||
RasterizationOptions::GrayscaleAa).unwrap();
|
RasterizationOptions::GrayscaleAa,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
vertical_metrics.actual_bounding_box_ascent =
|
vertical_metrics.actual_bounding_box_ascent =
|
||||||
(glyph_rect.max_y() as f32).max(vertical_metrics.actual_bounding_box_ascent);
|
(glyph_rect.max_y() as f32).max(vertical_metrics.actual_bounding_box_ascent);
|
||||||
vertical_metrics.actual_bounding_box_descent =
|
vertical_metrics.actual_bounding_box_descent =
|
||||||
|
@ -533,7 +612,10 @@ impl VerticalMetrics {
|
||||||
/// Various things that can be conveniently converted into font collections for use with
|
/// Various things that can be conveniently converted into font collections for use with
|
||||||
/// `CanvasRenderingContext2D::set_font()`.
|
/// `CanvasRenderingContext2D::set_font()`.
|
||||||
pub trait IntoFontCollection {
|
pub trait IntoFontCollection {
|
||||||
fn into_font_collection(self, font_context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError>;
|
fn into_font_collection(
|
||||||
|
self,
|
||||||
|
font_context: &CanvasFontContext,
|
||||||
|
) -> Result<Arc<FontCollection>, FontError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoFontCollection for Arc<FontCollection> {
|
impl IntoFontCollection for Arc<FontCollection> {
|
||||||
|
@ -565,14 +647,20 @@ impl IntoFontCollection for Vec<FontFamily> {
|
||||||
|
|
||||||
impl IntoFontCollection for Font {
|
impl IntoFontCollection for Font {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
fn into_font_collection(
|
||||||
|
self,
|
||||||
|
context: &CanvasFontContext,
|
||||||
|
) -> Result<Arc<FontCollection>, FontError> {
|
||||||
Ok(FontFamily::new_from_font(self).into_font_collection(context)?)
|
Ok(FontFamily::new_from_font(self).into_font_collection(context)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoFontCollection for &'a [Font] {
|
impl<'a> IntoFontCollection for &'a [Font] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
fn into_font_collection(
|
||||||
|
self,
|
||||||
|
context: &CanvasFontContext,
|
||||||
|
) -> Result<Arc<FontCollection>, FontError> {
|
||||||
let mut family = FontFamily::new();
|
let mut family = FontFamily::new();
|
||||||
for font in self {
|
for font in self {
|
||||||
family.add_font(FontRef::new((*font).clone()))
|
family.add_font(FontRef::new((*font).clone()))
|
||||||
|
@ -583,14 +671,22 @@ impl<'a> IntoFontCollection for &'a [Font] {
|
||||||
|
|
||||||
impl<'a> IntoFontCollection for &'a str {
|
impl<'a> IntoFontCollection for &'a str {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
fn into_font_collection(
|
||||||
context.get_font_by_postscript_name(self)?.into_font_collection(context)
|
self,
|
||||||
|
context: &CanvasFontContext,
|
||||||
|
) -> Result<Arc<FontCollection>, FontError> {
|
||||||
|
context
|
||||||
|
.get_font_by_postscript_name(self)?
|
||||||
|
.into_font_collection(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> IntoFontCollection for &'a [&'b str] {
|
impl<'a, 'b> IntoFontCollection for &'a [&'b str] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
fn into_font_collection(
|
||||||
|
self,
|
||||||
|
context: &CanvasFontContext,
|
||||||
|
) -> Result<Arc<FontCollection>, FontError> {
|
||||||
let mut font_collection = FontCollection::new();
|
let mut font_collection = FontCollection::new();
|
||||||
for postscript_name in self {
|
for postscript_name in self {
|
||||||
let font = context.get_font_by_postscript_name(postscript_name)?;
|
let font = context.get_font_by_postscript_name(postscript_name)?;
|
||||||
|
|
|
@ -162,7 +162,12 @@ impl ColorF {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_u8(&self) -> ColorU {
|
pub fn to_u8(&self) -> ColorU {
|
||||||
let color = (self.0 * F32x4::splat(255.0)).to_i32x4();
|
let color = (self.0 * F32x4::splat(255.0)).to_i32x4();
|
||||||
ColorU { r: color[0] as u8, g: color[1] as u8, b: color[2] as u8, a: color[3] as u8 }
|
ColorU {
|
||||||
|
r: color[0] as u8,
|
||||||
|
g: color[1] as u8,
|
||||||
|
b: color[2] as u8,
|
||||||
|
a: color[3] as u8,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -226,9 +231,7 @@ impl Debug for ColorF {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn color_slice_to_u8_slice(slice: &[ColorU]) -> &[u8] {
|
pub fn color_slice_to_u8_slice(slice: &[ColorU]) -> &[u8] {
|
||||||
unsafe {
|
unsafe { slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len() * 4) }
|
||||||
slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len() * 4)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::{Add, Mul, Deref};
|
use std::ops::{Add, Deref, Mul};
|
||||||
|
|
||||||
/// ColorMatrix filter/transformation
|
/// ColorMatrix filter/transformation
|
||||||
///
|
///
|
||||||
|
|
|
@ -18,7 +18,7 @@ use arrayvec::ArrayVec;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::util::lerp;
|
use pathfinder_geometry::util::lerp;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector4F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F, Vector4F};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -491,8 +491,10 @@ pub(crate) fn rect_is_inside_polygon(rect: RectF, polygon_points: &[Vector2F]) -
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clips a line segment to an axis-aligned rectangle using Cohen-Sutherland clipping.
|
/// Clips a line segment to an axis-aligned rectangle using Cohen-Sutherland clipping.
|
||||||
pub fn clip_line_segment_to_rect(mut line_segment: LineSegment2F, rect: RectF)
|
pub fn clip_line_segment_to_rect(
|
||||||
-> Option<LineSegment2F> {
|
mut line_segment: LineSegment2F,
|
||||||
|
rect: RectF,
|
||||||
|
) -> Option<LineSegment2F> {
|
||||||
let mut outcode_from = compute_outcode(line_segment.from(), rect);
|
let mut outcode_from = compute_outcode(line_segment.from(), rect);
|
||||||
let mut outcode_to = compute_outcode(line_segment.to(), rect);
|
let mut outcode_to = compute_outcode(line_segment.to(), rect);
|
||||||
|
|
||||||
|
@ -512,29 +514,45 @@ pub fn clip_line_segment_to_rect(mut line_segment: LineSegment2F, rect: RectF)
|
||||||
};
|
};
|
||||||
|
|
||||||
if outcode.contains(Outcode::LEFT) {
|
if outcode.contains(Outcode::LEFT) {
|
||||||
point = vec2f(rect.min_x(),
|
point = vec2f(
|
||||||
lerp(line_segment.from_y(),
|
rect.min_x(),
|
||||||
|
lerp(
|
||||||
|
line_segment.from_y(),
|
||||||
line_segment.to_y(),
|
line_segment.to_y(),
|
||||||
(rect.min_x() - line_segment.from_x()) /
|
(rect.min_x() - line_segment.from_x())
|
||||||
(line_segment.to_x() - line_segment.from_x())));
|
/ (line_segment.to_x() - line_segment.from_x()),
|
||||||
|
),
|
||||||
|
);
|
||||||
} else if outcode.contains(Outcode::RIGHT) {
|
} else if outcode.contains(Outcode::RIGHT) {
|
||||||
point = vec2f(rect.max_x(),
|
point = vec2f(
|
||||||
lerp(line_segment.from_y(),
|
rect.max_x(),
|
||||||
|
lerp(
|
||||||
|
line_segment.from_y(),
|
||||||
line_segment.to_y(),
|
line_segment.to_y(),
|
||||||
(rect.max_x() - line_segment.from_x()) /
|
(rect.max_x() - line_segment.from_x())
|
||||||
(line_segment.to_x() - line_segment.from_x())));
|
/ (line_segment.to_x() - line_segment.from_x()),
|
||||||
|
),
|
||||||
|
);
|
||||||
} else if outcode.contains(Outcode::TOP) {
|
} else if outcode.contains(Outcode::TOP) {
|
||||||
point = vec2f(lerp(line_segment.from_x(),
|
point = vec2f(
|
||||||
|
lerp(
|
||||||
|
line_segment.from_x(),
|
||||||
line_segment.to_x(),
|
line_segment.to_x(),
|
||||||
(rect.min_y() - line_segment.from_y()) /
|
(rect.min_y() - line_segment.from_y())
|
||||||
(line_segment.to_y() - line_segment.from_y())),
|
/ (line_segment.to_y() - line_segment.from_y()),
|
||||||
rect.min_y());
|
),
|
||||||
|
rect.min_y(),
|
||||||
|
);
|
||||||
} else if outcode.contains(Outcode::BOTTOM) {
|
} else if outcode.contains(Outcode::BOTTOM) {
|
||||||
point = vec2f(lerp(line_segment.from_x(),
|
point = vec2f(
|
||||||
|
lerp(
|
||||||
|
line_segment.from_x(),
|
||||||
line_segment.to_x(),
|
line_segment.to_x(),
|
||||||
(rect.max_y() - line_segment.from_y()) /
|
(rect.max_y() - line_segment.from_y())
|
||||||
(line_segment.to_y() - line_segment.from_y())),
|
/ (line_segment.to_y() - line_segment.from_y()),
|
||||||
rect.max_y());
|
),
|
||||||
|
rect.max_y(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if clip_from {
|
if clip_from {
|
||||||
|
|
|
@ -38,7 +38,11 @@ impl<'a> OutlineDash<'a> {
|
||||||
/// <https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset>.
|
/// <https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset>.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(input: &'a Outline, dashes: &'a [f32], offset: f32) -> OutlineDash<'a> {
|
pub fn new(input: &'a Outline, dashes: &'a [f32], offset: f32) -> OutlineDash<'a> {
|
||||||
OutlineDash { input, output: Outline::new(), state: DashState::new(dashes, offset) }
|
OutlineDash {
|
||||||
|
input,
|
||||||
|
output: Outline::new(),
|
||||||
|
state: DashState::new(dashes, offset),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs the dashing operation.
|
/// Performs the dashing operation.
|
||||||
|
@ -66,9 +70,16 @@ struct ContourDash<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c> ContourDash<'a, 'b, 'c> {
|
impl<'a, 'b, 'c> ContourDash<'a, 'b, 'c> {
|
||||||
fn new(input: &'a Contour, output: &'b mut Outline, state: &'c mut DashState<'a>)
|
fn new(
|
||||||
-> ContourDash<'a, 'b, 'c> {
|
input: &'a Contour,
|
||||||
ContourDash { input, output, state }
|
output: &'b mut Outline,
|
||||||
|
state: &'c mut DashState<'a>,
|
||||||
|
) -> ContourDash<'a, 'b, 'c> {
|
||||||
|
ContourDash {
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
state,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dash(&mut self) {
|
fn dash(&mut self) {
|
||||||
|
@ -95,13 +106,16 @@ impl<'a, 'b, 'c> ContourDash<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.state.is_on() {
|
if self.state.is_on() {
|
||||||
self.state.output.push_segment(¤t_segment, PushSegmentFlags::empty());
|
self.state
|
||||||
|
.output
|
||||||
|
.push_segment(¤t_segment, PushSegmentFlags::empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state.distance_left -= distance;
|
self.state.distance_left -= distance;
|
||||||
if self.state.distance_left < EPSILON {
|
if self.state.distance_left < EPSILON {
|
||||||
if self.state.is_on() {
|
if self.state.is_on() {
|
||||||
self.output.push_contour(mem::replace(&mut self.state.output, Contour::new()));
|
self.output
|
||||||
|
.push_contour(mem::replace(&mut self.state.output, Contour::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state.current_dash_index += 1;
|
self.state.current_dash_index += 1;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use crate::orientation::Orientation;
|
use crate::orientation::Orientation;
|
||||||
use crate::outline::Contour;
|
use crate::outline::Contour;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
|
|
||||||
pub struct ContourDilator<'a> {
|
pub struct ContourDilator<'a> {
|
||||||
contour: &'a mut Contour,
|
contour: &'a mut Contour,
|
||||||
|
@ -33,7 +33,8 @@ impl<'a> ContourDilator<'a> {
|
||||||
|
|
||||||
pub fn dilate(&mut self) {
|
pub fn dilate(&mut self) {
|
||||||
// Determine orientation.
|
// Determine orientation.
|
||||||
let scale = self.amount * (match self.orientation {
|
let scale = self.amount
|
||||||
|
* (match self.orientation {
|
||||||
Orientation::Ccw => vec2f(1.0, -1.0),
|
Orientation::Ccw => vec2f(1.0, -1.0),
|
||||||
Orientation::Cw => vec2f(-1.0, 1.0),
|
Orientation::Cw => vec2f(-1.0, 1.0),
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
//! Special effects that can be applied to layers.
|
//! Special effects that can be applied to layers.
|
||||||
|
|
||||||
use pathfinder_color::{ColorF, matrix::ColorMatrix};
|
use pathfinder_color::{matrix::ColorMatrix, ColorF};
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_simd::default::F32x2;
|
use pathfinder_simd::default::F32x2;
|
||||||
|
@ -202,64 +202,64 @@ impl BlendMode {
|
||||||
pub fn occludes_backdrop(self) -> bool {
|
pub fn occludes_backdrop(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
BlendMode::SrcOver | BlendMode::Clear => true,
|
BlendMode::SrcOver | BlendMode::Clear => true,
|
||||||
BlendMode::DestOver |
|
BlendMode::DestOver
|
||||||
BlendMode::DestOut |
|
| BlendMode::DestOut
|
||||||
BlendMode::SrcAtop |
|
| BlendMode::SrcAtop
|
||||||
BlendMode::Xor |
|
| BlendMode::Xor
|
||||||
BlendMode::Lighter |
|
| BlendMode::Lighter
|
||||||
BlendMode::Lighten |
|
| BlendMode::Lighten
|
||||||
BlendMode::Darken |
|
| BlendMode::Darken
|
||||||
BlendMode::Copy |
|
| BlendMode::Copy
|
||||||
BlendMode::SrcIn |
|
| BlendMode::SrcIn
|
||||||
BlendMode::DestIn |
|
| BlendMode::DestIn
|
||||||
BlendMode::SrcOut |
|
| BlendMode::SrcOut
|
||||||
BlendMode::DestAtop |
|
| BlendMode::DestAtop
|
||||||
BlendMode::Multiply |
|
| BlendMode::Multiply
|
||||||
BlendMode::Screen |
|
| BlendMode::Screen
|
||||||
BlendMode::HardLight |
|
| BlendMode::HardLight
|
||||||
BlendMode::Overlay |
|
| BlendMode::Overlay
|
||||||
BlendMode::ColorDodge |
|
| BlendMode::ColorDodge
|
||||||
BlendMode::ColorBurn |
|
| BlendMode::ColorBurn
|
||||||
BlendMode::SoftLight |
|
| BlendMode::SoftLight
|
||||||
BlendMode::Difference |
|
| BlendMode::Difference
|
||||||
BlendMode::Exclusion |
|
| BlendMode::Exclusion
|
||||||
BlendMode::Hue |
|
| BlendMode::Hue
|
||||||
BlendMode::Saturation |
|
| BlendMode::Saturation
|
||||||
BlendMode::Color |
|
| BlendMode::Color
|
||||||
BlendMode::Luminosity => false,
|
| BlendMode::Luminosity => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if this blend mode does not preserve destination areas outside the source.
|
/// True if this blend mode does not preserve destination areas outside the source.
|
||||||
pub fn is_destructive(self) -> bool {
|
pub fn is_destructive(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
BlendMode::Clear |
|
BlendMode::Clear
|
||||||
BlendMode::Copy |
|
| BlendMode::Copy
|
||||||
BlendMode::SrcIn |
|
| BlendMode::SrcIn
|
||||||
BlendMode::DestIn |
|
| BlendMode::DestIn
|
||||||
BlendMode::SrcOut |
|
| BlendMode::SrcOut
|
||||||
BlendMode::DestAtop => true,
|
| BlendMode::DestAtop => true,
|
||||||
BlendMode::SrcOver |
|
BlendMode::SrcOver
|
||||||
BlendMode::DestOver |
|
| BlendMode::DestOver
|
||||||
BlendMode::DestOut |
|
| BlendMode::DestOut
|
||||||
BlendMode::SrcAtop |
|
| BlendMode::SrcAtop
|
||||||
BlendMode::Xor |
|
| BlendMode::Xor
|
||||||
BlendMode::Lighter |
|
| BlendMode::Lighter
|
||||||
BlendMode::Lighten |
|
| BlendMode::Lighten
|
||||||
BlendMode::Darken |
|
| BlendMode::Darken
|
||||||
BlendMode::Multiply |
|
| BlendMode::Multiply
|
||||||
BlendMode::Screen |
|
| BlendMode::Screen
|
||||||
BlendMode::HardLight |
|
| BlendMode::HardLight
|
||||||
BlendMode::Overlay |
|
| BlendMode::Overlay
|
||||||
BlendMode::ColorDodge |
|
| BlendMode::ColorDodge
|
||||||
BlendMode::ColorBurn |
|
| BlendMode::ColorBurn
|
||||||
BlendMode::SoftLight |
|
| BlendMode::SoftLight
|
||||||
BlendMode::Difference |
|
| BlendMode::Difference
|
||||||
BlendMode::Exclusion |
|
| BlendMode::Exclusion
|
||||||
BlendMode::Hue |
|
| BlendMode::Hue
|
||||||
BlendMode::Saturation |
|
| BlendMode::Saturation
|
||||||
BlendMode::Color |
|
| BlendMode::Color
|
||||||
BlendMode::Luminosity => false,
|
| BlendMode::Luminosity => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ use crate::util;
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
|
||||||
use pathfinder_geometry::util as geometry_util;
|
use pathfinder_geometry::util as geometry_util;
|
||||||
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_simd::default::F32x2;
|
use pathfinder_simd::default::F32x2;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert;
|
use std::convert;
|
||||||
|
@ -67,7 +67,7 @@ pub enum GradientGeometry {
|
||||||
/// Like `gradientTransform` in SVG. Note that this is the inverse of Cairo's gradient
|
/// Like `gradientTransform` in SVG. Note that this is the inverse of Cairo's gradient
|
||||||
/// transform.
|
/// transform.
|
||||||
transform: Transform2F,
|
transform: Transform2F,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// What should be rendered outside the color stops.
|
/// What should be rendered outside the color stops.
|
||||||
|
@ -83,13 +83,20 @@ pub enum GradientWrap {
|
||||||
impl Eq for Gradient {}
|
impl Eq for Gradient {}
|
||||||
|
|
||||||
impl Hash for Gradient {
|
impl Hash for Gradient {
|
||||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
fn hash<H>(&self, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
match self.geometry {
|
match self.geometry {
|
||||||
GradientGeometry::Linear(line) => {
|
GradientGeometry::Linear(line) => {
|
||||||
(0).hash(state);
|
(0).hash(state);
|
||||||
util::hash_line_segment(line, state);
|
util::hash_line_segment(line, state);
|
||||||
}
|
}
|
||||||
GradientGeometry::Radial { line, radii, transform } => {
|
GradientGeometry::Radial {
|
||||||
|
line,
|
||||||
|
radii,
|
||||||
|
transform,
|
||||||
|
} => {
|
||||||
(1).hash(state);
|
(1).hash(state);
|
||||||
util::hash_line_segment(line, state);
|
util::hash_line_segment(line, state);
|
||||||
util::hash_f32(radii.x(), state);
|
util::hash_f32(radii.x(), state);
|
||||||
|
@ -109,7 +116,10 @@ impl Hash for Gradient {
|
||||||
impl Eq for ColorStop {}
|
impl Eq for ColorStop {}
|
||||||
|
|
||||||
impl Hash for ColorStop {
|
impl Hash for ColorStop {
|
||||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
fn hash<H>(&self, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
self.color.hash(state);
|
self.color.hash(state);
|
||||||
let offset = mem::transmute::<f32, u32>(self.offset);
|
let offset = mem::transmute::<f32, u32>(self.offset);
|
||||||
|
@ -145,10 +155,17 @@ impl Gradient {
|
||||||
/// with two circles, pass a `LineSegment2F`. To start the gradient at the center of the
|
/// with two circles, pass a `LineSegment2F`. To start the gradient at the center of the
|
||||||
/// circle, pass zero for the first radius.
|
/// circle, pass zero for the first radius.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn radial<L>(line: L, radii: F32x2) -> Gradient where L: RadialGradientLine {
|
pub fn radial<L>(line: L, radii: F32x2) -> Gradient
|
||||||
|
where
|
||||||
|
L: RadialGradientLine,
|
||||||
|
{
|
||||||
let transform = Transform2F::default();
|
let transform = Transform2F::default();
|
||||||
Gradient {
|
Gradient {
|
||||||
geometry: GradientGeometry::Radial { line: line.to_line(), radii, transform },
|
geometry: GradientGeometry::Radial {
|
||||||
|
line: line.to_line(),
|
||||||
|
radii,
|
||||||
|
transform,
|
||||||
|
},
|
||||||
stops: Vec::new(),
|
stops: Vec::new(),
|
||||||
wrap: GradientWrap::Clamp,
|
wrap: GradientWrap::Clamp,
|
||||||
}
|
}
|
||||||
|
@ -157,9 +174,16 @@ impl Gradient {
|
||||||
/// Adds a new color stop to the radial gradient.
|
/// Adds a new color stop to the radial gradient.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add(&mut self, stop: ColorStop) {
|
pub fn add(&mut self, stop: ColorStop) {
|
||||||
let index = self.stops.binary_search_by(|other| {
|
let index = self
|
||||||
if other.offset <= stop.offset { Ordering::Less } else { Ordering::Greater }
|
.stops
|
||||||
}).unwrap_or_else(convert::identity);
|
.binary_search_by(|other| {
|
||||||
|
if other.offset <= stop.offset {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(convert::identity);
|
||||||
self.stops.insert(index, stop);
|
self.stops.insert(index, stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +217,22 @@ impl Gradient {
|
||||||
t = geometry_util::clamp(t, 0.0, 1.0);
|
t = geometry_util::clamp(t, 0.0, 1.0);
|
||||||
let last_index = self.stops.len() - 1;
|
let last_index = self.stops.len() - 1;
|
||||||
|
|
||||||
let upper_index = self.stops.binary_search_by(|stop| {
|
let upper_index = self
|
||||||
if stop.offset < t || stop.offset == 0.0 { Ordering::Less } else { Ordering::Greater }
|
.stops
|
||||||
}).unwrap_or_else(convert::identity).min(last_index);
|
.binary_search_by(|stop| {
|
||||||
let lower_index = if upper_index > 0 { upper_index - 1 } else { upper_index };
|
if stop.offset < t || stop.offset == 0.0 {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(convert::identity)
|
||||||
|
.min(last_index);
|
||||||
|
let lower_index = if upper_index > 0 {
|
||||||
|
upper_index - 1
|
||||||
|
} else {
|
||||||
|
upper_index
|
||||||
|
};
|
||||||
|
|
||||||
let lower_stop = &self.stops[lower_index];
|
let lower_stop = &self.stops[lower_index];
|
||||||
let upper_stop = &self.stops[upper_index];
|
let upper_stop = &self.stops[upper_index];
|
||||||
|
@ -207,7 +243,11 @@ impl Gradient {
|
||||||
}
|
}
|
||||||
|
|
||||||
let ratio = ((t - lower_stop.offset) / denom).min(1.0);
|
let ratio = ((t - lower_stop.offset) / denom).min(1.0);
|
||||||
lower_stop.color.to_f32().lerp(upper_stop.color.to_f32(), ratio).to_u8()
|
lower_stop
|
||||||
|
.color
|
||||||
|
.to_f32()
|
||||||
|
.lerp(upper_stop.color.to_f32(), ratio)
|
||||||
|
.to_u8()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if all colors of all stops in this gradient are opaque (alpha is 1.0).
|
/// Returns true if all colors of all stops in this gradient are opaque (alpha is 1.0).
|
||||||
|
@ -220,7 +260,9 @@ impl Gradient {
|
||||||
/// 0.0).
|
/// 0.0).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_fully_transparent(&self) -> bool {
|
pub fn is_fully_transparent(&self) -> bool {
|
||||||
self.stops.iter().all(|stop| stop.color.is_fully_transparent())
|
self.stops
|
||||||
|
.iter()
|
||||||
|
.all(|stop| stop.color.is_fully_transparent())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the given affine transform to this gradient.
|
/// Applies the given affine transform to this gradient.
|
||||||
|
@ -234,9 +276,9 @@ impl Gradient {
|
||||||
|
|
||||||
match self.geometry {
|
match self.geometry {
|
||||||
GradientGeometry::Linear(ref mut line) => *line = new_transform * *line,
|
GradientGeometry::Linear(ref mut line) => *line = new_transform * *line,
|
||||||
GradientGeometry::Radial { ref mut transform, .. } => {
|
GradientGeometry::Radial {
|
||||||
*transform = new_transform * *transform
|
ref mut transform, ..
|
||||||
}
|
} => *transform = new_transform * *transform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,9 +325,10 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that it sorted stably
|
// Check that it sorted stably
|
||||||
assert!(grad.stops.windows(2).all(|w| {
|
assert!(grad
|
||||||
w[0].offset < w[1].offset || w[0].color.r < w[1].color.r
|
.stops
|
||||||
}));
|
.windows(2)
|
||||||
|
.all(|w| { w[0].offset < w[1].offset || w[0].color.r < w[1].color.r }));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -293,7 +336,10 @@ mod test {
|
||||||
let mut grad = Gradient::linear_from_points(Vector2F::default(), Vector2F::default());
|
let mut grad = Gradient::linear_from_points(Vector2F::default(), Vector2F::default());
|
||||||
for i in 0..110 {
|
for i in 0..110 {
|
||||||
let zero_width = (i == 0) || (11 <= i && i < 99) || (i == 109);
|
let zero_width = (i == 0) || (11 <= i && i < 99) || (i == 109);
|
||||||
grad.add_color_stop(ColorU::new(if zero_width { 255 } else { 0 }, 0, 0, 1), (i % 11) as f32 / 10.0);
|
grad.add_color_stop(
|
||||||
|
ColorU::new(if zero_width { 255 } else { 0 }, 0, 0, 1),
|
||||||
|
(i % 11) as f32 / 10.0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..11 {
|
for i in 0..11 {
|
||||||
|
|
|
@ -17,10 +17,10 @@ use crate::segment::{Segment, SegmentFlags, SegmentKind};
|
||||||
use crate::util::safe_sqrt;
|
use crate::util::safe_sqrt;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::{Transform2F, Matrix2x2F};
|
use pathfinder_geometry::transform2d::{Matrix2x2F, Transform2F};
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::unit_vector::UnitVector;
|
use pathfinder_geometry::unit_vector::UnitVector;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -90,7 +90,10 @@ impl Outline {
|
||||||
|
|
||||||
/// Creates a new outline from a list of segments.
|
/// Creates a new outline from a list of segments.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_segments<I>(segments: I) -> Outline where I: Iterator<Item = Segment> {
|
pub fn from_segments<I>(segments: I) -> Outline
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Segment>,
|
||||||
|
{
|
||||||
let mut outline = Outline::new();
|
let mut outline = Outline::new();
|
||||||
let mut current_contour = Contour::new();
|
let mut current_contour = Contour::new();
|
||||||
|
|
||||||
|
@ -380,7 +383,7 @@ impl Contour {
|
||||||
contour.push_cubic(
|
contour.push_cubic(
|
||||||
vec2f(p0.x(), p1.y()),
|
vec2f(p0.x(), p1.y()),
|
||||||
vec2f(p1.x(), p0.y()),
|
vec2f(p1.x(), p0.y()),
|
||||||
vec2f(p2.x(), p0.y())
|
vec2f(p2.x(), p0.y()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +396,7 @@ impl Contour {
|
||||||
contour.push_cubic(
|
contour.push_cubic(
|
||||||
vec2f(p1.x(), p0.y()),
|
vec2f(p1.x(), p0.y()),
|
||||||
vec2f(p0.x(), p1.y()),
|
vec2f(p0.x(), p1.y()),
|
||||||
vec2f(p0.x(), p2.y())
|
vec2f(p0.x(), p2.y()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +409,7 @@ impl Contour {
|
||||||
contour.push_cubic(
|
contour.push_cubic(
|
||||||
vec2f(p0.x(), p1.y()),
|
vec2f(p0.x(), p1.y()),
|
||||||
vec2f(p1.x(), p0.y()),
|
vec2f(p1.x(), p0.y()),
|
||||||
vec2f(p2.x(), p0.y())
|
vec2f(p2.x(), p0.y()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +422,7 @@ impl Contour {
|
||||||
contour.push_cubic(
|
contour.push_cubic(
|
||||||
vec2f(p1.x(), p0.y()),
|
vec2f(p1.x(), p0.y()),
|
||||||
vec2f(p0.x(), p1.y()),
|
vec2f(p0.x(), p1.y()),
|
||||||
vec2f(p0.x(), p2.y())
|
vec2f(p0.x(), p2.y()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,10 +560,7 @@ impl Contour {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn push_point(&mut self,
|
pub(crate) fn push_point(&mut self, point: Vector2F, flags: PointFlags, update_bounds: bool) {
|
||||||
point: Vector2F,
|
|
||||||
flags: PointFlags,
|
|
||||||
update_bounds: bool) {
|
|
||||||
debug_assert!(!point.x().is_nan() && !point.y().is_nan());
|
debug_assert!(!point.x().is_nan() && !point.y().is_nan());
|
||||||
|
|
||||||
if update_bounds {
|
if update_bounds {
|
||||||
|
@ -612,11 +612,13 @@ impl Contour {
|
||||||
///
|
///
|
||||||
/// * `direction`: Whether the arc should be drawn clockwise or counterclockwise from the +x
|
/// * `direction`: Whether the arc should be drawn clockwise or counterclockwise from the +x
|
||||||
/// axis.
|
/// axis.
|
||||||
pub fn push_arc(&mut self,
|
pub fn push_arc(
|
||||||
|
&mut self,
|
||||||
transform: &Transform2F,
|
transform: &Transform2F,
|
||||||
start_angle: f32,
|
start_angle: f32,
|
||||||
end_angle: f32,
|
end_angle: f32,
|
||||||
direction: ArcDirection) {
|
direction: ArcDirection,
|
||||||
|
) {
|
||||||
if end_angle - start_angle >= PI * 2.0 {
|
if end_angle - start_angle >= PI * 2.0 {
|
||||||
self.push_ellipse(transform);
|
self.push_ellipse(transform);
|
||||||
} else {
|
} else {
|
||||||
|
@ -628,10 +630,12 @@ impl Contour {
|
||||||
|
|
||||||
/// Given the endpoints of a unit arc, adds Bézier curves to approximate that arc to the
|
/// Given the endpoints of a unit arc, adds Bézier curves to approximate that arc to the
|
||||||
/// current contour. The given transform is applied to the resulting arc.
|
/// current contour. The given transform is applied to the resulting arc.
|
||||||
pub fn push_arc_from_unit_chord(&mut self,
|
pub fn push_arc_from_unit_chord(
|
||||||
|
&mut self,
|
||||||
transform: &Transform2F,
|
transform: &Transform2F,
|
||||||
mut chord: LineSegment2F,
|
mut chord: LineSegment2F,
|
||||||
direction: ArcDirection) {
|
direction: ArcDirection,
|
||||||
|
) {
|
||||||
let mut direction_transform = Transform2F::default();
|
let mut direction_transform = Transform2F::default();
|
||||||
if direction == ArcDirection::CCW {
|
if direction == ArcDirection::CCW {
|
||||||
chord *= vec2f(1.0, -1.0);
|
chord *= vec2f(1.0, -1.0);
|
||||||
|
@ -640,15 +644,17 @@ impl Contour {
|
||||||
|
|
||||||
let (mut vector, end_vector) = (UnitVector(chord.from()), UnitVector(chord.to()));
|
let (mut vector, end_vector) = (UnitVector(chord.from()), UnitVector(chord.to()));
|
||||||
for segment_index in 0..4 {
|
for segment_index in 0..4 {
|
||||||
debug!("push_arc_from_unit_chord(): loop segment index {}", segment_index);
|
debug!(
|
||||||
|
"push_arc_from_unit_chord(): loop segment index {}",
|
||||||
|
segment_index
|
||||||
|
);
|
||||||
|
|
||||||
let mut sweep_vector = end_vector.rev_rotate_by(vector);
|
let mut sweep_vector = end_vector.rev_rotate_by(vector);
|
||||||
let last = sweep_vector.0.x() >= -EPSILON && sweep_vector.0.y() >= -EPSILON;
|
let last = sweep_vector.0.x() >= -EPSILON && sweep_vector.0.y() >= -EPSILON;
|
||||||
debug!("... end_vector={:?} vector={:?} sweep_vector={:?} last={:?}",
|
debug!(
|
||||||
end_vector,
|
"... end_vector={:?} vector={:?} sweep_vector={:?} last={:?}",
|
||||||
vector,
|
end_vector, vector, sweep_vector, last
|
||||||
sweep_vector,
|
);
|
||||||
last);
|
|
||||||
|
|
||||||
let mut segment;
|
let mut segment;
|
||||||
if !last {
|
if !last {
|
||||||
|
@ -683,12 +689,14 @@ impl Contour {
|
||||||
/// Draws an ellipse section with radii given by `radius` rotated by `x_axis_rotation` in
|
/// Draws an ellipse section with radii given by `radius` rotated by `x_axis_rotation` in
|
||||||
/// radians to `to` in the given direction. If `large_arc` is true, draws an arc bigger than
|
/// radians to `to` in the given direction. If `large_arc` is true, draws an arc bigger than
|
||||||
/// π radians, otherwise smaller than π radians.
|
/// π radians, otherwise smaller than π radians.
|
||||||
pub fn push_svg_arc(&mut self,
|
pub fn push_svg_arc(
|
||||||
|
&mut self,
|
||||||
radius: Vector2F,
|
radius: Vector2F,
|
||||||
x_axis_rotation: f32,
|
x_axis_rotation: f32,
|
||||||
large_arc: bool,
|
large_arc: bool,
|
||||||
direction: ArcDirection,
|
direction: ArcDirection,
|
||||||
to: Vector2F) {
|
to: Vector2F,
|
||||||
|
) {
|
||||||
let r = radius;
|
let r = radius;
|
||||||
let p = to;
|
let p = to;
|
||||||
let last = self.last_position().unwrap_or_default();
|
let last = self.last_position().unwrap_or_default();
|
||||||
|
@ -698,7 +706,7 @@ impl Contour {
|
||||||
let r_inv = r.recip();
|
let r_inv = r.recip();
|
||||||
let sign = match (large_arc, direction) {
|
let sign = match (large_arc, direction) {
|
||||||
(false, ArcDirection::CW) | (true, ArcDirection::CCW) => 1.0,
|
(false, ArcDirection::CW) | (true, ArcDirection::CCW) => 1.0,
|
||||||
(false, ArcDirection::CCW) | (true, ArcDirection::CW) => -1.0
|
(false, ArcDirection::CCW) | (true, ArcDirection::CW) => -1.0,
|
||||||
};
|
};
|
||||||
let rot = Matrix2x2F::from_rotation(x_axis_rotation);
|
let rot = Matrix2x2F::from_rotation(x_axis_rotation);
|
||||||
// x'
|
// x'
|
||||||
|
@ -717,7 +725,11 @@ impl Contour {
|
||||||
let rq2 = r2 * q2.yx(); // (r_x^2 q_y^2, r_y^2 q_x^2)
|
let rq2 = r2 * q2.yx(); // (r_x^2 q_y^2, r_y^2 q_x^2)
|
||||||
let rq2_sum = rq2.x() + rq2.y(); // r_x^2 q_y^2 + r_y^2 q_x^2
|
let rq2_sum = rq2.x() + rq2.y(); // r_x^2 q_y^2 + r_y^2 q_x^2
|
||||||
// c'
|
// c'
|
||||||
let s = vec2f(1., -1.) * r * (q * r_inv).yx() * safe_sqrt((r2_prod - rq2_sum) / rq2_sum) * sign;
|
let s = vec2f(1., -1.)
|
||||||
|
* r
|
||||||
|
* (q * r_inv).yx()
|
||||||
|
* safe_sqrt((r2_prod - rq2_sum) / rq2_sum)
|
||||||
|
* sign;
|
||||||
let c = rot * s + (last + p) * 0.5;
|
let c = rot * s + (last + p) * 0.5;
|
||||||
|
|
||||||
let a = (q - s) * r_inv;
|
let a = (q - s) * r_inv;
|
||||||
|
@ -732,7 +744,7 @@ impl Contour {
|
||||||
|
|
||||||
let transform = Transform2F {
|
let transform = Transform2F {
|
||||||
matrix: rot,
|
matrix: rot,
|
||||||
vector: c
|
vector: c,
|
||||||
} * Transform2F::from_scale(r);
|
} * Transform2F::from_scale(r);
|
||||||
let chord = LineSegment2F::new(a, b);
|
let chord = LineSegment2F::new(a, b);
|
||||||
self.push_arc_from_unit_chord(&transform, chord, direction);
|
self.push_arc_from_unit_chord(&transform, chord, direction);
|
||||||
|
@ -747,17 +759,25 @@ impl Contour {
|
||||||
pub fn push_ellipse(&mut self, transform: &Transform2F) {
|
pub fn push_ellipse(&mut self, transform: &Transform2F) {
|
||||||
let segment = Segment::quarter_circle_arc();
|
let segment = Segment::quarter_circle_arc();
|
||||||
let mut rotation;
|
let mut rotation;
|
||||||
self.push_segment(&segment.transform(transform),
|
self.push_segment(
|
||||||
PushSegmentFlags::UPDATE_BOUNDS | PushSegmentFlags::INCLUDE_FROM_POINT);
|
&segment.transform(transform),
|
||||||
|
PushSegmentFlags::UPDATE_BOUNDS | PushSegmentFlags::INCLUDE_FROM_POINT,
|
||||||
|
);
|
||||||
rotation = Transform2F::from_rotation_vector(UnitVector(vec2f(0.0, 1.0)));
|
rotation = Transform2F::from_rotation_vector(UnitVector(vec2f(0.0, 1.0)));
|
||||||
self.push_segment(&segment.transform(&(*transform * rotation)),
|
self.push_segment(
|
||||||
PushSegmentFlags::UPDATE_BOUNDS);
|
&segment.transform(&(*transform * rotation)),
|
||||||
|
PushSegmentFlags::UPDATE_BOUNDS,
|
||||||
|
);
|
||||||
rotation = Transform2F::from_rotation_vector(UnitVector(vec2f(-1.0, 0.0)));
|
rotation = Transform2F::from_rotation_vector(UnitVector(vec2f(-1.0, 0.0)));
|
||||||
self.push_segment(&segment.transform(&(*transform * rotation)),
|
self.push_segment(
|
||||||
PushSegmentFlags::UPDATE_BOUNDS);
|
&segment.transform(&(*transform * rotation)),
|
||||||
|
PushSegmentFlags::UPDATE_BOUNDS,
|
||||||
|
);
|
||||||
rotation = Transform2F::from_rotation_vector(UnitVector(vec2f(0.0, -1.0)));
|
rotation = Transform2F::from_rotation_vector(UnitVector(vec2f(0.0, -1.0)));
|
||||||
self.push_segment(&segment.transform(&(*transform * rotation)),
|
self.push_segment(
|
||||||
PushSegmentFlags::UPDATE_BOUNDS);
|
&segment.transform(&(*transform * rotation)),
|
||||||
|
PushSegmentFlags::UPDATE_BOUNDS,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the segment starting at the point with the given index.
|
/// Returns the segment starting at the point with the given index.
|
||||||
|
@ -928,8 +948,10 @@ impl Contour {
|
||||||
|
|
||||||
impl Debug for Contour {
|
impl Debug for Contour {
|
||||||
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
for (segment_index, segment) in self.iter(ContourIterFlags::IGNORE_CLOSE_SEGMENT)
|
for (segment_index, segment) in self
|
||||||
.enumerate() {
|
.iter(ContourIterFlags::IGNORE_CLOSE_SEGMENT)
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
if segment_index == 0 {
|
if segment_index == 0 {
|
||||||
write!(
|
write!(
|
||||||
formatter,
|
formatter,
|
||||||
|
@ -1024,10 +1046,11 @@ impl<'a> Iterator for ContourIter<'a> {
|
||||||
fn next(&mut self) -> Option<Segment> {
|
fn next(&mut self) -> Option<Segment> {
|
||||||
let contour = self.contour;
|
let contour = self.contour;
|
||||||
|
|
||||||
let include_close_segment = self.contour.closed &&
|
let include_close_segment =
|
||||||
!self.flags.contains(ContourIterFlags::IGNORE_CLOSE_SEGMENT);
|
self.contour.closed && !self.flags.contains(ContourIterFlags::IGNORE_CLOSE_SEGMENT);
|
||||||
if (self.index == contour.len() && !include_close_segment) ||
|
if (self.index == contour.len() && !include_close_segment)
|
||||||
self.index == contour.len() + 1 {
|
|| self.index == contour.len() + 1
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1050,7 +1073,10 @@ impl<'a> Iterator for ContourIter<'a> {
|
||||||
let point2 = contour.position_of(point2_index);
|
let point2 = contour.position_of(point2_index);
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
if contour.point_is_endpoint(point2_index) {
|
if contour.point_is_endpoint(point2_index) {
|
||||||
return Some(Segment::quadratic(LineSegment2F::new(point0, point2), point1));
|
return Some(Segment::quadratic(
|
||||||
|
LineSegment2F::new(point0, point2),
|
||||||
|
point1,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let point3_index = self.index;
|
let point3_index = self.index;
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::render_target::RenderTargetId;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use pathfinder_color::{self as color, ColorU};
|
use pathfinder_color::{self as color, ColorU};
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{vec2i, Vector2I};
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
@ -46,7 +46,7 @@ pub enum PatternSource {
|
||||||
id: RenderTargetId,
|
id: RenderTargetId,
|
||||||
/// The device pixel size of the render target.
|
/// The device pixel size of the render target.
|
||||||
size: Vector2I,
|
size: Vector2I,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A raster image, in 32-bit RGBA (8 bits per channel), non-premultiplied form.
|
/// A raster image, in 32-bit RGBA (8 bits per channel), non-premultiplied form.
|
||||||
|
@ -213,7 +213,12 @@ impl Image {
|
||||||
pixels.hash(&mut pixels_hasher);
|
pixels.hash(&mut pixels_hasher);
|
||||||
let pixels_hash = pixels_hasher.finish();
|
let pixels_hash = pixels_hasher.finish();
|
||||||
|
|
||||||
Image { size, pixels, pixels_hash, is_opaque }
|
Image {
|
||||||
|
size,
|
||||||
|
pixels,
|
||||||
|
pixels_hash,
|
||||||
|
is_opaque,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience function to create a new image with the given image from the `image` crate.
|
/// A convenience function to create a new image with the given image from the `image` crate.
|
||||||
|
@ -280,7 +285,10 @@ impl Debug for Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Image {
|
impl Hash for Image {
|
||||||
fn hash<H>(&self, hasher: &mut H) where H: Hasher {
|
fn hash<H>(&self, hasher: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
self.size.hash(hasher);
|
self.size.hash(hasher);
|
||||||
self.pixels_hash.hash(hasher);
|
self.pixels_hash.hash(hasher);
|
||||||
self.is_opaque.hash(hasher);
|
self.is_opaque.hash(hasher);
|
||||||
|
@ -290,7 +298,10 @@ impl Hash for Image {
|
||||||
impl Eq for Pattern {}
|
impl Eq for Pattern {}
|
||||||
|
|
||||||
impl Hash for Pattern {
|
impl Hash for Pattern {
|
||||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
fn hash<H>(&self, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
self.source.hash(state);
|
self.source.hash(state);
|
||||||
util::hash_transform2f(self.transform, state);
|
util::hash_transform2f(self.transform, state);
|
||||||
self.flags.hash(state);
|
self.flags.hash(state);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::util::EPSILON;
|
use pathfinder_geometry::util::EPSILON;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::f32::consts::SQRT_2;
|
use std::f32::consts::SQRT_2;
|
||||||
|
|
||||||
|
@ -100,8 +100,12 @@ impl Segment {
|
||||||
return Segment::line(LineSegment2F::new(vec2f(1.0, 0.0), vec2f(1.0, 0.0)));
|
return Segment::line(LineSegment2F::new(vec2f(1.0, 0.0), vec2f(1.0, 0.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let term = F32x4::new(cos_sweep_angle, -cos_sweep_angle,
|
let term = F32x4::new(
|
||||||
cos_sweep_angle, -cos_sweep_angle);
|
cos_sweep_angle,
|
||||||
|
-cos_sweep_angle,
|
||||||
|
cos_sweep_angle,
|
||||||
|
-cos_sweep_angle,
|
||||||
|
);
|
||||||
let signs = F32x4::new(1.0, -1.0, 1.0, 1.0);
|
let signs = F32x4::new(1.0, -1.0, 1.0, 1.0);
|
||||||
let p3p0 = ((F32x4::splat(1.0) + term) * F32x4::splat(0.5)).sqrt() * signs;
|
let p3p0 = ((F32x4::splat(1.0) + term) * F32x4::splat(0.5)).sqrt() * signs;
|
||||||
let (p0x, p0y) = (p3p0.z(), p3p0.w());
|
let (p0x, p0y) = (p3p0.z(), p3p0.w());
|
||||||
|
@ -175,8 +179,9 @@ impl Segment {
|
||||||
|
|
||||||
let mut new_segment = *self;
|
let mut new_segment = *self;
|
||||||
let p1_2 = self.ctrl.from() + self.ctrl.from();
|
let p1_2 = self.ctrl.from() + self.ctrl.from();
|
||||||
new_segment.ctrl = LineSegment2F::new(self.baseline.from() + p1_2,
|
new_segment.ctrl =
|
||||||
p1_2 + self.baseline.to()) * (1.0 / 3.0);
|
LineSegment2F::new(self.baseline.from() + p1_2, p1_2 + self.baseline.to())
|
||||||
|
* (1.0 / 3.0);
|
||||||
new_segment.kind = SegmentKind::Cubic;
|
new_segment.kind = SegmentKind::Cubic;
|
||||||
new_segment
|
new_segment
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::util::EPSILON;
|
use pathfinder_geometry::util::EPSILON;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
|
||||||
const TOLERANCE: f32 = 0.01;
|
const TOLERANCE: f32 = 0.01;
|
||||||
|
@ -86,7 +86,11 @@ impl<'a> OutlineStrokeToFill<'a> {
|
||||||
/// given stroke style.
|
/// given stroke style.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(input: &Outline, style: StrokeStyle) -> OutlineStrokeToFill {
|
pub fn new(input: &Outline, style: StrokeStyle) -> OutlineStrokeToFill {
|
||||||
OutlineStrokeToFill { input, output: Outline::new(), style }
|
OutlineStrokeToFill {
|
||||||
|
input,
|
||||||
|
output: Outline::new(),
|
||||||
|
style,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs the stroke operation.
|
/// Performs the stroke operation.
|
||||||
|
@ -94,18 +98,22 @@ impl<'a> OutlineStrokeToFill<'a> {
|
||||||
let mut new_contours = vec![];
|
let mut new_contours = vec![];
|
||||||
for input in &self.input.contours {
|
for input in &self.input.contours {
|
||||||
let closed = input.closed;
|
let closed = input.closed;
|
||||||
let mut stroker = ContourStrokeToFill::new(input,
|
let mut stroker = ContourStrokeToFill::new(
|
||||||
|
input,
|
||||||
Contour::new(),
|
Contour::new(),
|
||||||
self.style.line_width * 0.5,
|
self.style.line_width * 0.5,
|
||||||
self.style.line_join);
|
self.style.line_join,
|
||||||
|
);
|
||||||
|
|
||||||
stroker.offset_forward();
|
stroker.offset_forward();
|
||||||
if closed {
|
if closed {
|
||||||
self.push_stroked_contour(&mut new_contours, stroker, true);
|
self.push_stroked_contour(&mut new_contours, stroker, true);
|
||||||
stroker = ContourStrokeToFill::new(input,
|
stroker = ContourStrokeToFill::new(
|
||||||
|
input,
|
||||||
Contour::new(),
|
Contour::new(),
|
||||||
self.style.line_width * 0.5,
|
self.style.line_width * 0.5,
|
||||||
self.style.line_join);
|
self.style.line_join,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
self.add_cap(&mut stroker.output);
|
self.add_cap(&mut stroker.output);
|
||||||
}
|
}
|
||||||
|
@ -119,7 +127,9 @@ impl<'a> OutlineStrokeToFill<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_bounds = None;
|
let mut new_bounds = None;
|
||||||
new_contours.iter().for_each(|contour| contour.update_bounds(&mut new_bounds));
|
new_contours
|
||||||
|
.iter()
|
||||||
|
.for_each(|contour| contour.update_bounds(&mut new_bounds));
|
||||||
|
|
||||||
self.output.contours = new_contours;
|
self.output.contours = new_contours;
|
||||||
self.output.bounds = new_bounds.unwrap_or_else(|| RectF::default());
|
self.output.bounds = new_bounds.unwrap_or_else(|| RectF::default());
|
||||||
|
@ -131,18 +141,22 @@ impl<'a> OutlineStrokeToFill<'a> {
|
||||||
self.output
|
self.output
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_stroked_contour(&mut self,
|
fn push_stroked_contour(
|
||||||
|
&mut self,
|
||||||
new_contours: &mut Vec<Contour>,
|
new_contours: &mut Vec<Contour>,
|
||||||
mut stroker: ContourStrokeToFill,
|
mut stroker: ContourStrokeToFill,
|
||||||
closed: bool) {
|
closed: bool,
|
||||||
|
) {
|
||||||
// Add join if necessary.
|
// Add join if necessary.
|
||||||
if closed && stroker.output.might_need_join(self.style.line_join) {
|
if closed && stroker.output.might_need_join(self.style.line_join) {
|
||||||
let (p1, p0) = (stroker.output.position_of(1), stroker.output.position_of(0));
|
let (p1, p0) = (stroker.output.position_of(1), stroker.output.position_of(0));
|
||||||
let final_segment = LineSegment2F::new(p1, p0);
|
let final_segment = LineSegment2F::new(p1, p0);
|
||||||
stroker.output.add_join(self.style.line_width * 0.5,
|
stroker.output.add_join(
|
||||||
|
self.style.line_width * 0.5,
|
||||||
self.style.line_join,
|
self.style.line_join,
|
||||||
stroker.input.position_of(0),
|
stroker.input.position_of(0),
|
||||||
final_segment);
|
final_segment,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
stroker.output.closed = true;
|
stroker.output.closed = true;
|
||||||
|
@ -151,7 +165,7 @@ impl<'a> OutlineStrokeToFill<'a> {
|
||||||
|
|
||||||
fn add_cap(&mut self, contour: &mut Contour) {
|
fn add_cap(&mut self, contour: &mut Contour) {
|
||||||
if self.style.line_cap == LineCap::Butt || contour.len() < 2 {
|
if self.style.line_cap == LineCap::Butt || contour.len() < 2 {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let width = self.style.line_width;
|
let width = self.style.line_width;
|
||||||
|
@ -209,14 +223,23 @@ struct ContourStrokeToFill<'a> {
|
||||||
impl<'a> ContourStrokeToFill<'a> {
|
impl<'a> ContourStrokeToFill<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(input: &Contour, output: Contour, radius: f32, join: LineJoin) -> ContourStrokeToFill {
|
fn new(input: &Contour, output: Contour, radius: f32, join: LineJoin) -> ContourStrokeToFill {
|
||||||
ContourStrokeToFill { input, output, radius, join }
|
ContourStrokeToFill {
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
radius,
|
||||||
|
join,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset_forward(&mut self) {
|
fn offset_forward(&mut self) {
|
||||||
for (segment_index, segment) in self.input.iter(ContourIterFlags::empty()).enumerate() {
|
for (segment_index, segment) in self.input.iter(ContourIterFlags::empty()).enumerate() {
|
||||||
// FIXME(pcwalton): We negate the radius here so that round end caps can be drawn
|
// FIXME(pcwalton): We negate the radius here so that round end caps can be drawn
|
||||||
// clockwise. Of course, we should just implement anticlockwise arcs to begin with...
|
// clockwise. Of course, we should just implement anticlockwise arcs to begin with...
|
||||||
let join = if segment_index == 0 { LineJoin::Bevel } else { self.join };
|
let join = if segment_index == 0 {
|
||||||
|
LineJoin::Bevel
|
||||||
|
} else {
|
||||||
|
self.join
|
||||||
|
};
|
||||||
segment.offset(-self.radius, join, &mut self.output);
|
segment.offset(-self.radius, join, &mut self.output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,7 +254,11 @@ impl<'a> ContourStrokeToFill<'a> {
|
||||||
for (segment_index, segment) in segments.iter().enumerate() {
|
for (segment_index, segment) in segments.iter().enumerate() {
|
||||||
// FIXME(pcwalton): We negate the radius here so that round end caps can be drawn
|
// FIXME(pcwalton): We negate the radius here so that round end caps can be drawn
|
||||||
// clockwise. Of course, we should just implement anticlockwise arcs to begin with...
|
// clockwise. Of course, we should just implement anticlockwise arcs to begin with...
|
||||||
let join = if segment_index == 0 { LineJoin::Bevel } else { self.join };
|
let join = if segment_index == 0 {
|
||||||
|
LineJoin::Bevel
|
||||||
|
} else {
|
||||||
|
self.join
|
||||||
|
};
|
||||||
segment.offset(-self.radius, join, &mut self.output);
|
segment.offset(-self.radius, join, &mut self.output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,11 +266,13 @@ impl<'a> ContourStrokeToFill<'a> {
|
||||||
|
|
||||||
trait Offset {
|
trait Offset {
|
||||||
fn offset(&self, distance: f32, join: LineJoin, contour: &mut Contour);
|
fn offset(&self, distance: f32, join: LineJoin, contour: &mut Contour);
|
||||||
fn add_to_contour(&self,
|
fn add_to_contour(
|
||||||
|
&self,
|
||||||
distance: f32,
|
distance: f32,
|
||||||
join: LineJoin,
|
join: LineJoin,
|
||||||
join_point: Vector2F,
|
join_point: Vector2F,
|
||||||
contour: &mut Contour);
|
contour: &mut Contour,
|
||||||
|
);
|
||||||
fn offset_once(&self, distance: f32) -> Self;
|
fn offset_once(&self, distance: f32) -> Self;
|
||||||
fn error_is_within_tolerance(&self, other: &Segment, distance: f32) -> bool;
|
fn error_is_within_tolerance(&self, other: &Segment, distance: f32) -> bool;
|
||||||
}
|
}
|
||||||
|
@ -270,11 +299,13 @@ impl Offset for Segment {
|
||||||
after.offset(distance, join, contour);
|
after.offset(distance, join, contour);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_to_contour(&self,
|
fn add_to_contour(
|
||||||
|
&self,
|
||||||
distance: f32,
|
distance: f32,
|
||||||
join: LineJoin,
|
join: LineJoin,
|
||||||
join_point: Vector2F,
|
join_point: Vector2F,
|
||||||
contour: &mut Contour) {
|
contour: &mut Contour,
|
||||||
|
) {
|
||||||
// Add join if necessary.
|
// Add join if necessary.
|
||||||
if contour.might_need_join(join) {
|
if contour.might_need_join(join) {
|
||||||
let p3 = self.baseline.from();
|
let p3 = self.baseline.from();
|
||||||
|
@ -404,11 +435,13 @@ impl Contour {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_join(&mut self,
|
fn add_join(
|
||||||
|
&mut self,
|
||||||
distance: f32,
|
distance: f32,
|
||||||
join: LineJoin,
|
join: LineJoin,
|
||||||
join_point: Vector2F,
|
join_point: Vector2F,
|
||||||
next_tangent: LineSegment2F) {
|
next_tangent: LineSegment2F,
|
||||||
|
) {
|
||||||
let (p0, p1) = (self.position_of_last(2), self.position_of_last(1));
|
let (p0, p1) = (self.position_of_last(2), self.position_of_last(1));
|
||||||
let prev_tangent = LineSegment2F::new(p0, p1);
|
let prev_tangent = LineSegment2F::new(p0, p1);
|
||||||
|
|
||||||
|
@ -456,10 +489,14 @@ impl Default for StrokeStyle {
|
||||||
|
|
||||||
impl Default for LineCap {
|
impl Default for LineCap {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> LineCap { LineCap::Butt }
|
fn default() -> LineCap {
|
||||||
|
LineCap::Butt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LineJoin {
|
impl Default for LineJoin {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> LineJoin { LineJoin::Miter(10.0) }
|
fn default() -> LineJoin {
|
||||||
|
LineJoin::Miter(10.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,12 @@ where
|
||||||
// TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD?
|
// TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD?
|
||||||
let mut segment = self.iter.next()?;
|
let mut segment = self.iter.next()?;
|
||||||
if !segment.is_none() {
|
if !segment.is_none() {
|
||||||
segment.baseline.set_from(self.transform * segment.baseline.from());
|
segment
|
||||||
segment.baseline.set_to(self.transform * segment.baseline.to());
|
.baseline
|
||||||
|
.set_from(self.transform * segment.baseline.from());
|
||||||
|
segment
|
||||||
|
.baseline
|
||||||
|
.set_to(self.transform * segment.baseline.to());
|
||||||
if !segment.is_line() {
|
if !segment.is_line() {
|
||||||
segment.ctrl.set_from(self.transform * segment.ctrl.from());
|
segment.ctrl.set_from(self.transform * segment.ctrl.from());
|
||||||
if !segment.is_quadratic() {
|
if !segment.is_quadratic() {
|
||||||
|
@ -83,10 +87,16 @@ where
|
||||||
fn next(&mut self) -> Option<Segment> {
|
fn next(&mut self) -> Option<Segment> {
|
||||||
let mut segment = self.iter.next()?;
|
let mut segment = self.iter.next()?;
|
||||||
if !segment.is_none() {
|
if !segment.is_none() {
|
||||||
segment.baseline.set_from(self.perspective * segment.baseline.from());
|
segment
|
||||||
segment.baseline.set_to(self.perspective * segment.baseline.to());
|
.baseline
|
||||||
|
.set_from(self.perspective * segment.baseline.from());
|
||||||
|
segment
|
||||||
|
.baseline
|
||||||
|
.set_to(self.perspective * segment.baseline.to());
|
||||||
if !segment.is_line() {
|
if !segment.is_line() {
|
||||||
segment.ctrl.set_from(self.perspective * segment.ctrl.from());
|
segment
|
||||||
|
.ctrl
|
||||||
|
.set_from(self.perspective * segment.ctrl.from());
|
||||||
if !segment.is_quadratic() {
|
if !segment.is_quadratic() {
|
||||||
segment.ctrl.set_to(self.perspective * segment.ctrl.to());
|
segment.ctrl.set_to(self.perspective * segment.ctrl.to());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,30 +16,45 @@ use pathfinder_simd::default::{F32x2, F32x4};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
pub(crate) fn hash_line_segment<H>(line_segment: LineSegment2F, state: &mut H) where H: Hasher {
|
pub(crate) fn hash_line_segment<H>(line_segment: LineSegment2F, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
hash_f32x4(line_segment.0, state);
|
hash_f32x4(line_segment.0, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn hash_transform2f<H>(transform: Transform2F, state: &mut H) where H: Hasher {
|
pub(crate) fn hash_transform2f<H>(transform: Transform2F, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
hash_f32x4(transform.matrix.0, state);
|
hash_f32x4(transform.matrix.0, state);
|
||||||
hash_f32x2(transform.vector.0, state);
|
hash_f32x2(transform.vector.0, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn hash_f32<H>(value: f32, state: &mut H) where H: Hasher {
|
pub(crate) fn hash_f32<H>(value: f32, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let data: u32 = mem::transmute::<f32, u32>(value);
|
let data: u32 = mem::transmute::<f32, u32>(value);
|
||||||
data.hash(state);
|
data.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn hash_f32x2<H>(vector: F32x2, state: &mut H) where H: Hasher {
|
pub(crate) fn hash_f32x2<H>(vector: F32x2, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let data: [u32; 2] = mem::transmute::<F32x2, [u32; 2]>(vector);
|
let data: [u32; 2] = mem::transmute::<F32x2, [u32; 2]>(vector);
|
||||||
data.hash(state);
|
data.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn hash_f32x4<H>(vector: F32x4, state: &mut H) where H: Hasher {
|
pub(crate) fn hash_f32x4<H>(vector: F32x4, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let data: [u32; 4] = mem::transmute::<F32x4, [u32; 4]>(vector);
|
let data: [u32; 4] = mem::transmute::<F32x4, [u32; 4]>(vector);
|
||||||
data.hash(state);
|
data.hash(state);
|
||||||
|
|
|
@ -16,8 +16,8 @@ use jni::{JNIEnv, JavaVM};
|
||||||
use pathfinder_demo::window::{Event, SVGPath, View, Window, WindowSize};
|
use pathfinder_demo::window::{Event, SVGPath, View, Window, WindowSize};
|
||||||
use pathfinder_demo::DemoApp;
|
use pathfinder_demo::DemoApp;
|
||||||
use pathfinder_demo::Options;
|
use pathfinder_demo::Options;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
|
use pathfinder_geometry::vector::{vec2i, Vector2I};
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
@ -131,7 +131,10 @@ pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_Pathfinder
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
) {
|
) {
|
||||||
EVENT_QUEUE.lock().unwrap().push(Event::MouseDown(vec2i(x, y)))
|
EVENT_QUEUE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push(Event::MouseDown(vec2i(x, y)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -141,7 +144,10 @@ pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_Pathfinder
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
) {
|
) {
|
||||||
EVENT_QUEUE.lock().unwrap().push(Event::MouseDragged(vec2i(x, y)))
|
EVENT_QUEUE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push(Event::MouseDragged(vec2i(x, y)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -152,7 +158,10 @@ pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_Pathfinder
|
||||||
center_x: i32,
|
center_x: i32,
|
||||||
center_y: i32,
|
center_y: i32,
|
||||||
) {
|
) {
|
||||||
EVENT_QUEUE.lock().unwrap().push(Event::Zoom(factor, vec2i(center_x, center_y)))
|
EVENT_QUEUE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push(Event::Zoom(factor, vec2i(center_x, center_y)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -11,7 +11,7 @@ pf-gl = []
|
||||||
clap = "2.32"
|
clap = "2.32"
|
||||||
gl = "0.14"
|
gl = "0.14"
|
||||||
rayon = "1.0"
|
rayon = "1.0"
|
||||||
usvg = "0.9"
|
usvg = "0.10"
|
||||||
|
|
||||||
[dependencies.image]
|
[dependencies.image]
|
||||||
version = "0.23"
|
version = "0.23"
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
// proper.
|
// proper.
|
||||||
|
|
||||||
use crate::window::{OcularTransform, View};
|
use crate::window::{OcularTransform, View};
|
||||||
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
|
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
|
||||||
|
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
||||||
use std::f32::consts::FRAC_PI_4;
|
use std::f32::consts::FRAC_PI_4;
|
||||||
|
|
||||||
const NEAR_CLIP_PLANE: f32 = 0.01;
|
const NEAR_CLIP_PLANE: f32 = 0.01;
|
||||||
|
@ -53,8 +53,8 @@ impl Camera {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_2d(view_box: RectF, viewport_size: Vector2I) -> Camera {
|
fn new_2d(view_box: RectF, viewport_size: Vector2I) -> Camera {
|
||||||
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 *
|
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32
|
||||||
scale_factor_for_view_box(view_box);
|
* scale_factor_for_view_box(view_box);
|
||||||
let origin = viewport_size.to_f32() * 0.5 - view_box.size() * (scale * 0.5);
|
let origin = viewport_size.to_f32() * 0.5 - view_box.size() * (scale * 0.5);
|
||||||
Camera::TwoD(Transform2F::from_scale(scale).translate(origin))
|
Camera::TwoD(Transform2F::from_scale(scale).translate(origin))
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,8 @@ impl CameraTransform3D {
|
||||||
|
|
||||||
pub fn to_transform(&self) -> Transform4F {
|
pub fn to_transform(&self) -> Transform4F {
|
||||||
let flip = Vector4F::new(1.0, -1.0, 1.0, 1.0);
|
let flip = Vector4F::new(1.0, -1.0, 1.0, 1.0);
|
||||||
Transform4F::from_scale(flip).translate(-self.position)
|
Transform4F::from_scale(flip)
|
||||||
|
.translate(-self.position)
|
||||||
.uniform_scale(2.0 * self.scale)
|
.uniform_scale(2.0 * self.scale)
|
||||||
.rotate(self.yaw, self.pitch, 0.0)
|
.rotate(self.yaw, self.pitch, 0.0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,10 @@ impl DemoExecutor {
|
||||||
|
|
||||||
impl Executor for DemoExecutor {
|
impl Executor for DemoExecutor {
|
||||||
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
|
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
|
||||||
where T: Send, F: Fn(usize) -> T + Send + Sync {
|
where
|
||||||
|
T: Send,
|
||||||
|
F: Fn(usize) -> T + Send + Sync,
|
||||||
|
{
|
||||||
if self.sequential_mode {
|
if self.sequential_mode {
|
||||||
SequentialExecutor.build_vector(length, builder)
|
SequentialExecutor.build_vector(length, builder)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -63,10 +63,19 @@ where
|
||||||
) -> GroundVertexArray<D> {
|
) -> GroundVertexArray<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let position_attr = device.get_vertex_attr(&ground_program.program, "Position").unwrap();
|
let position_attr = device
|
||||||
|
.get_vertex_attr(&ground_program.program, "Position")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
device.bind_buffer(
|
||||||
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
|
&vertex_array,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&position_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -74,8 +83,13 @@ where
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quad_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
GroundVertexArray { vertex_array }
|
GroundVertexArray { vertex_array }
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ use crate::camera::Camera;
|
||||||
use crate::concurrent::DemoExecutor;
|
use crate::concurrent::DemoExecutor;
|
||||||
use crate::device::{GroundProgram, GroundVertexArray};
|
use crate::device::{GroundProgram, GroundVertexArray};
|
||||||
use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction};
|
use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction};
|
||||||
use crate::window::{Event, Keycode, DataPath, Window, WindowSize};
|
use crate::window::{DataPath, Event, Keycode, Window, WindowSize};
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use pathfinder_content::effects::DEFRINGING_KERNEL_CORE_GRAPHICS;
|
|
||||||
use pathfinder_content::effects::PatternFilter;
|
use pathfinder_content::effects::PatternFilter;
|
||||||
|
use pathfinder_content::effects::DEFRINGING_KERNEL_CORE_GRAPHICS;
|
||||||
use pathfinder_content::effects::STEM_DARKENING_FACTORS;
|
use pathfinder_content::effects::STEM_DARKENING_FACTORS;
|
||||||
use pathfinder_content::outline::Outline;
|
use pathfinder_content::outline::Outline;
|
||||||
use pathfinder_content::pattern::Pattern;
|
use pathfinder_content::pattern::Pattern;
|
||||||
|
@ -32,7 +32,7 @@ use pathfinder_export::{Export, FileFormat};
|
||||||
use pathfinder_geometry::rect::{RectF, RectI};
|
use pathfinder_geometry::rect::{RectF, RectI};
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::transform3d::Transform4F;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i};
|
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F, Vector2I, Vector4F};
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::Device;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
|
||||||
|
@ -44,14 +44,14 @@ use pathfinder_renderer::scene::{DrawPath, RenderTarget, Scene};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_svg::SVGScene;
|
use pathfinder_svg::SVGScene;
|
||||||
use pathfinder_ui::{MousePosition, UIEvent};
|
use pathfinder_ui::{MousePosition, UIEvent};
|
||||||
|
use pdf::file::{CachedFile, FileOptions};
|
||||||
|
use pdf_render::{Cache as PdfRenderCache, SceneBackend};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufWriter;
|
use std::io::BufWriter;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use usvg::{Options as UsvgOptions, Tree as SvgTree};
|
use usvg::{Options as UsvgOptions, Tree as SvgTree};
|
||||||
use pdf::file::{CachedFile, FileOptions};
|
|
||||||
use pdf_render::{Cache as PdfRenderCache, SceneBackend};
|
|
||||||
|
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
use pathfinder_gl::GLDevice as DeviceImpl;
|
use pathfinder_gl::GLDevice as DeviceImpl;
|
||||||
|
@ -88,11 +88,14 @@ enum Content {
|
||||||
Pdf {
|
Pdf {
|
||||||
file: CachedFile<Vec<u8>>,
|
file: CachedFile<Vec<u8>>,
|
||||||
cache: PdfRenderCache,
|
cache: PdfRenderCache,
|
||||||
page_nr: u32
|
page_nr: u32,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DemoApp<W> where W: Window {
|
pub struct DemoApp<W>
|
||||||
|
where
|
||||||
|
W: Window,
|
||||||
|
{
|
||||||
pub window: W,
|
pub window: W,
|
||||||
pub should_exit: bool,
|
pub should_exit: bool,
|
||||||
pub options: Options,
|
pub options: Options,
|
||||||
|
@ -126,7 +129,10 @@ pub struct DemoApp<W> where W: Window {
|
||||||
ground_vertex_array: GroundVertexArray<DeviceImpl>,
|
ground_vertex_array: GroundVertexArray<DeviceImpl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W> DemoApp<W> where W: Window {
|
impl<W> DemoApp<W>
|
||||||
|
where
|
||||||
|
W: Window,
|
||||||
|
{
|
||||||
pub fn new(window: W, window_size: WindowSize, options: Options) -> DemoApp<W> {
|
pub fn new(window: W, window_size: WindowSize, options: Options) -> DemoApp<W> {
|
||||||
let expire_message_event_id = window.create_user_event_id();
|
let expire_message_event_id = window.create_user_event_id();
|
||||||
|
|
||||||
|
@ -172,17 +178,18 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
|
|
||||||
let renderer = Renderer::new(device, resources, render_mode, render_options);
|
let renderer = Renderer::new(device, resources, render_mode, render_options);
|
||||||
|
|
||||||
let scene_metadata = SceneMetadata::new_clipping_view_box(&mut scene,
|
let scene_metadata = SceneMetadata::new_clipping_view_box(&mut scene, viewport.size());
|
||||||
viewport.size());
|
|
||||||
let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size());
|
let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size());
|
||||||
|
|
||||||
let scene_proxy = SceneProxy::from_scene(scene, level, executor);
|
let scene_proxy = SceneProxy::from_scene(scene, level, executor);
|
||||||
|
|
||||||
let ground_program = GroundProgram::new(renderer.device(), resources);
|
let ground_program = GroundProgram::new(renderer.device(), resources);
|
||||||
let ground_vertex_array = GroundVertexArray::new(renderer.device(),
|
let ground_vertex_array = GroundVertexArray::new(
|
||||||
|
renderer.device(),
|
||||||
&ground_program,
|
&ground_program,
|
||||||
&renderer.quad_vertex_positions_buffer(),
|
&renderer.quad_vertex_positions_buffer(),
|
||||||
&renderer.quad_vertex_indices_buffer());
|
&renderer.quad_vertex_indices_buffer(),
|
||||||
|
);
|
||||||
|
|
||||||
let mut message_epoch = 0;
|
let mut message_epoch = 0;
|
||||||
emit_message::<W>(
|
emit_message::<W>(
|
||||||
|
@ -260,9 +267,9 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
if modelview_transform.offset(*velocity) {
|
if modelview_transform.offset(*velocity) {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
let perspective = scene_transform.perspective *
|
let perspective = scene_transform.perspective
|
||||||
scene_transform.modelview_to_eye *
|
* scene_transform.modelview_to_eye
|
||||||
modelview_transform.to_transform();
|
* modelview_transform.to_transform();
|
||||||
Some(RenderTransform::Perspective(perspective))
|
Some(RenderTransform::Perspective(perspective))
|
||||||
}
|
}
|
||||||
Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)),
|
Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)),
|
||||||
|
@ -299,8 +306,8 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
Event::WindowResized(new_size) => {
|
Event::WindowResized(new_size) => {
|
||||||
self.window_size = new_size;
|
self.window_size = new_size;
|
||||||
let viewport = self.window.viewport(self.ui_model.mode.view(0));
|
let viewport = self.window.viewport(self.ui_model.mode.view(0));
|
||||||
self.scene_proxy.set_view_box(RectF::new(Vector2F::zero(),
|
self.scene_proxy
|
||||||
viewport.size().to_f32()));
|
.set_view_box(RectF::new(Vector2F::zero(), viewport.size().to_f32()));
|
||||||
self.renderer.options_mut().dest =
|
self.renderer.options_mut().dest =
|
||||||
DestFramebuffer::full_window(self.window_size.device_size());
|
DestFramebuffer::full_window(self.window_size.device_size());
|
||||||
self.renderer.dest_framebuffer_size_changed();
|
self.renderer.dest_framebuffer_size_changed();
|
||||||
|
@ -312,7 +319,11 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
}
|
}
|
||||||
Event::MouseMoved(new_position) if self.mouselook_enabled => {
|
Event::MouseMoved(new_position) if self.mouselook_enabled => {
|
||||||
let mouse_position = self.process_mouse_position(new_position);
|
let mouse_position = self.process_mouse_position(new_position);
|
||||||
if let Camera::ThreeD { ref mut modelview_transform, .. } = self.camera {
|
if let Camera::ThreeD {
|
||||||
|
ref mut modelview_transform,
|
||||||
|
..
|
||||||
|
} = self.camera
|
||||||
|
{
|
||||||
let rotation = mouse_position.relative.to_f32() * MOUSELOOK_ROTATION_SPEED;
|
let rotation = mouse_position.relative.to_f32() * MOUSELOOK_ROTATION_SPEED;
|
||||||
modelview_transform.yaw += rotation.x();
|
modelview_transform.yaw += rotation.x();
|
||||||
modelview_transform.pitch += rotation.y();
|
modelview_transform.pitch += rotation.y();
|
||||||
|
@ -329,13 +340,18 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let backing_scale_factor = self.window_size.backing_scale_factor;
|
let backing_scale_factor = self.window_size.backing_scale_factor;
|
||||||
let position = position.to_f32() * backing_scale_factor;
|
let position = position.to_f32() * backing_scale_factor;
|
||||||
let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
|
let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
|
||||||
*transform = transform.translate(-position)
|
*transform = transform
|
||||||
|
.translate(-position)
|
||||||
.scale(scale_delta)
|
.scale(scale_delta)
|
||||||
.translate(position);
|
.translate(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Look { pitch, yaw } => {
|
Event::Look { pitch, yaw } => {
|
||||||
if let Camera::ThreeD { ref mut modelview_transform, .. } = self.camera {
|
if let Camera::ThreeD {
|
||||||
|
ref mut modelview_transform,
|
||||||
|
..
|
||||||
|
} = self.camera
|
||||||
|
{
|
||||||
modelview_transform.pitch += pitch;
|
modelview_transform.pitch += pitch;
|
||||||
modelview_transform.yaw += yaw;
|
modelview_transform.yaw += yaw;
|
||||||
}
|
}
|
||||||
|
@ -352,21 +368,20 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
*scene_transform = eye_transforms[0];
|
*scene_transform = eye_transforms[0];
|
||||||
for (index, eye_transform) in eye_transforms.iter().enumerate().skip(1) {
|
for (index, eye_transform) in eye_transforms.iter().enumerate().skip(1) {
|
||||||
let weight = 1.0 / (index + 1) as f32;
|
let weight = 1.0 / (index + 1) as f32;
|
||||||
scene_transform.perspective.transform =
|
scene_transform.perspective.transform = scene_transform
|
||||||
scene_transform.perspective
|
.perspective
|
||||||
.transform
|
.transform
|
||||||
.lerp(weight, &eye_transform.perspective.transform);
|
.lerp(weight, &eye_transform.perspective.transform);
|
||||||
scene_transform.modelview_to_eye =
|
scene_transform.modelview_to_eye = scene_transform
|
||||||
scene_transform.modelview_to_eye
|
.modelview_to_eye
|
||||||
.lerp(weight, &eye_transform.modelview_to_eye);
|
.lerp(weight, &eye_transform.modelview_to_eye);
|
||||||
}
|
}
|
||||||
// TODO: calculate the eye offset from the eye transforms?
|
// TODO: calculate the eye offset from the eye transforms?
|
||||||
let z_offset = -DEFAULT_EYE_OFFSET *
|
let z_offset =
|
||||||
scene_transform.perspective.transform.c0.x();
|
-DEFAULT_EYE_OFFSET * scene_transform.perspective.transform.c0.x();
|
||||||
let z_offset = Vector4F::new(0.0, 0.0, z_offset, 1.0);
|
let z_offset = Vector4F::new(0.0, 0.0, z_offset, 1.0);
|
||||||
scene_transform.modelview_to_eye =
|
scene_transform.modelview_to_eye = Transform4F::from_translation(z_offset)
|
||||||
Transform4F::from_translation(z_offset) *
|
* scene_transform.modelview_to_eye;
|
||||||
scene_transform.modelview_to_eye;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
|
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
|
||||||
|
@ -452,9 +467,11 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let viewport_size = self.window.viewport(self.ui_model.mode.view(0)).size();
|
let viewport_size = self.window.viewport(self.ui_model.mode.view(0)).size();
|
||||||
self.scene_metadata =
|
self.scene_metadata =
|
||||||
SceneMetadata::new_clipping_view_box(&mut scene, viewport_size);
|
SceneMetadata::new_clipping_view_box(&mut scene, viewport_size);
|
||||||
self.camera = Camera::new(self.ui_model.mode,
|
self.camera = Camera::new(
|
||||||
|
self.ui_model.mode,
|
||||||
self.scene_metadata.view_box,
|
self.scene_metadata.view_box,
|
||||||
viewport_size);
|
viewport_size,
|
||||||
|
);
|
||||||
|
|
||||||
self.scene_proxy.replace_scene(scene);
|
self.scene_proxy.replace_scene(scene);
|
||||||
|
|
||||||
|
@ -498,19 +515,28 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
.push(*ui_event);
|
.push(*ui_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.renderer.debug_ui_presenter_mut().debug_ui_presenter.ui_presenter.mouse_position =
|
self.renderer
|
||||||
|
.debug_ui_presenter_mut()
|
||||||
|
.debug_ui_presenter
|
||||||
|
.ui_presenter
|
||||||
|
.mouse_position =
|
||||||
self.last_mouse_position.to_f32() * self.window_size.backing_scale_factor;
|
self.last_mouse_position.to_f32() * self.window_size.backing_scale_factor;
|
||||||
|
|
||||||
let mut ui_action = UIAction::None;
|
let mut ui_action = UIAction::None;
|
||||||
if self.options.ui == UIVisibility::All {
|
if self.options.ui == UIVisibility::All {
|
||||||
let DebugUIPresenterInfo { device, allocator, debug_ui_presenter } =
|
let DebugUIPresenterInfo {
|
||||||
self.renderer.debug_ui_presenter_mut();
|
device,
|
||||||
self.ui_presenter.update(device,
|
allocator,
|
||||||
|
debug_ui_presenter,
|
||||||
|
} = self.renderer.debug_ui_presenter_mut();
|
||||||
|
self.ui_presenter.update(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&mut self.window,
|
&mut self.window,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
&mut ui_action,
|
&mut ui_action,
|
||||||
&mut self.ui_model);
|
&mut self.ui_model,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handle_ui_events(frame, &mut ui_action);
|
self.handle_ui_events(frame, &mut ui_action);
|
||||||
|
@ -524,19 +550,27 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
fn maybe_take_screenshot(&mut self) {
|
fn maybe_take_screenshot(&mut self) {
|
||||||
match self.pending_screenshot_info.take() {
|
match self.pending_screenshot_info.take() {
|
||||||
None => {}
|
None => {}
|
||||||
Some(ScreenshotInfo { kind: ScreenshotType::PNG, path }) => {
|
Some(ScreenshotInfo {
|
||||||
self.take_raster_screenshot(path)
|
kind: ScreenshotType::PNG,
|
||||||
}
|
path,
|
||||||
Some(ScreenshotInfo { kind: ScreenshotType::SVG, path }) => {
|
}) => self.take_raster_screenshot(path),
|
||||||
|
Some(ScreenshotInfo {
|
||||||
|
kind: ScreenshotType::SVG,
|
||||||
|
path,
|
||||||
|
}) => {
|
||||||
// FIXME(pcwalton): This won't work on Android.
|
// FIXME(pcwalton): This won't work on Android.
|
||||||
let mut writer = BufWriter::new(File::create(path).unwrap());
|
let mut writer = BufWriter::new(File::create(path).unwrap());
|
||||||
self.scene_proxy.copy_scene().export(&mut writer, FileFormat::SVG).unwrap();
|
self.scene_proxy
|
||||||
|
.copy_scene()
|
||||||
|
.export(&mut writer, FileFormat::SVG)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_ui_events(&mut self, mut frame: Frame, ui_action: &mut UIAction) {
|
fn handle_ui_events(&mut self, mut frame: Frame, ui_action: &mut UIAction) {
|
||||||
frame.ui_events = self.renderer
|
frame.ui_events = self
|
||||||
|
.renderer
|
||||||
.debug_ui_presenter_mut()
|
.debug_ui_presenter_mut()
|
||||||
.debug_ui_presenter
|
.debug_ui_presenter
|
||||||
.ui_presenter
|
.ui_presenter
|
||||||
|
@ -550,9 +584,11 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
// FIXME(pcwalton): This should really be an MVC setup.
|
// FIXME(pcwalton): This should really be an MVC setup.
|
||||||
if self.camera.mode() != self.ui_model.mode {
|
if self.camera.mode() != self.ui_model.mode {
|
||||||
let viewport_size = self.window.viewport(self.ui_model.mode.view(0)).size();
|
let viewport_size = self.window.viewport(self.ui_model.mode.view(0)).size();
|
||||||
self.camera = Camera::new(self.ui_model.mode,
|
self.camera = Camera::new(
|
||||||
|
self.ui_model.mode,
|
||||||
self.scene_metadata.view_box,
|
self.scene_metadata.view_box,
|
||||||
viewport_size);
|
viewport_size,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ui_event in frame.ui_events {
|
for ui_event in frame.ui_events {
|
||||||
|
@ -614,7 +650,8 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
if let Camera::TwoD(ref mut transform) = self.camera {
|
if let Camera::TwoD(ref mut transform) = self.camera {
|
||||||
let old_rotation = transform.rotation();
|
let old_rotation = transform.rotation();
|
||||||
let center = center_of_window(&self.window_size);
|
let center = center_of_window(&self.window_size);
|
||||||
*transform = transform.translate(-center)
|
*transform = transform
|
||||||
|
.translate(-center)
|
||||||
.rotate(*theta - old_rotation)
|
.rotate(*theta - old_rotation)
|
||||||
.translate(center);
|
.translate(center);
|
||||||
}
|
}
|
||||||
|
@ -695,7 +732,7 @@ impl Options {
|
||||||
Arg::with_name("high-performance-gpu")
|
Arg::with_name("high-performance-gpu")
|
||||||
.short("g")
|
.short("g")
|
||||||
.long("high-performance-gpu")
|
.long("high-performance-gpu")
|
||||||
.help("Use the high-performance (discrete) GPU, if available")
|
.help("Use the high-performance (discrete) GPU, if available"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("level")
|
Arg::with_name("level")
|
||||||
|
@ -703,7 +740,7 @@ impl Options {
|
||||||
.short("l")
|
.short("l")
|
||||||
.help("Set the renderer feature level as a Direct3D version equivalent")
|
.help("Set the renderer feature level as a Direct3D version equivalent")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["9", "11"])
|
.possible_values(&["9", "11"]),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("INPUT")
|
Arg::with_name("INPUT")
|
||||||
|
@ -764,36 +801,52 @@ pub enum UIVisibility {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Content {
|
impl Content {
|
||||||
fn render(&mut self, viewport_size: Vector2I, filter: Option<PatternFilter>) -> (Scene, String) {
|
fn render(
|
||||||
|
&mut self,
|
||||||
|
viewport_size: Vector2I,
|
||||||
|
filter: Option<PatternFilter>,
|
||||||
|
) -> (Scene, String) {
|
||||||
match *self {
|
match *self {
|
||||||
Content::Svg(ref tree) => {
|
Content::Svg(ref tree) => {
|
||||||
let built_svg = build_svg_tree(&tree, viewport_size, filter);
|
let built_svg = build_svg_tree(&tree, viewport_size, filter);
|
||||||
let message = get_svg_building_message(&built_svg);
|
let message = get_svg_building_message(&built_svg);
|
||||||
(built_svg.scene, message)
|
(built_svg.scene, message)
|
||||||
}
|
}
|
||||||
Content::Pdf { ref file, ref mut cache, page_nr } => {
|
Content::Pdf {
|
||||||
|
ref file,
|
||||||
|
ref mut cache,
|
||||||
|
page_nr,
|
||||||
|
} => {
|
||||||
let page = file.get_page(page_nr).expect("no such page");
|
let page = file.get_page(page_nr).expect("no such page");
|
||||||
let mut backend = SceneBackend::new(cache);
|
let mut backend = SceneBackend::new(cache);
|
||||||
pdf_render::render_page(&mut backend, &file.resolver(), &page, Transform2F::default()).unwrap();
|
pdf_render::render_page(
|
||||||
|
&mut backend,
|
||||||
|
&file.resolver(),
|
||||||
|
&page,
|
||||||
|
Transform2F::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
(backend.finish(), String::new())
|
(backend.finish(), String::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_scene(resource_loader: &dyn ResourceLoader,
|
fn load_scene(resource_loader: &dyn ResourceLoader, input_path: &DataPath) -> Content {
|
||||||
input_path: &DataPath,)
|
|
||||||
-> Content {
|
|
||||||
let data = match *input_path {
|
let data = match *input_path {
|
||||||
DataPath::Default => resource_loader.slurp(DEFAULT_SVG_VIRTUAL_PATH).unwrap(),
|
DataPath::Default => resource_loader.slurp(DEFAULT_SVG_VIRTUAL_PATH).unwrap(),
|
||||||
DataPath::Resource(ref name) => resource_loader.slurp(name).unwrap(),
|
DataPath::Resource(ref name) => resource_loader.slurp(name).unwrap(),
|
||||||
DataPath::Path(ref path) => std::fs::read(path).unwrap().into()
|
DataPath::Path(ref path) => std::fs::read(path).unwrap().into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(tree) = SvgTree::from_data(&data, &UsvgOptions::default()) {
|
if let Ok(tree) = SvgTree::from_data(&data, &UsvgOptions::default()) {
|
||||||
Content::Svg(tree)
|
Content::Svg(tree)
|
||||||
} else if let Ok(file) = FileOptions::cached().load(data) {
|
} else if let Ok(file) = FileOptions::cached().load(data) {
|
||||||
Content::Pdf { file, cache: PdfRenderCache::new(), page_nr: 0 }
|
Content::Pdf {
|
||||||
|
file,
|
||||||
|
cache: PdfRenderCache::new(),
|
||||||
|
page_nr: 0,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("can't load data");
|
panic!("can't load data");
|
||||||
}
|
}
|
||||||
|
@ -801,22 +854,38 @@ fn load_scene(resource_loader: &dyn ResourceLoader,
|
||||||
|
|
||||||
// FIXME(pcwalton): Rework how transforms work in the demo. The transform affects the final
|
// FIXME(pcwalton): Rework how transforms work in the demo. The transform affects the final
|
||||||
// composite steps, breaking this approach.
|
// composite steps, breaking this approach.
|
||||||
fn build_svg_tree(tree: &SvgTree, viewport_size: Vector2I, filter: Option<PatternFilter>) -> SVGScene {
|
fn build_svg_tree(
|
||||||
|
tree: &SvgTree,
|
||||||
|
viewport_size: Vector2I,
|
||||||
|
filter: Option<PatternFilter>,
|
||||||
|
) -> SVGScene {
|
||||||
let mut scene = Scene::new();
|
let mut scene = Scene::new();
|
||||||
let filter_info = filter.map(|filter| {
|
let filter_info = filter.map(|filter| {
|
||||||
let scale = match filter {
|
let scale = match filter {
|
||||||
PatternFilter::Text { defringing_kernel: Some(_), .. } => vec2i(3, 1),
|
PatternFilter::Text {
|
||||||
|
defringing_kernel: Some(_),
|
||||||
|
..
|
||||||
|
} => vec2i(3, 1),
|
||||||
_ => vec2i(1, 1),
|
_ => vec2i(1, 1),
|
||||||
};
|
};
|
||||||
let name = "Text".to_owned();
|
let name = "Text".to_owned();
|
||||||
let render_target_size = viewport_size * scale;
|
let render_target_size = viewport_size * scale;
|
||||||
let render_target = RenderTarget::new(render_target_size, name);
|
let render_target = RenderTarget::new(render_target_size, name);
|
||||||
let render_target_id = scene.push_render_target(render_target);
|
let render_target_id = scene.push_render_target(render_target);
|
||||||
FilterInfo { filter, render_target_id, render_target_size }
|
FilterInfo {
|
||||||
|
filter,
|
||||||
|
render_target_id,
|
||||||
|
render_target_size,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut built_svg = SVGScene::from_tree_and_scene(&tree, scene);
|
let mut built_svg = SVGScene::from_tree_and_scene(&tree, scene);
|
||||||
if let Some(FilterInfo { filter, render_target_id, render_target_size }) = filter_info {
|
if let Some(FilterInfo {
|
||||||
|
filter,
|
||||||
|
render_target_id,
|
||||||
|
render_target_size,
|
||||||
|
}) = filter_info
|
||||||
|
{
|
||||||
let mut pattern = Pattern::from_render_target(render_target_id, render_target_size);
|
let mut pattern = Pattern::from_render_target(render_target_id, render_target_size);
|
||||||
pattern.set_filter(Some(filter));
|
pattern.set_filter(Some(filter));
|
||||||
let paint_id = built_svg.scene.push_paint(&Paint::from_pattern(pattern));
|
let paint_id = built_svg.scene.push_paint(&Paint::from_pattern(pattern));
|
||||||
|
@ -879,7 +948,10 @@ struct Frame {
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
fn new(transform: RenderTransform, ui_events: Vec<UIEvent>) -> Frame {
|
fn new(transform: RenderTransform, ui_events: Vec<UIEvent>) -> Frame {
|
||||||
Frame { transform, ui_events }
|
Frame {
|
||||||
|
transform,
|
||||||
|
ui_events,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,6 +1000,6 @@ fn build_filter(ui_model: &DemoUIModel) -> Option<PatternFilter> {
|
||||||
Some(DEFRINGING_KERNEL_CORE_GRAPHICS)
|
Some(DEFRINGING_KERNEL_CORE_GRAPHICS)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@ use crate::window::{View, Window};
|
||||||
use crate::{BackgroundColor, DemoApp, UIVisibility};
|
use crate::{BackgroundColor, DemoApp, UIVisibility};
|
||||||
use image::ColorType;
|
use image::ColorType;
|
||||||
use pathfinder_color::{ColorF, ColorU};
|
use pathfinder_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::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::Transform4F;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
||||||
|
use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions};
|
||||||
|
use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData};
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
||||||
use pathfinder_renderer::options::RenderTransform;
|
use pathfinder_renderer::options::RenderTransform;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -41,7 +41,10 @@ const GROUND_LINE_COLOR: ColorU = ColorU {
|
||||||
|
|
||||||
const GRIDLINE_COUNT: i32 = 10;
|
const GRIDLINE_COUNT: i32 = 10;
|
||||||
|
|
||||||
impl<W> DemoApp<W> where W: Window {
|
impl<W> DemoApp<W>
|
||||||
|
where
|
||||||
|
W: Window,
|
||||||
|
{
|
||||||
pub fn prepare_frame_rendering(&mut self) -> u32 {
|
pub fn prepare_frame_rendering(&mut self) -> u32 {
|
||||||
// Make the context current.
|
// Make the context current.
|
||||||
let view = self.ui_model.mode.view(0);
|
let view = self.ui_model.mode.view(0);
|
||||||
|
@ -62,9 +65,10 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let viewport = self.window.viewport(View::Stereo(0));
|
let viewport = self.window.viewport(View::Stereo(0));
|
||||||
if self.scene_framebuffer.is_none()
|
if self.scene_framebuffer.is_none()
|
||||||
|| self.renderer.device().texture_size(
|
|| self.renderer.device().texture_size(
|
||||||
&self.renderer.device().framebuffer_texture(self.scene_framebuffer
|
&self
|
||||||
.as_ref()
|
.renderer
|
||||||
.unwrap()),
|
.device()
|
||||||
|
.framebuffer_texture(self.scene_framebuffer.as_ref().unwrap()),
|
||||||
) != viewport.size()
|
) != viewport.size()
|
||||||
{
|
{
|
||||||
let scene_texture = self
|
let scene_texture = self
|
||||||
|
@ -120,9 +124,9 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
},
|
},
|
||||||
..*self.renderer.options()
|
..*self.renderer.options()
|
||||||
};
|
};
|
||||||
if let DestFramebuffer::Other(scene_framebuffer) = mem::replace(self.renderer
|
if let DestFramebuffer::Other(scene_framebuffer) =
|
||||||
.options_mut(),
|
mem::replace(self.renderer.options_mut(), new_options).dest
|
||||||
new_options).dest {
|
{
|
||||||
self.scene_framebuffer = Some(scene_framebuffer);
|
self.scene_framebuffer = Some(scene_framebuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,22 +169,25 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
self.draw_environment(render_scene_index);
|
self.draw_environment(render_scene_index);
|
||||||
|
|
||||||
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
||||||
let scene_texture = self.renderer.device().framebuffer_texture(scene_framebuffer);
|
let scene_texture = self
|
||||||
|
.renderer
|
||||||
|
.device()
|
||||||
|
.framebuffer_texture(scene_framebuffer);
|
||||||
|
|
||||||
let mut quad_scale = self.scene_metadata.view_box.size().to_4d();
|
let mut quad_scale = self.scene_metadata.view_box.size().to_4d();
|
||||||
quad_scale.set_z(1.0);
|
quad_scale.set_z(1.0);
|
||||||
let quad_scale_transform = Transform4F::from_scale(quad_scale);
|
let quad_scale_transform = Transform4F::from_scale(quad_scale);
|
||||||
|
|
||||||
let scene_transform_matrix = scene_transform.perspective *
|
let scene_transform_matrix = scene_transform.perspective
|
||||||
scene_transform.modelview_to_eye *
|
* scene_transform.modelview_to_eye
|
||||||
modelview_transform.to_transform() *
|
* modelview_transform.to_transform()
|
||||||
quad_scale_transform;
|
* quad_scale_transform;
|
||||||
|
|
||||||
let eye_transform = &eye_transforms[render_scene_index as usize];
|
let eye_transform = &eye_transforms[render_scene_index as usize];
|
||||||
let eye_transform_matrix = eye_transform.perspective *
|
let eye_transform_matrix = eye_transform.perspective
|
||||||
eye_transform.modelview_to_eye *
|
* eye_transform.modelview_to_eye
|
||||||
modelview_transform.to_transform() *
|
* modelview_transform.to_transform()
|
||||||
quad_scale_transform;
|
* quad_scale_transform;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"eye transform({}).modelview_to_eye={:?}",
|
"eye transform({}).modelview_to_eye={:?}",
|
||||||
|
@ -220,8 +227,8 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let base_transform = perspective.transform * Transform4F::from_translation(offset);
|
let base_transform = perspective.transform * Transform4F::from_translation(offset);
|
||||||
|
|
||||||
// Fill ground.
|
// Fill ground.
|
||||||
let transform = base_transform *
|
let transform = base_transform
|
||||||
Transform4F::from_scale(Vector4F::new(ground_scale, 1.0, ground_scale, 1.0));
|
* Transform4F::from_scale(Vector4F::new(ground_scale, 1.0, ground_scale, 1.0));
|
||||||
|
|
||||||
// Don't clear the first scene after drawing it.
|
// Don't clear the first scene after drawing it.
|
||||||
let clear_color = if render_scene_index == 0 {
|
let clear_color = if render_scene_index == 0 {
|
||||||
|
@ -230,7 +237,9 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
self.renderer.device().draw_elements(6, &RenderState {
|
self.renderer.device().draw_elements(
|
||||||
|
6,
|
||||||
|
&RenderState {
|
||||||
target: &self.renderer.draw_render_target(),
|
target: &self.renderer.draw_render_target(),
|
||||||
program: &self.ground_program.program,
|
program: &self.ground_program.program,
|
||||||
vertex_array: &self.ground_vertex_array.vertex_array,
|
vertex_array: &self.ground_vertex_array.vertex_array,
|
||||||
|
@ -239,21 +248,38 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
images: &[],
|
images: &[],
|
||||||
storage_buffers: &[],
|
storage_buffers: &[],
|
||||||
uniforms: &[
|
uniforms: &[
|
||||||
(&self.ground_program.transform_uniform,
|
(
|
||||||
UniformData::from_transform_3d(&transform)),
|
&self.ground_program.transform_uniform,
|
||||||
(&self.ground_program.ground_color_uniform,
|
UniformData::from_transform_3d(&transform),
|
||||||
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.ground_color_uniform,
|
||||||
(&self.ground_program.gridline_count_uniform, UniformData::Int(GRIDLINE_COUNT)),
|
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(),
|
viewport: self.renderer.draw_viewport(),
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
depth: Some(DepthState { func: DepthFunc::Less, write: true }),
|
depth: Some(DepthState {
|
||||||
clear_ops: ClearOps { color: clear_color, depth: Some(1.0), stencil: Some(0) },
|
func: DepthFunc::Less,
|
||||||
|
write: true,
|
||||||
|
}),
|
||||||
|
clear_ops: ClearOps {
|
||||||
|
color: clear_color,
|
||||||
|
depth: Some(1.0),
|
||||||
|
stencil: Some(0),
|
||||||
|
},
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
|
@ -271,9 +297,15 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
pub fn take_raster_screenshot(&mut self, path: PathBuf) {
|
pub fn take_raster_screenshot(&mut self, path: PathBuf) {
|
||||||
let drawable_size = self.window_size.device_size();
|
let drawable_size = self.window_size.device_size();
|
||||||
let viewport = RectI::new(Vector2I::default(), drawable_size);
|
let viewport = RectI::new(Vector2I::default(), drawable_size);
|
||||||
let texture_data_receiver =
|
let texture_data_receiver = self
|
||||||
self.renderer.device().read_pixels(&RenderTarget::Default, viewport);
|
.renderer
|
||||||
let pixels = match self.renderer.device().recv_texture_data(&texture_data_receiver) {
|
.device()
|
||||||
|
.read_pixels(&RenderTarget::Default, viewport);
|
||||||
|
let pixels = match self
|
||||||
|
.renderer
|
||||||
|
.device()
|
||||||
|
.recv_texture_data(&texture_data_receiver)
|
||||||
|
{
|
||||||
TextureData::U8(pixels) => pixels,
|
TextureData::U8(pixels) => pixels,
|
||||||
_ => panic!("Unexpected pixel format for default framebuffer!"),
|
_ => panic!("Unexpected pixel format for default framebuffer!"),
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::window::Window;
|
||||||
use crate::{BackgroundColor, Options};
|
use crate::{BackgroundColor, Options};
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{vec2i, Vector2I};
|
||||||
use pathfinder_gpu::allocator::GPUMemoryAllocator;
|
use pathfinder_gpu::allocator::GPUMemoryAllocator;
|
||||||
use pathfinder_gpu::{Device, TextureFormat};
|
use pathfinder_gpu::{Device, TextureFormat};
|
||||||
use pathfinder_renderer::gpu::debug::DebugUIPresenter;
|
use pathfinder_renderer::gpu::debug::DebugUIPresenter;
|
||||||
|
@ -41,9 +41,24 @@ const SCREENSHOT_PANEL_HEIGHT: i32 = BUTTON_HEIGHT * 2;
|
||||||
const ROTATE_PANEL_WIDTH: i32 = SLIDER_WIDTH + PADDING * 2;
|
const ROTATE_PANEL_WIDTH: i32 = SLIDER_WIDTH + PADDING * 2;
|
||||||
const ROTATE_PANEL_HEIGHT: i32 = PADDING * 2 + SLIDER_HEIGHT;
|
const ROTATE_PANEL_HEIGHT: i32 = PADDING * 2 + SLIDER_HEIGHT;
|
||||||
|
|
||||||
const LIGHT_BG_COLOR: ColorU = ColorU { r: 248, g: 248, b: 248, a: 255, };
|
const LIGHT_BG_COLOR: ColorU = ColorU {
|
||||||
const DARK_BG_COLOR: ColorU = ColorU { r: 32, g: 32, b: 32, a: 255, };
|
r: 248,
|
||||||
const TRANSPARENT_BG_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 0, };
|
g: 248,
|
||||||
|
b: 248,
|
||||||
|
a: 255,
|
||||||
|
};
|
||||||
|
const DARK_BG_COLOR: ColorU = ColorU {
|
||||||
|
r: 32,
|
||||||
|
g: 32,
|
||||||
|
b: 32,
|
||||||
|
a: 255,
|
||||||
|
};
|
||||||
|
const TRANSPARENT_BG_COLOR: ColorU = ColorU {
|
||||||
|
r: 0,
|
||||||
|
g: 0,
|
||||||
|
b: 0,
|
||||||
|
a: 0,
|
||||||
|
};
|
||||||
|
|
||||||
static EFFECTS_PNG_NAME: &'static str = "demo-effects";
|
static EFFECTS_PNG_NAME: &'static str = "demo-effects";
|
||||||
static OPEN_PNG_NAME: &'static str = "demo-open";
|
static OPEN_PNG_NAME: &'static str = "demo-open";
|
||||||
|
@ -98,7 +113,10 @@ impl DemoUIModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DemoUIPresenter<D> where D: Device {
|
pub struct DemoUIPresenter<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
effects_texture: D::Texture,
|
effects_texture: D::Texture,
|
||||||
open_texture: D::Texture,
|
open_texture: D::Texture,
|
||||||
rotate_texture: D::Texture,
|
rotate_texture: D::Texture,
|
||||||
|
@ -114,34 +132,29 @@ pub struct DemoUIPresenter<D> where D: Device {
|
||||||
rotate_panel_visible: bool,
|
rotate_panel_visible: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> DemoUIPresenter<D> where D: Device {
|
impl<D> DemoUIPresenter<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> DemoUIPresenter<D> {
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> DemoUIPresenter<D> {
|
||||||
device.begin_commands();
|
device.begin_commands();
|
||||||
|
|
||||||
let effects_texture = device.create_texture_from_png(resources,
|
let effects_texture =
|
||||||
EFFECTS_PNG_NAME,
|
device.create_texture_from_png(resources, EFFECTS_PNG_NAME, TextureFormat::R8);
|
||||||
TextureFormat::R8);
|
let open_texture =
|
||||||
let open_texture = device.create_texture_from_png(resources,
|
device.create_texture_from_png(resources, OPEN_PNG_NAME, TextureFormat::R8);
|
||||||
OPEN_PNG_NAME,
|
let rotate_texture =
|
||||||
TextureFormat::R8);
|
device.create_texture_from_png(resources, ROTATE_PNG_NAME, TextureFormat::R8);
|
||||||
let rotate_texture = device.create_texture_from_png(resources,
|
let zoom_in_texture =
|
||||||
ROTATE_PNG_NAME,
|
device.create_texture_from_png(resources, ZOOM_IN_PNG_NAME, TextureFormat::R8);
|
||||||
TextureFormat::R8);
|
let zoom_actual_size_texture =
|
||||||
let zoom_in_texture = device.create_texture_from_png(resources,
|
device.create_texture_from_png(resources, ZOOM_ACTUAL_SIZE_PNG_NAME, TextureFormat::R8);
|
||||||
ZOOM_IN_PNG_NAME,
|
let zoom_out_texture =
|
||||||
TextureFormat::R8);
|
device.create_texture_from_png(resources, ZOOM_OUT_PNG_NAME, TextureFormat::R8);
|
||||||
let zoom_actual_size_texture = device.create_texture_from_png(resources,
|
let background_texture =
|
||||||
ZOOM_ACTUAL_SIZE_PNG_NAME,
|
device.create_texture_from_png(resources, BACKGROUND_PNG_NAME, TextureFormat::R8);
|
||||||
TextureFormat::R8);
|
let screenshot_texture =
|
||||||
let zoom_out_texture = device.create_texture_from_png(resources,
|
device.create_texture_from_png(resources, SCREENSHOT_PNG_NAME, TextureFormat::R8);
|
||||||
ZOOM_OUT_PNG_NAME,
|
|
||||||
TextureFormat::R8);
|
|
||||||
let background_texture = device.create_texture_from_png(resources,
|
|
||||||
BACKGROUND_PNG_NAME,
|
|
||||||
TextureFormat::R8);
|
|
||||||
let screenshot_texture = device.create_texture_from_png(resources,
|
|
||||||
SCREENSHOT_PNG_NAME,
|
|
||||||
TextureFormat::R8);
|
|
||||||
|
|
||||||
device.end_commands();
|
device.end_commands();
|
||||||
|
|
||||||
|
@ -162,14 +175,17 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<W>(&mut self,
|
pub fn update<W>(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
window: &mut W,
|
window: &mut W,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
model: &mut DemoUIModel)
|
model: &mut DemoUIModel,
|
||||||
where W: Window {
|
) where
|
||||||
|
W: Window,
|
||||||
|
{
|
||||||
// Draw message text.
|
// Draw message text.
|
||||||
|
|
||||||
self.draw_message_text(device, allocator, debug_ui_presenter, model);
|
self.draw_message_text(device, allocator, debug_ui_presenter, model);
|
||||||
|
@ -182,34 +198,50 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
let button_size = vec2i(BUTTON_WIDTH, BUTTON_HEIGHT);
|
let button_size = vec2i(BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||||
|
|
||||||
// Draw effects button.
|
// Draw effects button.
|
||||||
if debug_ui_presenter.ui_presenter
|
if debug_ui_presenter.ui_presenter.draw_button(
|
||||||
.draw_button(device, allocator, position, &self.effects_texture) {
|
device,
|
||||||
|
allocator,
|
||||||
|
position,
|
||||||
|
&self.effects_texture,
|
||||||
|
) {
|
||||||
self.effects_panel_visible = !self.effects_panel_visible;
|
self.effects_panel_visible = !self.effects_panel_visible;
|
||||||
}
|
}
|
||||||
if !self.effects_panel_visible {
|
if !self.effects_panel_visible {
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(device,
|
debug_ui_presenter.ui_presenter.draw_tooltip(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
"Effects",
|
"Effects",
|
||||||
RectI::new(position, button_size));
|
RectI::new(position, button_size),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
position += vec2i(button_size.x() + PADDING, 0);
|
position += vec2i(button_size.x() + PADDING, 0);
|
||||||
|
|
||||||
// Draw open button.
|
// Draw open button.
|
||||||
if debug_ui_presenter.ui_presenter
|
if debug_ui_presenter.ui_presenter.draw_button(
|
||||||
.draw_button(device, allocator, position, &self.open_texture) {
|
device,
|
||||||
|
allocator,
|
||||||
|
position,
|
||||||
|
&self.open_texture,
|
||||||
|
) {
|
||||||
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
|
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
|
||||||
// the contents of the file.
|
// the contents of the file.
|
||||||
window.present_open_svg_dialog();
|
window.present_open_svg_dialog();
|
||||||
}
|
}
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(device,
|
debug_ui_presenter.ui_presenter.draw_tooltip(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
"Open SVG",
|
"Open SVG",
|
||||||
RectI::new(position, button_size));
|
RectI::new(position, button_size),
|
||||||
|
);
|
||||||
position += vec2i(BUTTON_WIDTH + PADDING, 0);
|
position += vec2i(BUTTON_WIDTH + PADDING, 0);
|
||||||
|
|
||||||
// Draw screenshot button.
|
// Draw screenshot button.
|
||||||
if debug_ui_presenter.ui_presenter
|
if debug_ui_presenter.ui_presenter.draw_button(
|
||||||
.draw_button(device, allocator, position, &self.screenshot_texture) {
|
device,
|
||||||
|
allocator,
|
||||||
|
position,
|
||||||
|
&self.screenshot_texture,
|
||||||
|
) {
|
||||||
self.screenshot_panel_visible = !self.screenshot_panel_visible;
|
self.screenshot_panel_visible = !self.screenshot_panel_visible;
|
||||||
}
|
}
|
||||||
if !self.screenshot_panel_visible {
|
if !self.screenshot_panel_visible {
|
||||||
|
@ -222,20 +254,24 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw screenshot panel, if necessary.
|
// Draw screenshot panel, if necessary.
|
||||||
self.draw_screenshot_panel(device,
|
self.draw_screenshot_panel(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
window,
|
window,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
position.x(),
|
position.x(),
|
||||||
action);
|
action,
|
||||||
|
);
|
||||||
position += vec2i(button_size.x() + PADDING, 0);
|
position += vec2i(button_size.x() + PADDING, 0);
|
||||||
|
|
||||||
// Draw mode switch.
|
// Draw mode switch.
|
||||||
let new_mode = debug_ui_presenter.ui_presenter.draw_text_switch(device,
|
let new_mode = debug_ui_presenter.ui_presenter.draw_text_switch(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
position,
|
position,
|
||||||
&["2D", "3D", "VR"],
|
&["2D", "3D", "VR"],
|
||||||
model.mode as u8);
|
model.mode as u8,
|
||||||
|
);
|
||||||
if new_mode != model.mode as u8 {
|
if new_mode != model.mode as u8 {
|
||||||
model.mode = match new_mode {
|
model.mode = match new_mode {
|
||||||
0 => Mode::TwoD,
|
0 => Mode::TwoD,
|
||||||
|
@ -256,10 +292,12 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
position += vec2i(mode_switch_width + PADDING, 0);
|
position += vec2i(mode_switch_width + PADDING, 0);
|
||||||
|
|
||||||
// Draw background switch.
|
// Draw background switch.
|
||||||
if debug_ui_presenter.ui_presenter.draw_button(device,
|
if debug_ui_presenter.ui_presenter.draw_button(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
position,
|
position,
|
||||||
&self.background_texture) {
|
&self.background_texture,
|
||||||
|
) {
|
||||||
self.background_panel_visible = !self.background_panel_visible;
|
self.background_panel_visible = !self.background_panel_visible;
|
||||||
}
|
}
|
||||||
if !self.background_panel_visible {
|
if !self.background_panel_visible {
|
||||||
|
@ -272,12 +310,14 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw background panel, if necessary.
|
// Draw background panel, if necessary.
|
||||||
self.draw_background_panel(device,
|
self.draw_background_panel(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
position.x(),
|
position.x(),
|
||||||
action,
|
action,
|
||||||
model);
|
model,
|
||||||
|
);
|
||||||
position += vec2i(button_size.x() + PADDING, 0);
|
position += vec2i(button_size.x() + PADDING, 0);
|
||||||
|
|
||||||
// Draw effects panel, if necessary.
|
// Draw effects panel, if necessary.
|
||||||
|
@ -288,49 +328,65 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug_ui_presenter.ui_presenter.draw_button(device,
|
if debug_ui_presenter.ui_presenter.draw_button(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
position,
|
position,
|
||||||
&self.rotate_texture) {
|
&self.rotate_texture,
|
||||||
|
) {
|
||||||
self.rotate_panel_visible = !self.rotate_panel_visible;
|
self.rotate_panel_visible = !self.rotate_panel_visible;
|
||||||
}
|
}
|
||||||
if !self.rotate_panel_visible {
|
if !self.rotate_panel_visible {
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(device,
|
debug_ui_presenter.ui_presenter.draw_tooltip(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
"Rotate",
|
"Rotate",
|
||||||
RectI::new(position, button_size));
|
RectI::new(position, button_size),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
self.draw_rotate_panel(device, allocator, debug_ui_presenter, position.x(), action, model);
|
self.draw_rotate_panel(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
debug_ui_presenter,
|
||||||
|
position.x(),
|
||||||
|
action,
|
||||||
|
model,
|
||||||
|
);
|
||||||
position += vec2i(BUTTON_WIDTH + PADDING, 0);
|
position += vec2i(BUTTON_WIDTH + PADDING, 0);
|
||||||
|
|
||||||
// Draw zoom control.
|
// Draw zoom control.
|
||||||
self.draw_zoom_control(device, allocator, debug_ui_presenter, position, action);
|
self.draw_zoom_control(device, allocator, debug_ui_presenter, position, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_zoom_control(&mut self,
|
fn draw_zoom_control(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
position: Vector2I,
|
position: Vector2I,
|
||||||
action: &mut UIAction) {
|
action: &mut UIAction,
|
||||||
|
) {
|
||||||
let zoom_segmented_control_width =
|
let zoom_segmented_control_width =
|
||||||
debug_ui_presenter.ui_presenter.measure_segmented_control(3);
|
debug_ui_presenter.ui_presenter.measure_segmented_control(3);
|
||||||
let zoom_segmented_control_rect =
|
let zoom_segmented_control_rect =
|
||||||
RectI::new(position, vec2i(zoom_segmented_control_width, BUTTON_HEIGHT));
|
RectI::new(position, vec2i(zoom_segmented_control_width, BUTTON_HEIGHT));
|
||||||
debug_ui_presenter.ui_presenter
|
debug_ui_presenter.ui_presenter.draw_tooltip(
|
||||||
.draw_tooltip(device, allocator, "Zoom", zoom_segmented_control_rect);
|
device,
|
||||||
|
allocator,
|
||||||
|
"Zoom",
|
||||||
|
zoom_segmented_control_rect,
|
||||||
|
);
|
||||||
|
|
||||||
let zoom_textures = &[
|
let zoom_textures = &[
|
||||||
&self.zoom_in_texture,
|
&self.zoom_in_texture,
|
||||||
&self.zoom_actual_size_texture,
|
&self.zoom_actual_size_texture,
|
||||||
&self.zoom_out_texture
|
&self.zoom_out_texture,
|
||||||
];
|
];
|
||||||
|
|
||||||
match debug_ui_presenter.ui_presenter.draw_image_segmented_control(device,
|
match debug_ui_presenter
|
||||||
allocator,
|
.ui_presenter
|
||||||
position,
|
.draw_image_segmented_control(device, allocator, position, zoom_textures, None)
|
||||||
zoom_textures,
|
{
|
||||||
None) {
|
|
||||||
Some(0) => *action = UIAction::ZoomIn,
|
Some(0) => *action = UIAction::ZoomIn,
|
||||||
Some(1) => *action = UIAction::ZoomActualSize,
|
Some(1) => *action = UIAction::ZoomActualSize,
|
||||||
Some(2) => *action = UIAction::ZoomOut,
|
Some(2) => *action = UIAction::ZoomOut,
|
||||||
|
@ -338,11 +394,13 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_message_text(&mut self,
|
fn draw_message_text(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
model: &mut DemoUIModel) {
|
model: &mut DemoUIModel,
|
||||||
|
) {
|
||||||
if model.message.is_empty() {
|
if model.message.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -365,12 +423,14 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_effects_panel(&mut self,
|
fn draw_effects_panel(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
model: &mut DemoUIModel,
|
model: &mut DemoUIModel,
|
||||||
action: &mut UIAction) {
|
action: &mut UIAction,
|
||||||
|
) {
|
||||||
if !self.effects_panel_visible {
|
if !self.effects_panel_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -380,44 +440,56 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
RectI::new(vec2i(PADDING, effects_panel_y),
|
RectI::new(
|
||||||
vec2i(EFFECTS_PANEL_WIDTH, EFFECTS_PANEL_HEIGHT)),
|
vec2i(PADDING, effects_panel_y),
|
||||||
WINDOW_COLOR);
|
vec2i(EFFECTS_PANEL_WIDTH, EFFECTS_PANEL_HEIGHT),
|
||||||
|
),
|
||||||
|
WINDOW_COLOR,
|
||||||
|
);
|
||||||
|
|
||||||
self.draw_effects_switch(device,
|
self.draw_effects_switch(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
action,
|
action,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
"Gamma Correction",
|
"Gamma Correction",
|
||||||
0,
|
0,
|
||||||
effects_panel_y,
|
effects_panel_y,
|
||||||
&mut model.gamma_correction_effect_enabled);
|
&mut model.gamma_correction_effect_enabled,
|
||||||
self.draw_effects_switch(device,
|
);
|
||||||
|
self.draw_effects_switch(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
action,
|
action,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
"Stem Darkening",
|
"Stem Darkening",
|
||||||
1,
|
1,
|
||||||
effects_panel_y,
|
effects_panel_y,
|
||||||
&mut model.stem_darkening_effect_enabled);
|
&mut model.stem_darkening_effect_enabled,
|
||||||
self.draw_effects_switch(device,
|
);
|
||||||
|
self.draw_effects_switch(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
action,
|
action,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
"Subpixel AA",
|
"Subpixel AA",
|
||||||
2,
|
2,
|
||||||
effects_panel_y,
|
effects_panel_y,
|
||||||
&mut model.subpixel_aa_effect_enabled);
|
&mut model.subpixel_aa_effect_enabled,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_screenshot_panel<W>(&mut self,
|
fn draw_screenshot_panel<W>(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
window: &mut W,
|
window: &mut W,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
panel_x: i32,
|
panel_x: i32,
|
||||||
action: &mut UIAction)
|
action: &mut UIAction,
|
||||||
where W: Window {
|
) where
|
||||||
|
W: Window,
|
||||||
|
{
|
||||||
if !self.screenshot_panel_visible {
|
if !self.screenshot_panel_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -428,33 +500,42 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
RectI::new(panel_position, vec2i(SCREENSHOT_PANEL_WIDTH, SCREENSHOT_PANEL_HEIGHT)),
|
RectI::new(
|
||||||
|
panel_position,
|
||||||
|
vec2i(SCREENSHOT_PANEL_WIDTH, SCREENSHOT_PANEL_HEIGHT),
|
||||||
|
),
|
||||||
WINDOW_COLOR,
|
WINDOW_COLOR,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.draw_screenshot_menu_item(device,
|
self.draw_screenshot_menu_item(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
window,
|
window,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
ScreenshotType::PNG,
|
ScreenshotType::PNG,
|
||||||
panel_position,
|
panel_position,
|
||||||
action);
|
action,
|
||||||
self.draw_screenshot_menu_item(device,
|
);
|
||||||
|
self.draw_screenshot_menu_item(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
window,
|
window,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
ScreenshotType::SVG,
|
ScreenshotType::SVG,
|
||||||
panel_position,
|
panel_position,
|
||||||
action);
|
action,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_background_panel(&mut self,
|
fn draw_background_panel(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
panel_x: i32,
|
panel_x: i32,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
model: &mut DemoUIModel) {
|
model: &mut DemoUIModel,
|
||||||
|
) {
|
||||||
if !self.background_panel_visible {
|
if !self.background_panel_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -465,40 +546,51 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
RectI::new(panel_position, vec2i(BACKGROUND_PANEL_WIDTH, BACKGROUND_PANEL_HEIGHT)),
|
RectI::new(
|
||||||
|
panel_position,
|
||||||
|
vec2i(BACKGROUND_PANEL_WIDTH, BACKGROUND_PANEL_HEIGHT),
|
||||||
|
),
|
||||||
WINDOW_COLOR,
|
WINDOW_COLOR,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.draw_background_menu_item(device,
|
self.draw_background_menu_item(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
BackgroundColor::Light,
|
BackgroundColor::Light,
|
||||||
panel_position,
|
panel_position,
|
||||||
action,
|
action,
|
||||||
model);
|
model,
|
||||||
self.draw_background_menu_item(device,
|
);
|
||||||
|
self.draw_background_menu_item(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
BackgroundColor::Dark,
|
BackgroundColor::Dark,
|
||||||
panel_position,
|
panel_position,
|
||||||
action,
|
action,
|
||||||
model);
|
model,
|
||||||
self.draw_background_menu_item(device,
|
);
|
||||||
|
self.draw_background_menu_item(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
BackgroundColor::Transparent,
|
BackgroundColor::Transparent,
|
||||||
panel_position,
|
panel_position,
|
||||||
action,
|
action,
|
||||||
model);
|
model,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_rotate_panel(&mut self,
|
fn draw_rotate_panel(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
rotate_panel_x: i32,
|
rotate_panel_x: i32,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
model: &mut DemoUIModel) {
|
model: &mut DemoUIModel,
|
||||||
|
) {
|
||||||
if !self.rotate_panel_visible {
|
if !self.rotate_panel_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -511,42 +603,61 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
RectI::new(rotate_panel_origin, rotate_panel_size),
|
RectI::new(rotate_panel_origin, rotate_panel_size),
|
||||||
WINDOW_COLOR);
|
WINDOW_COLOR,
|
||||||
|
);
|
||||||
|
|
||||||
let (widget_x, widget_y) = (rotate_panel_x + PADDING, rotate_panel_y + PADDING);
|
let (widget_x, widget_y) = (rotate_panel_x + PADDING, rotate_panel_y + PADDING);
|
||||||
let widget_rect = RectI::new(vec2i(widget_x, widget_y),
|
let widget_rect = RectI::new(
|
||||||
vec2i(SLIDER_WIDTH, SLIDER_KNOB_HEIGHT));
|
vec2i(widget_x, widget_y),
|
||||||
|
vec2i(SLIDER_WIDTH, SLIDER_KNOB_HEIGHT),
|
||||||
|
);
|
||||||
if let Some(position) = debug_ui_presenter
|
if let Some(position) = debug_ui_presenter
|
||||||
.ui_presenter
|
.ui_presenter
|
||||||
.event_queue
|
.event_queue
|
||||||
.handle_mouse_down_or_dragged_in_rect(widget_rect) {
|
.handle_mouse_down_or_dragged_in_rect(widget_rect)
|
||||||
|
{
|
||||||
model.rotation = position.x();
|
model.rotation = position.x();
|
||||||
*action = UIAction::Rotate(model.rotation());
|
*action = UIAction::Rotate(model.rotation());
|
||||||
}
|
}
|
||||||
|
|
||||||
let slider_track_y =
|
let slider_track_y =
|
||||||
rotate_panel_y + PADDING + SLIDER_KNOB_HEIGHT / 2 - SLIDER_TRACK_HEIGHT / 2;
|
rotate_panel_y + PADDING + SLIDER_KNOB_HEIGHT / 2 - SLIDER_TRACK_HEIGHT / 2;
|
||||||
let slider_track_rect = RectI::new(vec2i(widget_x, slider_track_y),
|
let slider_track_rect = RectI::new(
|
||||||
vec2i(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT));
|
vec2i(widget_x, slider_track_y),
|
||||||
debug_ui_presenter.ui_presenter
|
vec2i(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT),
|
||||||
.draw_rect_outline(device, allocator, slider_track_rect, TEXT_COLOR);
|
);
|
||||||
|
debug_ui_presenter.ui_presenter.draw_rect_outline(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
slider_track_rect,
|
||||||
|
TEXT_COLOR,
|
||||||
|
);
|
||||||
|
|
||||||
let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2;
|
let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2;
|
||||||
let slider_knob_rect = RectI::new(vec2i(slider_knob_x, widget_y),
|
let slider_knob_rect = RectI::new(
|
||||||
vec2i(SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT));
|
vec2i(slider_knob_x, widget_y),
|
||||||
debug_ui_presenter.ui_presenter
|
vec2i(SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT),
|
||||||
.draw_solid_rect(device, allocator, slider_knob_rect, TEXT_COLOR);
|
);
|
||||||
|
debug_ui_presenter.ui_presenter.draw_solid_rect(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
slider_knob_rect,
|
||||||
|
TEXT_COLOR,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_screenshot_menu_item<W>(&mut self,
|
fn draw_screenshot_menu_item<W>(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
window: &mut W,
|
window: &mut W,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
screenshot_type: ScreenshotType,
|
screenshot_type: ScreenshotType,
|
||||||
panel_position: Vector2I,
|
panel_position: Vector2I,
|
||||||
action: &mut UIAction)
|
action: &mut UIAction,
|
||||||
where W: Window {
|
) where
|
||||||
|
W: Window,
|
||||||
|
{
|
||||||
let index = screenshot_type as i32;
|
let index = screenshot_type as i32;
|
||||||
let text = format!("Save as {}...", screenshot_type.as_str());
|
let text = format!("Save as {}...", screenshot_type.as_str());
|
||||||
|
|
||||||
|
@ -554,29 +665,36 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
let widget_origin = panel_position + vec2i(0, widget_size.y() * index);
|
let widget_origin = panel_position + vec2i(0, widget_size.y() * index);
|
||||||
let widget_rect = RectI::new(widget_origin, widget_size);
|
let widget_rect = RectI::new(widget_origin, widget_size);
|
||||||
|
|
||||||
if self.draw_menu_item(device,
|
if self.draw_menu_item(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
&text,
|
&text,
|
||||||
widget_rect,
|
widget_rect,
|
||||||
false) {
|
false,
|
||||||
|
) {
|
||||||
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
|
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
|
||||||
// the contents of the file.
|
// the contents of the file.
|
||||||
if let Ok(path) = window.run_save_dialog(screenshot_type.extension()) {
|
if let Ok(path) = window.run_save_dialog(screenshot_type.extension()) {
|
||||||
self.screenshot_panel_visible = false;
|
self.screenshot_panel_visible = false;
|
||||||
*action = UIAction::TakeScreenshot(ScreenshotInfo { kind: screenshot_type, path });
|
*action = UIAction::TakeScreenshot(ScreenshotInfo {
|
||||||
|
kind: screenshot_type,
|
||||||
|
path,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_background_menu_item(&mut self,
|
fn draw_background_menu_item(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
color: BackgroundColor,
|
color: BackgroundColor,
|
||||||
panel_position: Vector2I,
|
panel_position: Vector2I,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
model: &mut DemoUIModel) {
|
model: &mut DemoUIModel,
|
||||||
|
) {
|
||||||
let (text, index) = (color.as_str(), color as i32);
|
let (text, index) = (color.as_str(), color as i32);
|
||||||
|
|
||||||
let widget_size = vec2i(BACKGROUND_PANEL_WIDTH, BUTTON_HEIGHT);
|
let widget_size = vec2i(BACKGROUND_PANEL_WIDTH, BUTTON_HEIGHT);
|
||||||
|
@ -584,42 +702,52 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
let widget_rect = RectI::new(widget_origin, widget_size);
|
let widget_rect = RectI::new(widget_origin, widget_size);
|
||||||
|
|
||||||
let selected = color == model.background_color;
|
let selected = color == model.background_color;
|
||||||
if self.draw_menu_item(device,
|
if self.draw_menu_item(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
text,
|
text,
|
||||||
widget_rect,
|
widget_rect,
|
||||||
selected) {
|
selected,
|
||||||
|
) {
|
||||||
model.background_color = color;
|
model.background_color = color;
|
||||||
*action = UIAction::ModelChanged;
|
*action = UIAction::ModelChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_menu_item(&self,
|
fn draw_menu_item(
|
||||||
|
&self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
text: &str,
|
text: &str,
|
||||||
widget_rect: RectI,
|
widget_rect: RectI,
|
||||||
selected: bool)
|
selected: bool,
|
||||||
-> bool {
|
) -> bool {
|
||||||
if selected {
|
if selected {
|
||||||
debug_ui_presenter.ui_presenter
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
.draw_solid_rounded_rect(device, allocator, widget_rect, TEXT_COLOR);
|
device,
|
||||||
|
allocator,
|
||||||
|
widget_rect,
|
||||||
|
TEXT_COLOR,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (text_x, text_y) = (PADDING * 2, BUTTON_TEXT_OFFSET);
|
let (text_x, text_y) = (PADDING * 2, BUTTON_TEXT_OFFSET);
|
||||||
let text_position = widget_rect.origin() + vec2i(text_x, text_y);
|
let text_position = widget_rect.origin() + vec2i(text_x, text_y);
|
||||||
debug_ui_presenter.ui_presenter
|
debug_ui_presenter
|
||||||
|
.ui_presenter
|
||||||
.draw_text(device, allocator, text, text_position, selected);
|
.draw_text(device, allocator, text, text_position, selected);
|
||||||
|
|
||||||
debug_ui_presenter.ui_presenter
|
debug_ui_presenter
|
||||||
|
.ui_presenter
|
||||||
.event_queue
|
.event_queue
|
||||||
.handle_mouse_down_in_rect(widget_rect)
|
.handle_mouse_down_in_rect(widget_rect)
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_effects_switch(&self,
|
fn draw_effects_switch(
|
||||||
|
&self,
|
||||||
device: &D,
|
device: &D,
|
||||||
allocator: &mut GPUMemoryAllocator<D>,
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
|
@ -627,23 +755,30 @@ impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
text: &str,
|
text: &str,
|
||||||
index: i32,
|
index: i32,
|
||||||
window_y: i32,
|
window_y: i32,
|
||||||
value: &mut bool) {
|
value: &mut bool,
|
||||||
|
) {
|
||||||
let text_x = PADDING * 2;
|
let text_x = PADDING * 2;
|
||||||
let text_y = window_y + PADDING + BUTTON_TEXT_OFFSET + (BUTTON_HEIGHT + PADDING) * index;
|
let text_y = window_y + PADDING + BUTTON_TEXT_OFFSET + (BUTTON_HEIGHT + PADDING) * index;
|
||||||
debug_ui_presenter.ui_presenter
|
debug_ui_presenter.ui_presenter.draw_text(
|
||||||
.draw_text(device, allocator, text, vec2i(text_x, text_y), false);
|
device,
|
||||||
|
allocator,
|
||||||
|
text,
|
||||||
|
vec2i(text_x, text_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
let switch_width = debug_ui_presenter.ui_presenter.measure_segmented_control(2);
|
let switch_width = debug_ui_presenter.ui_presenter.measure_segmented_control(2);
|
||||||
let switch_x = PADDING + EFFECTS_PANEL_WIDTH - (switch_width + PADDING);
|
let switch_x = PADDING + EFFECTS_PANEL_WIDTH - (switch_width + PADDING);
|
||||||
let switch_y = window_y + PADDING + (BUTTON_HEIGHT + PADDING) * index;
|
let switch_y = window_y + PADDING + (BUTTON_HEIGHT + PADDING) * index;
|
||||||
let switch_position = vec2i(switch_x, switch_y);
|
let switch_position = vec2i(switch_x, switch_y);
|
||||||
|
|
||||||
let new_value = debug_ui_presenter.ui_presenter
|
let new_value = debug_ui_presenter.ui_presenter.draw_text_switch(
|
||||||
.draw_text_switch(device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
switch_position,
|
switch_position,
|
||||||
&["Off", "On"],
|
&["Off", "On"],
|
||||||
*value as u8) != 0;
|
*value as u8,
|
||||||
|
) != 0;
|
||||||
|
|
||||||
if new_value != *value {
|
if new_value != *value {
|
||||||
*action = UIAction::EffectsChanged;
|
*action = UIAction::EffectsChanged;
|
||||||
|
|
|
@ -33,7 +33,9 @@ pub trait Window {
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
fn gl_version(&self) -> GLVersion;
|
fn gl_version(&self) -> GLVersion;
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
fn gl_default_framebuffer(&self) -> GLuint { 0 }
|
fn gl_default_framebuffer(&self) -> GLuint {
|
||||||
|
0
|
||||||
|
}
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
fn present(&mut self, device: &mut GLDevice);
|
fn present(&mut self, device: &mut GLDevice);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ authors = ["Alan Jeffrey <ajeffrey@mozilla.com>"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gl = "0.14"
|
gl = "0.14"
|
||||||
rayon = "1.0"
|
rayon = "1.0"
|
||||||
usvg = "0.9"
|
usvg = "0.10"
|
||||||
egl = "0.2"
|
egl = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
smallvec = "1.2"
|
smallvec = "1.2"
|
||||||
|
|
|
@ -263,27 +263,51 @@ impl MLResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for MLResult {
|
impl Error for MLResult {}
|
||||||
}
|
|
||||||
|
|
||||||
// Functions from the MagicLeap C API
|
// Functions from the MagicLeap C API
|
||||||
|
|
||||||
#[cfg(not(feature = "mocked"))]
|
#[cfg(not(feature = "mocked"))]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn MLGraphicsCreateClientGL(options: *const MLGraphicsOptions, gl_context: MLHandle, graphics_client : &mut MLHandle) -> MLResult;
|
pub fn MLGraphicsCreateClientGL(
|
||||||
|
options: *const MLGraphicsOptions,
|
||||||
|
gl_context: MLHandle,
|
||||||
|
graphics_client: &mut MLHandle,
|
||||||
|
) -> MLResult;
|
||||||
pub fn MLGraphicsDestroyClient(graphics_client: *mut MLHandle) -> MLResult;
|
pub fn MLGraphicsDestroyClient(graphics_client: *mut MLHandle) -> MLResult;
|
||||||
pub fn MLHeadTrackingCreate(tracker: *mut MLHandle) -> MLResult;
|
pub fn MLHeadTrackingCreate(tracker: *mut MLHandle) -> MLResult;
|
||||||
pub fn MLHeadTrackingGetStaticData(head_tracker: MLHandle, data: *mut MLHeadTrackingStaticData) -> MLResult;
|
pub fn MLHeadTrackingGetStaticData(
|
||||||
|
head_tracker: MLHandle,
|
||||||
|
data: *mut MLHeadTrackingStaticData,
|
||||||
|
) -> MLResult;
|
||||||
pub fn MLPerceptionGetSnapshot(snapshot: *mut MLSnapshotPtr) -> MLResult;
|
pub fn MLPerceptionGetSnapshot(snapshot: *mut MLSnapshotPtr) -> MLResult;
|
||||||
pub fn MLSnapshotGetTransform(snapshot: MLSnapshotPtr, id: *const MLCoordinateFrameUID, transform: *mut MLTransform) -> MLResult;
|
pub fn MLSnapshotGetTransform(
|
||||||
|
snapshot: MLSnapshotPtr,
|
||||||
|
id: *const MLCoordinateFrameUID,
|
||||||
|
transform: *mut MLTransform,
|
||||||
|
) -> MLResult;
|
||||||
pub fn MLPerceptionReleaseSnapshot(snapshot: MLSnapshotPtr) -> MLResult;
|
pub fn MLPerceptionReleaseSnapshot(snapshot: MLSnapshotPtr) -> MLResult;
|
||||||
pub fn MLLifecycleSetReadyIndication() -> MLResult;
|
pub fn MLLifecycleSetReadyIndication() -> MLResult;
|
||||||
pub fn MLGraphicsGetClipExtents(graphics_client: MLHandle, array: *mut MLGraphicsClipExtentsInfoArray) -> MLResult;
|
pub fn MLGraphicsGetClipExtents(
|
||||||
pub fn MLGraphicsGetRenderTargets(graphics_client: MLHandle, targets: *mut MLGraphicsRenderTargetsInfo) -> MLResult;
|
graphics_client: MLHandle,
|
||||||
|
array: *mut MLGraphicsClipExtentsInfoArray,
|
||||||
|
) -> MLResult;
|
||||||
|
pub fn MLGraphicsGetRenderTargets(
|
||||||
|
graphics_client: MLHandle,
|
||||||
|
targets: *mut MLGraphicsRenderTargetsInfo,
|
||||||
|
) -> MLResult;
|
||||||
pub fn MLGraphicsInitFrameParams(params: *mut MLGraphicsFrameParams) -> MLResult;
|
pub fn MLGraphicsInitFrameParams(params: *mut MLGraphicsFrameParams) -> MLResult;
|
||||||
pub fn MLGraphicsBeginFrame(graphics_client: MLHandle, params: *const MLGraphicsFrameParams, frame_handle: *mut MLHandle, virtual_camera_array: *mut MLGraphicsVirtualCameraInfoArray) -> MLResult;
|
pub fn MLGraphicsBeginFrame(
|
||||||
|
graphics_client: MLHandle,
|
||||||
|
params: *const MLGraphicsFrameParams,
|
||||||
|
frame_handle: *mut MLHandle,
|
||||||
|
virtual_camera_array: *mut MLGraphicsVirtualCameraInfoArray,
|
||||||
|
) -> MLResult;
|
||||||
pub fn MLGraphicsEndFrame(graphics_client: MLHandle, frame_handle: MLHandle) -> MLResult;
|
pub fn MLGraphicsEndFrame(graphics_client: MLHandle, frame_handle: MLHandle) -> MLResult;
|
||||||
pub fn MLGraphicsSignalSyncObjectGL(graphics_client: MLHandle, sync_object: MLHandle) -> MLResult;
|
pub fn MLGraphicsSignalSyncObjectGL(
|
||||||
|
graphics_client: MLHandle,
|
||||||
|
sync_object: MLHandle,
|
||||||
|
) -> MLResult;
|
||||||
pub fn MLGetResultString(result_code: MLResult) -> *const c_char;
|
pub fn MLGetResultString(result_code: MLResult) -> *const c_char;
|
||||||
pub fn MLLoggingLogLevelIsEnabled(lvl: MLLogLevel) -> bool;
|
pub fn MLLoggingLogLevelIsEnabled(lvl: MLLogLevel) -> bool;
|
||||||
pub fn MLLoggingLog(lvl: MLLogLevel, tag: *const c_char, message: *const c_char);
|
pub fn MLLoggingLog(lvl: MLLogLevel, tag: *const c_char, message: *const c_char);
|
||||||
|
|
|
@ -22,31 +22,31 @@ use gl::types::GLuint;
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use pathfinder_demo::DemoApp;
|
use pathfinder_color::ColorF;
|
||||||
use pathfinder_demo::Options;
|
|
||||||
use pathfinder_demo::UIVisibility;
|
|
||||||
use pathfinder_demo::BackgroundColor;
|
|
||||||
use pathfinder_demo::Mode;
|
|
||||||
use pathfinder_demo::window::Event;
|
use pathfinder_demo::window::Event;
|
||||||
use pathfinder_demo::window::SVGPath;
|
use pathfinder_demo::window::SVGPath;
|
||||||
|
use pathfinder_demo::BackgroundColor;
|
||||||
|
use pathfinder_demo::DemoApp;
|
||||||
|
use pathfinder_demo::Mode;
|
||||||
|
use pathfinder_demo::Options;
|
||||||
|
use pathfinder_demo::UIVisibility;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
|
use pathfinder_geometry::vector::vec2i;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_geometry::vector::vec2i;
|
|
||||||
use pathfinder_color::ColorF;
|
|
||||||
use pathfinder_gl::GLDevice;
|
use pathfinder_gl::GLDevice;
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
use pathfinder_gpu::ClearParams;
|
use pathfinder_gpu::ClearParams;
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::Device;
|
||||||
use pathfinder_renderer::concurrent::executor::SequentialExecutor;
|
use pathfinder_renderer::concurrent::executor::SequentialExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
|
||||||
use pathfinder_renderer::gpu::renderer::DestFramebuffer;
|
use pathfinder_renderer::gpu::renderer::DestFramebuffer;
|
||||||
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::RenderOptions;
|
use pathfinder_renderer::options::RenderOptions;
|
||||||
use pathfinder_renderer::options::RenderTransform;
|
use pathfinder_renderer::options::RenderTransform;
|
||||||
use pathfinder_resources::ResourceLoader;
|
|
||||||
use pathfinder_resources::fs::FilesystemResourceLoader;
|
use pathfinder_resources::fs::FilesystemResourceLoader;
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use pathfinder_svg::SVGScene;
|
use pathfinder_svg::SVGScene;
|
||||||
|
|
||||||
|
@ -72,10 +72,17 @@ struct ImmersiveApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn magicleap_pathfinder_demo_init(egl_display: EGLDisplay, egl_context: EGLContext) -> *mut c_void {
|
pub extern "C" fn magicleap_pathfinder_demo_init(
|
||||||
unsafe { c_api::MLLoggingLog(c_api::MLLogLevel::Info,
|
egl_display: EGLDisplay,
|
||||||
|
egl_context: EGLContext,
|
||||||
|
) -> *mut c_void {
|
||||||
|
unsafe {
|
||||||
|
c_api::MLLoggingLog(
|
||||||
|
c_api::MLLogLevel::Info,
|
||||||
b"Pathfinder Demo\0".as_ptr() as *const _,
|
b"Pathfinder Demo\0".as_ptr() as *const _,
|
||||||
b"Initializing\0".as_ptr() as *const _) };
|
b"Initializing\0".as_ptr() as *const _,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let tag = CString::new("Pathfinder Demo").unwrap();
|
let tag = CString::new("Pathfinder Demo").unwrap();
|
||||||
let level = log::LevelFilter::Warn;
|
let level = log::LevelFilter::Warn;
|
||||||
|
@ -97,7 +104,11 @@ pub extern "C" fn magicleap_pathfinder_demo_init(egl_display: EGLDisplay, egl_co
|
||||||
info!("Initialized app");
|
info!("Initialized app");
|
||||||
|
|
||||||
let (sender, receiver) = flume::unbounded();
|
let (sender, receiver) = flume::unbounded();
|
||||||
Box::into_raw(Box::new(ImmersiveApp { sender, receiver, demo })) as *mut c_void
|
Box::into_raw(Box::new(ImmersiveApp {
|
||||||
|
sender,
|
||||||
|
receiver,
|
||||||
|
demo,
|
||||||
|
})) as *mut c_void
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -124,12 +135,17 @@ pub unsafe extern "C" fn magicleap_pathfinder_demo_run(app: *mut c_void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn magicleap_pathfinder_demo_load(app: *mut c_void, svg_filename: *const c_char) {
|
pub unsafe extern "C" fn magicleap_pathfinder_demo_load(
|
||||||
|
app: *mut c_void,
|
||||||
|
svg_filename: *const c_char,
|
||||||
|
) {
|
||||||
let app = app as *mut ImmersiveApp;
|
let app = app as *mut ImmersiveApp;
|
||||||
if let Some(app) = app.as_mut() {
|
if let Some(app) = app.as_mut() {
|
||||||
let svg_filename = CStr::from_ptr(svg_filename).to_string_lossy().into_owned();
|
let svg_filename = CStr::from_ptr(svg_filename).to_string_lossy().into_owned();
|
||||||
info!("Loading {}.", svg_filename);
|
info!("Loading {}.", svg_filename);
|
||||||
let _ = app.sender.send(Event::OpenSVG(SVGPath::Resource(svg_filename)));
|
let _ = app
|
||||||
|
.sender
|
||||||
|
.send(Event::OpenSVG(SVGPath::Resource(svg_filename)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,9 +166,13 @@ pub struct MagicLeapPathfinderRenderOptions {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn magicleap_pathfinder_init() -> *mut c_void {
|
pub extern "C" fn magicleap_pathfinder_init() -> *mut c_void {
|
||||||
unsafe { c_api::MLLoggingLog(c_api::MLLogLevel::Info,
|
unsafe {
|
||||||
|
c_api::MLLoggingLog(
|
||||||
|
c_api::MLLogLevel::Info,
|
||||||
b"Pathfinder Demo\0".as_ptr() as *const _,
|
b"Pathfinder Demo\0".as_ptr() as *const _,
|
||||||
b"Initializing\0".as_ptr() as *const _) };
|
b"Initializing\0".as_ptr() as *const _,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let tag = CString::new("Pathfinder Demo").unwrap();
|
let tag = CString::new("Pathfinder Demo").unwrap();
|
||||||
let level = log::LevelFilter::Info;
|
let level = log::LevelFilter::Info;
|
||||||
|
@ -175,12 +195,17 @@ pub extern "C" fn magicleap_pathfinder_init() -> *mut c_void {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn magicleap_pathfinder_render(pf: *mut c_void, options: *const MagicLeapPathfinderRenderOptions) {
|
pub unsafe extern "C" fn magicleap_pathfinder_render(
|
||||||
|
pf: *mut c_void,
|
||||||
|
options: *const MagicLeapPathfinderRenderOptions,
|
||||||
|
) {
|
||||||
let pf = pf as *mut MagicLeapPathfinder;
|
let pf = pf as *mut MagicLeapPathfinder;
|
||||||
if let (Some(pf), Some(options)) = (pf.as_mut(), options.as_ref()) {
|
if let (Some(pf), Some(options)) = (pf.as_mut(), options.as_ref()) {
|
||||||
let resources = &pf.resources;
|
let resources = &pf.resources;
|
||||||
|
|
||||||
let svg_filename = CStr::from_ptr(options.svg_filename).to_string_lossy().into_owned();
|
let svg_filename = CStr::from_ptr(options.svg_filename)
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
let svg = pf.svgs.entry(svg_filename).or_insert_with(|| {
|
let svg = pf.svgs.entry(svg_filename).or_insert_with(|| {
|
||||||
let svg_filename = CStr::from_ptr(options.svg_filename).to_string_lossy();
|
let svg_filename = CStr::from_ptr(options.svg_filename).to_string_lossy();
|
||||||
let data = resources.slurp(&*svg_filename).unwrap();
|
let data = resources.slurp(&*svg_filename).unwrap();
|
||||||
|
@ -191,35 +216,56 @@ pub unsafe extern "C" fn magicleap_pathfinder_render(pf: *mut c_void, options: *
|
||||||
let mut width = 0;
|
let mut width = 0;
|
||||||
let mut height = 0;
|
let mut height = 0;
|
||||||
egl::query_surface(options.display, options.surface, egl::EGL_WIDTH, &mut width);
|
egl::query_surface(options.display, options.surface, egl::EGL_WIDTH, &mut width);
|
||||||
egl::query_surface(options.display, options.surface, egl::EGL_HEIGHT, &mut height);
|
egl::query_surface(
|
||||||
|
options.display,
|
||||||
|
options.surface,
|
||||||
|
egl::EGL_HEIGHT,
|
||||||
|
&mut height,
|
||||||
|
);
|
||||||
let size = vec2i(width, height);
|
let size = vec2i(width, height);
|
||||||
|
|
||||||
let viewport_origin = vec2i(options.viewport[0] as i32, options.viewport[1] as i32);
|
let viewport_origin = vec2i(options.viewport[0] as i32, options.viewport[1] as i32);
|
||||||
let viewport_size = vec2i(options.viewport[2] as i32, options.viewport[3] as i32);
|
let viewport_size = vec2i(options.viewport[2] as i32, options.viewport[3] as i32);
|
||||||
let viewport = RectI::new(viewport_origin, viewport_size);
|
let viewport = RectI::new(viewport_origin, viewport_size);
|
||||||
|
|
||||||
let bg_color = ColorF(F32x4::new(options.bg_color[0], options.bg_color[1], options.bg_color[2], options.bg_color[3]));
|
let bg_color = ColorF(F32x4::new(
|
||||||
|
options.bg_color[0],
|
||||||
|
options.bg_color[1],
|
||||||
|
options.bg_color[2],
|
||||||
|
options.bg_color[3],
|
||||||
|
));
|
||||||
|
|
||||||
let renderer = pf.renderers.entry((options.display, options.surface)).or_insert_with(|| {
|
let renderer = pf
|
||||||
|
.renderers
|
||||||
|
.entry((options.display, options.surface))
|
||||||
|
.or_insert_with(|| {
|
||||||
let mut fbo = 0;
|
let mut fbo = 0;
|
||||||
gl::GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut fbo);
|
gl::GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut fbo);
|
||||||
let device = GLDevice::new(GLVersion::GLES3, fbo as GLuint);
|
let device = GLDevice::new(GLVersion::GLES3, fbo as GLuint);
|
||||||
let dest_framebuffer = DestFramebuffer::Default { viewport, window_size: size };
|
let dest_framebuffer = DestFramebuffer::Default {
|
||||||
|
viewport,
|
||||||
|
window_size: size,
|
||||||
|
};
|
||||||
Renderer::new(device, resources, dest_framebuffer)
|
Renderer::new(device, resources, dest_framebuffer)
|
||||||
});
|
});
|
||||||
|
|
||||||
renderer.set_main_framebuffer_size(size);
|
renderer.set_main_framebuffer_size(size);
|
||||||
renderer.device.bind_default_framebuffer(viewport);
|
renderer.device.bind_default_framebuffer(viewport);
|
||||||
renderer.device.clear(&ClearParams { color: Some(bg_color), ..ClearParams::default() });
|
renderer.device.clear(&ClearParams {
|
||||||
|
color: Some(bg_color),
|
||||||
|
..ClearParams::default()
|
||||||
|
});
|
||||||
renderer.disable_depth();
|
renderer.disable_depth();
|
||||||
|
|
||||||
svg.scene.set_view_box(viewport.to_f32());
|
svg.scene.set_view_box(viewport.to_f32());
|
||||||
|
|
||||||
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 /
|
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32
|
||||||
f32::max(svg.scene.bounds().size().x(), svg.scene.bounds().size().y());
|
/ f32::max(svg.scene.bounds().size().x(), svg.scene.bounds().size().y());
|
||||||
let transform = Transform2F::from_translation(svg.scene.bounds().size().scale(-0.5))
|
let transform = Transform2F::from_translation(svg.scene.bounds().size().scale(-0.5))
|
||||||
.post_mul(&Transform2F::from_scale(scale))
|
.post_mul(&Transform2F::from_scale(scale))
|
||||||
.post_mul(&Transform2F::from_translation(viewport_size.to_f32().scale(0.5)));
|
.post_mul(&Transform2F::from_translation(
|
||||||
|
viewport_size.to_f32().scale(0.5),
|
||||||
|
));
|
||||||
|
|
||||||
let render_options = RenderOptions {
|
let render_options = RenderOptions {
|
||||||
transform: RenderTransform::Transform2D(transform),
|
transform: RenderTransform::Transform2D(transform),
|
||||||
|
|
|
@ -32,9 +32,9 @@ use crate::c_api::ML_RESULT_TIMEOUT;
|
||||||
use crate::c_api::ML_VIRTUAL_CAMERA_COUNT;
|
use crate::c_api::ML_VIRTUAL_CAMERA_COUNT;
|
||||||
|
|
||||||
use egl;
|
use egl;
|
||||||
use egl::EGL_NO_SURFACE;
|
|
||||||
use egl::EGLContext;
|
use egl::EGLContext;
|
||||||
use egl::EGLDisplay;
|
use egl::EGLDisplay;
|
||||||
|
use egl::EGL_NO_SURFACE;
|
||||||
|
|
||||||
use gl;
|
use gl;
|
||||||
use gl::types::GLuint;
|
use gl::types::GLuint;
|
||||||
|
@ -53,12 +53,12 @@ use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::transform3d::Transform4F;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::util;
|
use pathfinder_geometry::util;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
|
||||||
use pathfinder_geometry::vector::vec2i;
|
use pathfinder_geometry::vector::vec2i;
|
||||||
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_gl::GLVersion;
|
use pathfinder_gl::GLVersion;
|
||||||
use pathfinder_resources::ResourceLoader;
|
|
||||||
use pathfinder_resources::fs::FilesystemResourceLoader;
|
use pathfinder_resources::fs::FilesystemResourceLoader;
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
|
|
||||||
use rayon::ThreadPoolBuilder;
|
use rayon::ThreadPoolBuilder;
|
||||||
|
@ -99,7 +99,10 @@ impl Window for MagicLeapWindow {
|
||||||
self.framebuffer_id
|
self.framebuffer_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adjust_thread_pool_settings(&self, thread_pool_builder: ThreadPoolBuilder) -> ThreadPoolBuilder {
|
fn adjust_thread_pool_settings(
|
||||||
|
&self,
|
||||||
|
thread_pool_builder: ThreadPoolBuilder,
|
||||||
|
) -> ThreadPoolBuilder {
|
||||||
thread_pool_builder.start_handler(|id| unsafe { init_scene_thread(id) })
|
thread_pool_builder.start_handler(|id| unsafe { init_scene_thread(id) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,11 +110,9 @@ impl Window for MagicLeapWindow {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_user_event(_: u32, _: u32) {
|
fn push_user_event(_: u32, _: u32) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn present_open_svg_dialog(&mut self) {
|
fn present_open_svg_dialog(&mut self) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn run_save_dialog(&self, _: &str) -> Result<PathBuf, ()> {
|
fn run_save_dialog(&self, _: &str) -> Result<PathBuf, ()> {
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -125,7 +126,10 @@ impl Window for MagicLeapWindow {
|
||||||
self.begin_frame();
|
self.begin_frame();
|
||||||
let eye = match view {
|
let eye = match view {
|
||||||
View::Stereo(eye) if (eye as usize) < ML_VIRTUAL_CAMERA_COUNT => eye as usize,
|
View::Stereo(eye) if (eye as usize) < ML_VIRTUAL_CAMERA_COUNT => eye as usize,
|
||||||
_ => { debug!("Asked for unexpected view: {:?}", view); 0 }
|
_ => {
|
||||||
|
debug!("Asked for unexpected view: {:?}", view);
|
||||||
|
0
|
||||||
|
}
|
||||||
};
|
};
|
||||||
debug!("Making {} current.", eye);
|
debug!("Making {} current.", eye);
|
||||||
let viewport = self.virtual_camera_array.viewport;
|
let viewport = self.virtual_camera_array.viewport;
|
||||||
|
@ -135,9 +139,26 @@ impl Window for MagicLeapWindow {
|
||||||
let layer_id = virtual_camera.virtual_camera_name as i32;
|
let layer_id = virtual_camera.virtual_camera_name as i32;
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer_id);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer_id);
|
||||||
gl::FramebufferTextureLayer(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, color_id, 0, layer_id);
|
gl::FramebufferTextureLayer(
|
||||||
gl::FramebufferTextureLayer(gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT, depth_id, 0, layer_id);
|
gl::FRAMEBUFFER,
|
||||||
gl::Viewport(viewport.x as i32, viewport.y as i32, viewport.w as i32, viewport.h as i32);
|
gl::COLOR_ATTACHMENT0,
|
||||||
|
color_id,
|
||||||
|
0,
|
||||||
|
layer_id,
|
||||||
|
);
|
||||||
|
gl::FramebufferTextureLayer(
|
||||||
|
gl::FRAMEBUFFER,
|
||||||
|
gl::DEPTH_ATTACHMENT,
|
||||||
|
depth_id,
|
||||||
|
0,
|
||||||
|
layer_id,
|
||||||
|
);
|
||||||
|
gl::Viewport(
|
||||||
|
viewport.x as i32,
|
||||||
|
viewport.y as i32,
|
||||||
|
viewport.w as i32,
|
||||||
|
viewport.h as i32,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
debug!("Made {} current.", eye);
|
debug!("Made {} current.", eye);
|
||||||
}
|
}
|
||||||
|
@ -175,7 +196,10 @@ impl MagicLeapWindow {
|
||||||
MLHeadTrackingCreate(&mut head_tracker).unwrap();
|
MLHeadTrackingCreate(&mut head_tracker).unwrap();
|
||||||
MLGraphicsGetRenderTargets(graphics_client, &mut targets).unwrap();
|
MLGraphicsGetRenderTargets(graphics_client, &mut targets).unwrap();
|
||||||
}
|
}
|
||||||
let (max_width, max_height) = targets.buffers.iter().map(|buffer| buffer.color)
|
let (max_width, max_height) = targets
|
||||||
|
.buffers
|
||||||
|
.iter()
|
||||||
|
.map(|buffer| buffer.color)
|
||||||
.chain(targets.buffers.iter().map(|buffer| buffer.depth))
|
.chain(targets.buffers.iter().map(|buffer| buffer.depth))
|
||||||
.map(|target| (target.width as i32, target.height as i32))
|
.map(|target| (target.width as i32, target.height as i32))
|
||||||
.max()
|
.max()
|
||||||
|
@ -218,7 +242,12 @@ impl MagicLeapWindow {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer_id);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer_id);
|
||||||
MLGraphicsInitFrameParams(&mut params).unwrap();
|
MLGraphicsInitFrameParams(&mut params).unwrap();
|
||||||
let mut result = MLGraphicsBeginFrame(self.graphics_client, ¶ms, &mut self.frame_handle, &mut self.virtual_camera_array);
|
let mut result = MLGraphicsBeginFrame(
|
||||||
|
self.graphics_client,
|
||||||
|
¶ms,
|
||||||
|
&mut self.frame_handle,
|
||||||
|
&mut self.virtual_camera_array,
|
||||||
|
);
|
||||||
if result == ML_RESULT_TIMEOUT {
|
if result == ML_RESULT_TIMEOUT {
|
||||||
info!("PF frame timeout");
|
info!("PF frame timeout");
|
||||||
let mut sleep = Duration::from_millis(1);
|
let mut sleep = Duration::from_millis(1);
|
||||||
|
@ -227,7 +256,12 @@ impl MagicLeapWindow {
|
||||||
sleep = (sleep * 2).min(max_sleep);
|
sleep = (sleep * 2).min(max_sleep);
|
||||||
info!("PF exponential backoff {}ms", sleep.as_millis());
|
info!("PF exponential backoff {}ms", sleep.as_millis());
|
||||||
thread::sleep(sleep);
|
thread::sleep(sleep);
|
||||||
result = MLGraphicsBeginFrame(self.graphics_client, ¶ms, &mut self.frame_handle, &mut self.virtual_camera_array);
|
result = MLGraphicsBeginFrame(
|
||||||
|
self.graphics_client,
|
||||||
|
¶ms,
|
||||||
|
&mut self.frame_handle,
|
||||||
|
&mut self.virtual_camera_array,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
info!("PF frame finished timeout");
|
info!("PF frame finished timeout");
|
||||||
}
|
}
|
||||||
|
@ -249,8 +283,13 @@ impl MagicLeapWindow {
|
||||||
let projection = Transform4F::from(camera.projection);
|
let projection = Transform4F::from(camera.projection);
|
||||||
let size = RectI::from(virtual_camera_array.viewport).size();
|
let size = RectI::from(virtual_camera_array.viewport).size();
|
||||||
let perspective = Perspective::new(&projection, size);
|
let perspective = Perspective::new(&projection, size);
|
||||||
let modelview_to_eye = Transform4F::from(camera.transform).inverse().post_mul(initial_camera);
|
let modelview_to_eye = Transform4F::from(camera.transform)
|
||||||
OcularTransform { perspective, modelview_to_eye }
|
.inverse()
|
||||||
|
.post_mul(initial_camera);
|
||||||
|
OcularTransform {
|
||||||
|
perspective,
|
||||||
|
modelview_to_eye,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.in_frame = true;
|
self.in_frame = true;
|
||||||
|
@ -266,7 +305,8 @@ impl MagicLeapWindow {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
for i in 0..self.virtual_camera_array.num_virtual_cameras {
|
for i in 0..self.virtual_camera_array.num_virtual_cameras {
|
||||||
let virtual_camera = &self.virtual_camera_array.virtual_cameras[i as usize];
|
let virtual_camera = &self.virtual_camera_array.virtual_cameras[i as usize];
|
||||||
MLGraphicsSignalSyncObjectGL(self.graphics_client, virtual_camera.sync_object).unwrap();
|
MLGraphicsSignalSyncObjectGL(self.graphics_client, virtual_camera.sync_object)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
MLGraphicsEndFrame(self.graphics_client, self.frame_handle).unwrap();
|
MLGraphicsEndFrame(self.graphics_client, self.frame_handle).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -358,8 +398,7 @@ impl MLTransform {
|
||||||
|
|
||||||
impl From<MLTransform> for Transform4F {
|
impl From<MLTransform> for Transform4F {
|
||||||
fn from(mat: MLTransform) -> Self {
|
fn from(mat: MLTransform) -> Self {
|
||||||
Transform4F::from(mat.rotation)
|
Transform4F::from(mat.rotation).pre_mul(&Transform4F::from(mat.position))
|
||||||
.pre_mul(&Transform4F::from(mat.position))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,10 +429,9 @@ impl From<MLQuaternionf> for Transform4F {
|
||||||
impl From<MLMat4f> for Transform4F {
|
impl From<MLMat4f> for Transform4F {
|
||||||
fn from(mat: MLMat4f) -> Self {
|
fn from(mat: MLMat4f) -> Self {
|
||||||
let a = mat.matrix_colmajor;
|
let a = mat.matrix_colmajor;
|
||||||
Transform4F::row_major(a[0], a[4], a[8], a[12],
|
Transform4F::row_major(
|
||||||
a[1], a[5], a[9], a[13],
|
a[0], a[4], a[8], a[12], a[1], a[5], a[9], a[13], a[2], a[6], a[10], a[14], a[3], a[7],
|
||||||
a[2], a[6], a[10], a[14],
|
a[11], a[15],
|
||||||
a[3], a[7], a[11], a[15])
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,11 @@ use crate::c_api::MLSnapshotPtr;
|
||||||
use crate::c_api::MLTransform;
|
use crate::c_api::MLTransform;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
pub unsafe fn MLGraphicsCreateClientGL(options: *const MLGraphicsOptions, gl_context: MLHandle, graphics_client : &mut MLHandle) -> MLResult {
|
pub unsafe fn MLGraphicsCreateClientGL(
|
||||||
|
options: *const MLGraphicsOptions,
|
||||||
|
gl_context: MLHandle,
|
||||||
|
graphics_client: &mut MLHandle,
|
||||||
|
) -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +44,10 @@ pub unsafe fn MLHeadTrackingCreate(tracker: *mut MLHandle) -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn MLHeadTrackingGetStaticData(head_tracker: MLHandle, data: *mut MLHeadTrackingStaticData) -> MLResult {
|
pub unsafe fn MLHeadTrackingGetStaticData(
|
||||||
|
head_tracker: MLHandle,
|
||||||
|
data: *mut MLHeadTrackingStaticData,
|
||||||
|
) -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +55,11 @@ pub unsafe fn MLPerceptionGetSnapshot(snapshot: *mut MLSnapshotPtr) -> MLResult
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn MLSnapshotGetTransform(snapshot: MLSnapshotPtr, id: *const MLCoordinateFrameUID, transform: *mut MLTransform) -> MLResult {
|
pub unsafe fn MLSnapshotGetTransform(
|
||||||
|
snapshot: MLSnapshotPtr,
|
||||||
|
id: *const MLCoordinateFrameUID,
|
||||||
|
transform: *mut MLTransform,
|
||||||
|
) -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +71,17 @@ pub unsafe fn MLLifecycleSetReadyIndication() -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn MLGraphicsGetClipExtents(graphics_client: MLHandle, array: *mut MLGraphicsClipExtentsInfoArray) -> MLResult {
|
pub unsafe fn MLGraphicsGetClipExtents(
|
||||||
|
graphics_client: MLHandle,
|
||||||
|
array: *mut MLGraphicsClipExtentsInfoArray,
|
||||||
|
) -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn MLGraphicsGetRenderTargets(graphics_client: MLHandle, targets: *mut MLGraphicsRenderTargetsInfo) -> MLResult {
|
pub unsafe fn MLGraphicsGetRenderTargets(
|
||||||
|
graphics_client: MLHandle,
|
||||||
|
targets: *mut MLGraphicsRenderTargetsInfo,
|
||||||
|
) -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +89,12 @@ pub unsafe fn MLGraphicsInitFrameParams(params: *mut MLGraphicsFrameParams) -> M
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn MLGraphicsBeginFrame(graphics_client: MLHandle, params: *const MLGraphicsFrameParams, frame_handle: *mut MLHandle, virtual_camera_array: *mut MLGraphicsVirtualCameraInfoArray) -> MLResult {
|
pub unsafe fn MLGraphicsBeginFrame(
|
||||||
|
graphics_client: MLHandle,
|
||||||
|
params: *const MLGraphicsFrameParams,
|
||||||
|
frame_handle: *mut MLHandle,
|
||||||
|
virtual_camera_array: *mut MLGraphicsVirtualCameraInfoArray,
|
||||||
|
) -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +102,10 @@ pub unsafe fn MLGraphicsEndFrame(graphics_client: MLHandle, frame_handle: MLHand
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn MLGraphicsSignalSyncObjectGL(graphics_client: MLHandle, sync_object: MLHandle) -> MLResult {
|
pub unsafe fn MLGraphicsSignalSyncObjectGL(
|
||||||
|
graphics_client: MLHandle,
|
||||||
|
sync_object: MLHandle,
|
||||||
|
) -> MLResult {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,4 +120,3 @@ pub unsafe fn MLLoggingLogLevelIsEnabled(lvl: MLLogLevel) -> bool {
|
||||||
pub unsafe fn MLLoggingLog(lvl: MLLogLevel, tag: *const c_char, message: *const c_char) {
|
pub unsafe fn MLLoggingLog(lvl: MLLogLevel, tag: *const c_char, message: *const c_char) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,33 +18,33 @@ extern crate objc;
|
||||||
|
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use nfd::Response;
|
use nfd::Response;
|
||||||
use pathfinder_demo::window::{Event, Keycode, DataPath, View, Window, WindowSize};
|
use pathfinder_demo::window::{DataPath, Event, Keycode, View, Window, WindowSize};
|
||||||
use pathfinder_demo::{DemoApp, Options};
|
use pathfinder_demo::{DemoApp, Options};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{vec2i, Vector2I};
|
||||||
use pathfinder_resources::ResourceLoader;
|
|
||||||
use pathfinder_resources::fs::FilesystemResourceLoader;
|
use pathfinder_resources::fs::FilesystemResourceLoader;
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use surfman::{SurfaceAccess, SurfaceType, declare_surfman};
|
use surfman::{declare_surfman, SurfaceAccess, SurfaceType};
|
||||||
|
use winit::dpi::LogicalSize;
|
||||||
use winit::{ControlFlow, ElementState, Event as WinitEvent, EventsLoop, EventsLoopProxy};
|
use winit::{ControlFlow, ElementState, Event as WinitEvent, EventsLoop, EventsLoopProxy};
|
||||||
use winit::{MouseButton, VirtualKeyCode, Window as WinitWindow, WindowBuilder, WindowEvent};
|
use winit::{MouseButton, VirtualKeyCode, Window as WinitWindow, WindowBuilder, WindowEvent};
|
||||||
use winit::dpi::LogicalSize;
|
|
||||||
|
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
|
||||||
use gl::types::GLuint;
|
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
use gl;
|
use gl;
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
use surfman::{Connection, Context, ContextAttributeFlags, ContextAttributes};
|
use gl::types::GLuint;
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
|
||||||
use surfman::{Device, GLVersion as SurfmanGLVersion};
|
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
use io_surface::IOSurfaceRef;
|
use io_surface::IOSurfaceRef;
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
use pathfinder_metal::MetalDevice;
|
use pathfinder_metal::MetalDevice;
|
||||||
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
|
use surfman::{Connection, Context, ContextAttributeFlags, ContextAttributes};
|
||||||
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
|
use surfman::{Device, GLVersion as SurfmanGLVersion};
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
use surfman::{NativeDevice, SystemConnection, SystemDevice, SystemSurface};
|
use surfman::{NativeDevice, SystemConnection, SystemDevice, SystemSurface};
|
||||||
|
|
||||||
|
@ -138,7 +138,10 @@ struct EventQueue {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum CustomEvent {
|
enum CustomEvent {
|
||||||
User { message_type: u32, message_data: u32 },
|
User {
|
||||||
|
message_type: u32,
|
||||||
|
message_data: u32,
|
||||||
|
},
|
||||||
OpenData(PathBuf),
|
OpenData(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,15 +158,17 @@ impl Window for WindowImpl {
|
||||||
|
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
fn gl_default_framebuffer(&self) -> GLuint {
|
fn gl_default_framebuffer(&self) -> GLuint {
|
||||||
self.device.context_surface_info(&self.context).unwrap().unwrap().framebuffer_object
|
self.device
|
||||||
|
.context_surface_info(&self.context)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.framebuffer_object
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
fn metal_device(&self) -> metal::Device {
|
fn metal_device(&self) -> metal::Device {
|
||||||
// FIXME(pcwalton): Remove once `surfman` upgrades `metal-rs` version.
|
// FIXME(pcwalton): Remove once `surfman` upgrades `metal-rs` version.
|
||||||
unsafe {
|
unsafe { std::mem::transmute(self.metal_device.0.clone()) }
|
||||||
std::mem::transmute(self.metal_device.0.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
|
@ -172,7 +177,10 @@ impl Window for WindowImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn viewport(&self, view: View) -> RectI {
|
fn viewport(&self, view: View) -> RectI {
|
||||||
let WindowSize { logical_size, backing_scale_factor } = self.size();
|
let WindowSize {
|
||||||
|
logical_size,
|
||||||
|
backing_scale_factor,
|
||||||
|
} = self.size();
|
||||||
let mut size = (logical_size.to_f32() * backing_scale_factor).to_i32();
|
let mut size = (logical_size.to_f32() * backing_scale_factor).to_i32();
|
||||||
let mut x_offset = 0;
|
let mut x_offset = 0;
|
||||||
if let View::Stereo(index) = view {
|
if let View::Stereo(index) = view {
|
||||||
|
@ -192,17 +200,24 @@ impl Window for WindowImpl {
|
||||||
|
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||||
fn present(&mut self, _: &mut GLDevice) {
|
fn present(&mut self, _: &mut GLDevice) {
|
||||||
let mut surface = self.device
|
let mut surface = self
|
||||||
|
.device
|
||||||
.unbind_surface_from_context(&mut self.context)
|
.unbind_surface_from_context(&mut self.context)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.device.present_surface(&mut self.context, &mut surface).unwrap();
|
self.device
|
||||||
self.device.bind_surface_to_context(&mut self.context, surface).unwrap();
|
.present_surface(&mut self.context, &mut surface)
|
||||||
|
.unwrap();
|
||||||
|
self.device
|
||||||
|
.bind_surface_to_context(&mut self.context, surface)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
fn present(&mut self, metal_device: &mut MetalDevice) {
|
fn present(&mut self, metal_device: &mut MetalDevice) {
|
||||||
self.device.present_surface(&mut self.surface).expect("Failed to present surface!");
|
self.device
|
||||||
|
.present_surface(&mut self.surface)
|
||||||
|
.expect("Failed to present surface!");
|
||||||
metal_device.swap_texture(self.device.native_surface(&self.surface).0);
|
metal_device.swap_texture(self.device.native_surface(&self.surface).0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +229,9 @@ impl Window for WindowImpl {
|
||||||
if let Ok(Response::Okay(path)) = nfd::open_file_dialog(Some("svg,pdf"), None) {
|
if let Ok(Response::Okay(path)) = nfd::open_file_dialog(Some("svg,pdf"), None) {
|
||||||
let mut event_queue = EVENT_QUEUE.lock().unwrap();
|
let mut event_queue = EVENT_QUEUE.lock().unwrap();
|
||||||
let event_queue = event_queue.as_mut().unwrap();
|
let event_queue = event_queue.as_mut().unwrap();
|
||||||
event_queue.pending_custom_events.push_back(CustomEvent::OpenData(PathBuf::from(path)));
|
event_queue
|
||||||
|
.pending_custom_events
|
||||||
|
.push_back(CustomEvent::OpenData(PathBuf::from(path)));
|
||||||
drop(event_queue.event_loop_proxy.wakeup());
|
drop(event_queue.event_loop_proxy.wakeup());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,7 +252,9 @@ impl Window for WindowImpl {
|
||||||
fn push_user_event(message_type: u32, message_data: u32) {
|
fn push_user_event(message_type: u32, message_data: u32) {
|
||||||
let mut event_queue = EVENT_QUEUE.lock().unwrap();
|
let mut event_queue = EVENT_QUEUE.lock().unwrap();
|
||||||
let event_queue = event_queue.as_mut().unwrap();
|
let event_queue = event_queue.as_mut().unwrap();
|
||||||
event_queue.pending_custom_events.push_back(CustomEvent::User {
|
event_queue
|
||||||
|
.pending_custom_events
|
||||||
|
.push_back(CustomEvent::User {
|
||||||
message_type,
|
message_type,
|
||||||
message_data,
|
message_data,
|
||||||
});
|
});
|
||||||
|
@ -249,14 +268,17 @@ impl WindowImpl {
|
||||||
let event_loop = EventsLoop::new();
|
let event_loop = EventsLoop::new();
|
||||||
let window_size = Size2D::new(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
|
let window_size = Size2D::new(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
|
||||||
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
||||||
let window = WindowBuilder::new().with_title("Pathfinder Demo")
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("Pathfinder Demo")
|
||||||
.with_dimensions(logical_size)
|
.with_dimensions(logical_size)
|
||||||
.build(&event_loop)
|
.build(&event_loop)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
let connection = Connection::from_winit_window(&window).unwrap();
|
let connection = Connection::from_winit_window(&window).unwrap();
|
||||||
let native_widget = connection.create_native_widget_from_winit_window(&window).unwrap();
|
let native_widget = connection
|
||||||
|
.create_native_widget_from_winit_window(&window)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let adapter = if options.high_performance_gpu {
|
let adapter = if options.high_performance_gpu {
|
||||||
connection.create_hardware_adapter().unwrap()
|
connection.create_hardware_adapter().unwrap()
|
||||||
|
@ -270,13 +292,18 @@ impl WindowImpl {
|
||||||
version: SurfmanGLVersion::new(3, 0),
|
version: SurfmanGLVersion::new(3, 0),
|
||||||
flags: ContextAttributeFlags::ALPHA,
|
flags: ContextAttributeFlags::ALPHA,
|
||||||
};
|
};
|
||||||
let context_descriptor = device.create_context_descriptor(&context_attributes).unwrap();
|
let context_descriptor = device
|
||||||
|
.create_context_descriptor(&context_attributes)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let surface_type = SurfaceType::Widget { native_widget };
|
let surface_type = SurfaceType::Widget { native_widget };
|
||||||
let mut context = device.create_context(&context_descriptor).unwrap();
|
let mut context = device.create_context(&context_descriptor).unwrap();
|
||||||
let surface = device.create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
|
let surface = device
|
||||||
|
.create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
|
||||||
|
.unwrap();
|
||||||
|
device
|
||||||
|
.bind_surface_to_context(&mut context, surface)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
device.bind_surface_to_context(&mut context, surface).unwrap();
|
|
||||||
device.make_context_current(&context).unwrap();
|
device.make_context_current(&context).unwrap();
|
||||||
|
|
||||||
gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));
|
gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));
|
||||||
|
@ -307,14 +334,17 @@ impl WindowImpl {
|
||||||
let event_loop = EventsLoop::new();
|
let event_loop = EventsLoop::new();
|
||||||
let window_size = Size2D::new(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
|
let window_size = Size2D::new(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
|
||||||
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
||||||
let window = WindowBuilder::new().with_title("Pathfinder Demo")
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("Pathfinder Demo")
|
||||||
.with_dimensions(logical_size)
|
.with_dimensions(logical_size)
|
||||||
.build(&event_loop)
|
.build(&event_loop)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
let connection = SystemConnection::from_winit_window(&window).unwrap();
|
let connection = SystemConnection::from_winit_window(&window).unwrap();
|
||||||
let native_widget = connection.create_native_widget_from_winit_window(&window).unwrap();
|
let native_widget = connection
|
||||||
|
.create_native_widget_from_winit_window(&window)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let adapter = if options.high_performance_gpu {
|
let adapter = if options.high_performance_gpu {
|
||||||
connection.create_hardware_adapter().unwrap()
|
connection.create_hardware_adapter().unwrap()
|
||||||
|
@ -326,7 +356,9 @@ impl WindowImpl {
|
||||||
let native_device = device.native_device();
|
let native_device = device.native_device();
|
||||||
|
|
||||||
let surface_type = SurfaceType::Widget { native_widget };
|
let surface_type = SurfaceType::Widget { native_widget };
|
||||||
let surface = device.create_surface(SurfaceAccess::GPUOnly, surface_type).unwrap();
|
let surface = device
|
||||||
|
.create_surface(SurfaceAccess::GPUOnly, surface_type)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let resource_loader = FilesystemResourceLoader::locate();
|
let resource_loader = FilesystemResourceLoader::locate();
|
||||||
|
|
||||||
|
@ -350,11 +382,16 @@ impl WindowImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window(&self) -> &WinitWindow { &self.window }
|
fn window(&self) -> &WinitWindow {
|
||||||
|
&self.window
|
||||||
|
}
|
||||||
|
|
||||||
fn size(&self) -> WindowSize {
|
fn size(&self) -> WindowSize {
|
||||||
let window = self.window();
|
let window = self.window();
|
||||||
let (monitor, size) = (window.get_current_monitor(), window.get_inner_size().unwrap());
|
let (monitor, size) = (
|
||||||
|
window.get_current_monitor(),
|
||||||
|
window.get_inner_size().unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
WindowSize {
|
WindowSize {
|
||||||
logical_size: vec2i(size.width as i32, size.height as i32),
|
logical_size: vec2i(size.width as i32, size.height as i32),
|
||||||
|
@ -370,18 +407,13 @@ impl WindowImpl {
|
||||||
let pending_events = &mut self.pending_events;
|
let pending_events = &mut self.pending_events;
|
||||||
self.event_loop.run_forever(|winit_event| {
|
self.event_loop.run_forever(|winit_event| {
|
||||||
//println!("blocking {:?}", winit_event);
|
//println!("blocking {:?}", winit_event);
|
||||||
match convert_winit_event(winit_event,
|
match convert_winit_event(winit_event, window, mouse_position, mouse_down) {
|
||||||
window,
|
|
||||||
mouse_position,
|
|
||||||
mouse_down) {
|
|
||||||
Some(event) => {
|
Some(event) => {
|
||||||
//println!("handled");
|
//println!("handled");
|
||||||
pending_events.push_back(event);
|
pending_events.push_back(event);
|
||||||
ControlFlow::Break
|
ControlFlow::Break
|
||||||
}
|
}
|
||||||
None => {
|
None => ControlFlow::Continue,
|
||||||
ControlFlow::Continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -397,10 +429,9 @@ impl WindowImpl {
|
||||||
let pending_events = &mut self.pending_events;
|
let pending_events = &mut self.pending_events;
|
||||||
self.event_loop.poll_events(|winit_event| {
|
self.event_loop.poll_events(|winit_event| {
|
||||||
//println!("nonblocking {:?}", winit_event);
|
//println!("nonblocking {:?}", winit_event);
|
||||||
if let Some(event) = convert_winit_event(winit_event,
|
if let Some(event) =
|
||||||
window,
|
convert_winit_event(winit_event, window, mouse_position, mouse_down)
|
||||||
mouse_position,
|
{
|
||||||
mouse_down) {
|
|
||||||
//println!("handled");
|
//println!("handled");
|
||||||
pending_events.push_back(event);
|
pending_events.push_back(event);
|
||||||
}
|
}
|
||||||
|
@ -410,26 +441,37 @@ impl WindowImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_winit_event(winit_event: WinitEvent,
|
fn convert_winit_event(
|
||||||
|
winit_event: WinitEvent,
|
||||||
window: &WinitWindow,
|
window: &WinitWindow,
|
||||||
mouse_position: &mut Vector2I,
|
mouse_position: &mut Vector2I,
|
||||||
mouse_down: &mut bool)
|
mouse_down: &mut bool,
|
||||||
-> Option<Event> {
|
) -> Option<Event> {
|
||||||
match winit_event {
|
match winit_event {
|
||||||
WinitEvent::Awakened => {
|
WinitEvent::Awakened => {
|
||||||
let mut event_queue = EVENT_QUEUE.lock().unwrap();
|
let mut event_queue = EVENT_QUEUE.lock().unwrap();
|
||||||
let event_queue = event_queue.as_mut().unwrap();
|
let event_queue = event_queue.as_mut().unwrap();
|
||||||
match event_queue.pending_custom_events
|
match event_queue
|
||||||
|
.pending_custom_events
|
||||||
.pop_front()
|
.pop_front()
|
||||||
.expect("`Awakened` with no pending custom event!") {
|
.expect("`Awakened` with no pending custom event!")
|
||||||
CustomEvent::OpenData(data_path) => Some(Event::OpenData(DataPath::Path(data_path))),
|
{
|
||||||
CustomEvent::User { message_data, message_type } => {
|
CustomEvent::OpenData(data_path) => {
|
||||||
Some(Event::User { message_data, message_type })
|
Some(Event::OpenData(DataPath::Path(data_path)))
|
||||||
|
}
|
||||||
|
CustomEvent::User {
|
||||||
|
message_data,
|
||||||
|
message_type,
|
||||||
|
} => Some(Event::User {
|
||||||
|
message_data,
|
||||||
|
message_type,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
WinitEvent::WindowEvent {
|
||||||
WinitEvent::WindowEvent { event: window_event, .. } => {
|
event: window_event,
|
||||||
match window_event {
|
..
|
||||||
|
} => match window_event {
|
||||||
WindowEvent::MouseInput {
|
WindowEvent::MouseInput {
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed,
|
||||||
button: MouseButton::Left,
|
button: MouseButton::Left,
|
||||||
|
@ -454,9 +496,9 @@ fn convert_winit_event(winit_event: WinitEvent,
|
||||||
Some(Event::MouseMoved(*mouse_position))
|
Some(Event::MouseMoved(*mouse_position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowEvent::KeyboardInput { input, .. } => {
|
WindowEvent::KeyboardInput { input, .. } => input
|
||||||
input.virtual_keycode.and_then(|virtual_keycode| {
|
.virtual_keycode
|
||||||
match virtual_keycode {
|
.and_then(|virtual_keycode| match virtual_keycode {
|
||||||
VirtualKeyCode::Escape => Some(Keycode::Escape),
|
VirtualKeyCode::Escape => Some(Keycode::Escape),
|
||||||
VirtualKeyCode::Tab => Some(Keycode::Tab),
|
VirtualKeyCode::Tab => Some(Keycode::Tab),
|
||||||
virtual_keycode => {
|
virtual_keycode => {
|
||||||
|
@ -470,27 +512,22 @@ fn convert_winit_event(winit_event: WinitEvent,
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}).map(|keycode| {
|
.map(|keycode| match input.state {
|
||||||
match input.state {
|
|
||||||
ElementState::Pressed => Event::KeyDown(keycode),
|
ElementState::Pressed => Event::KeyDown(keycode),
|
||||||
ElementState::Released => Event::KeyUp(keycode),
|
ElementState::Released => Event::KeyUp(keycode),
|
||||||
}
|
}),
|
||||||
})
|
|
||||||
}
|
|
||||||
WindowEvent::CloseRequested => Some(Event::Quit),
|
WindowEvent::CloseRequested => Some(Event::Quit),
|
||||||
WindowEvent::Resized(new_size) => {
|
WindowEvent::Resized(new_size) => {
|
||||||
let logical_size = vec2i(new_size.width as i32, new_size.height as i32);
|
let logical_size = vec2i(new_size.width as i32, new_size.height as i32);
|
||||||
let backing_scale_factor =
|
let backing_scale_factor = window.get_current_monitor().get_hidpi_factor() as f32;
|
||||||
window.get_current_monitor().get_hidpi_factor() as f32;
|
|
||||||
Some(Event::WindowResized(WindowSize {
|
Some(Event::WindowResized(WindowSize {
|
||||||
logical_size,
|
logical_size,
|
||||||
backing_scale_factor,
|
backing_scale_factor,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,21 +11,21 @@
|
||||||
//! Demonstrates how to use the Pathfinder canvas API with `glutin`.
|
//! Demonstrates how to use the Pathfinder canvas API with `glutin`.
|
||||||
|
|
||||||
use glutin::dpi::PhysicalSize;
|
use glutin::dpi::PhysicalSize;
|
||||||
use glutin::{ContextBuilder, GlProfile, GlRequest};
|
|
||||||
use glutin::event_loop::{ControlFlow, EventLoop};
|
|
||||||
use glutin::event::{Event, KeyboardInput, VirtualKeyCode, WindowEvent};
|
use glutin::event::{Event, KeyboardInput, VirtualKeyCode, WindowEvent};
|
||||||
|
use glutin::event_loop::{ControlFlow, EventLoop};
|
||||||
use glutin::window::WindowBuilder;
|
use glutin::window::WindowBuilder;
|
||||||
|
use glutin::{ContextBuilder, GlProfile, GlRequest};
|
||||||
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D};
|
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D};
|
||||||
use pathfinder_color::ColorF;
|
use pathfinder_color::ColorF;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::vector::{vec2f, vec2i};
|
use pathfinder_geometry::vector::{vec2f, vec2i};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Calculate the right logical size of the window.
|
// Calculate the right logical size of the window.
|
||||||
|
@ -34,11 +34,13 @@ fn main() {
|
||||||
let physical_window_size = PhysicalSize::new(window_size.x() as f64, window_size.y() as f64);
|
let physical_window_size = PhysicalSize::new(window_size.x() as f64, window_size.y() as f64);
|
||||||
|
|
||||||
// Open a window.
|
// Open a window.
|
||||||
let window_builder = WindowBuilder::new().with_title("Minimal example")
|
let window_builder = WindowBuilder::new()
|
||||||
|
.with_title("Minimal example")
|
||||||
.with_inner_size(physical_window_size);
|
.with_inner_size(physical_window_size);
|
||||||
|
|
||||||
// Create an OpenGL 3.x context for Pathfinder to use.
|
// Create an OpenGL 3.x context for Pathfinder to use.
|
||||||
let gl_context = ContextBuilder::new().with_gl(GlRequest::Latest)
|
let gl_context = ContextBuilder::new()
|
||||||
|
.with_gl(GlRequest::Latest)
|
||||||
.with_gl_profile(GlProfile::Core)
|
.with_gl_profile(GlProfile::Core)
|
||||||
.build_windowed(window_builder, &event_loop)
|
.build_windowed(window_builder, &event_loop)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -79,28 +81,38 @@ fn main() {
|
||||||
canvas.stroke_path(path);
|
canvas.stroke_path(path);
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let mut scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(),
|
let mut scene = SceneProxy::from_scene(
|
||||||
|
canvas.into_canvas().into_scene(),
|
||||||
renderer.mode().level,
|
renderer.mode().level,
|
||||||
RayonExecutor);
|
RayonExecutor,
|
||||||
|
);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
gl_context.swap_buffers().unwrap();
|
gl_context.swap_buffers().unwrap();
|
||||||
|
|
||||||
// Wait for a keypress.
|
// Wait for a keypress.
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } |
|
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::KeyboardInput {
|
event: WindowEvent::CloseRequested,
|
||||||
input: KeyboardInput { virtual_keycode: Some(VirtualKeyCode::Escape), .. },
|
..
|
||||||
|
}
|
||||||
|
| Event::WindowEvent {
|
||||||
|
event:
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
input:
|
||||||
|
KeyboardInput {
|
||||||
|
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||||
|
..
|
||||||
|
},
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
*control_flow = ControlFlow::Wait;
|
*control_flow = ControlFlow::Wait;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ use foreign_types::ForeignTypeRef;
|
||||||
use metal::{CAMetalLayer, CoreAnimationLayerRef};
|
use metal::{CAMetalLayer, CoreAnimationLayerRef};
|
||||||
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D};
|
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D};
|
||||||
use pathfinder_color::ColorF;
|
use pathfinder_color::ColorF;
|
||||||
use pathfinder_geometry::vector::{vec2f, vec2i};
|
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
|
use pathfinder_geometry::vector::{vec2f, vec2i};
|
||||||
use pathfinder_metal::MetalDevice;
|
use pathfinder_metal::MetalDevice;
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
|
@ -34,7 +34,12 @@ fn main() {
|
||||||
|
|
||||||
// Open a window.
|
// Open a window.
|
||||||
let window_size = vec2i(640, 480);
|
let window_size = vec2i(640, 480);
|
||||||
let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32)
|
let window = video
|
||||||
|
.window(
|
||||||
|
"Minimal example",
|
||||||
|
window_size.x() as u32,
|
||||||
|
window_size.y() as u32,
|
||||||
|
)
|
||||||
.opengl()
|
.opengl()
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -48,9 +53,7 @@ fn main() {
|
||||||
let drawable = metal_layer.next_drawable().unwrap();
|
let drawable = metal_layer.next_drawable().unwrap();
|
||||||
|
|
||||||
// Create a Pathfinder renderer.
|
// Create a Pathfinder renderer.
|
||||||
let device = unsafe {
|
let device = unsafe { MetalDevice::new(metal_device, drawable.clone()) };
|
||||||
MetalDevice::new(metal_device, drawable.clone())
|
|
||||||
};
|
|
||||||
let mode = RendererMode::default_for_device(&device);
|
let mode = RendererMode::default_for_device(&device);
|
||||||
let options = RendererOptions {
|
let options = RendererOptions {
|
||||||
dest: DestFramebuffer::full_window(window_size),
|
dest: DestFramebuffer::full_window(window_size),
|
||||||
|
@ -81,9 +84,11 @@ fn main() {
|
||||||
canvas.stroke_path(path);
|
canvas.stroke_path(path);
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let mut scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(),
|
let mut scene = SceneProxy::from_scene(
|
||||||
|
canvas.into_canvas().into_scene(),
|
||||||
renderer.mode().level,
|
renderer.mode().level,
|
||||||
RayonExecutor);
|
RayonExecutor,
|
||||||
|
);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
renderer.device().present_drawable(drawable);
|
renderer.device().present_drawable(drawable);
|
||||||
|
|
||||||
|
@ -91,7 +96,11 @@ fn main() {
|
||||||
let mut event_pump = sdl_context.event_pump().unwrap();
|
let mut event_pump = sdl_context.event_pump().unwrap();
|
||||||
loop {
|
loop {
|
||||||
match event_pump.wait_event() {
|
match event_pump.wait_event() {
|
||||||
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return,
|
Event::Quit { .. }
|
||||||
|
| Event::KeyDown {
|
||||||
|
keycode: Some(Keycode::Escape),
|
||||||
|
..
|
||||||
|
} => return,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@ use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererO
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
use surfman::{Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion};
|
use surfman::{
|
||||||
|
Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion,
|
||||||
|
};
|
||||||
use surfman::{SurfaceAccess, SurfaceType};
|
use surfman::{SurfaceAccess, SurfaceType};
|
||||||
use winit::dpi::LogicalSize;
|
use winit::dpi::LogicalSize;
|
||||||
use winit::{ControlFlow, Event, EventsLoop, WindowBuilder, WindowEvent};
|
use winit::{ControlFlow, Event, EventsLoop, WindowBuilder, WindowEvent};
|
||||||
|
@ -30,7 +32,8 @@ fn main() {
|
||||||
let mut event_loop = EventsLoop::new();
|
let mut event_loop = EventsLoop::new();
|
||||||
let window_size = Size2D::new(640, 480);
|
let window_size = Size2D::new(640, 480);
|
||||||
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
||||||
let window = WindowBuilder::new().with_title("Minimal example")
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("Minimal example")
|
||||||
.with_dimensions(logical_size)
|
.with_dimensions(logical_size)
|
||||||
.build(&event_loop)
|
.build(&event_loop)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -39,7 +42,9 @@ fn main() {
|
||||||
// Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
|
// Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
|
||||||
// GPU.
|
// GPU.
|
||||||
let connection = Connection::from_winit_window(&window).unwrap();
|
let connection = Connection::from_winit_window(&window).unwrap();
|
||||||
let native_widget = connection.create_native_widget_from_winit_window(&window).unwrap();
|
let native_widget = connection
|
||||||
|
.create_native_widget_from_winit_window(&window)
|
||||||
|
.unwrap();
|
||||||
let adapter = connection.create_low_power_adapter().unwrap();
|
let adapter = connection.create_low_power_adapter().unwrap();
|
||||||
let mut device = connection.create_device(&adapter).unwrap();
|
let mut device = connection.create_device(&adapter).unwrap();
|
||||||
|
|
||||||
|
@ -48,14 +53,19 @@ fn main() {
|
||||||
version: SurfmanGLVersion::new(3, 0),
|
version: SurfmanGLVersion::new(3, 0),
|
||||||
flags: ContextAttributeFlags::ALPHA,
|
flags: ContextAttributeFlags::ALPHA,
|
||||||
};
|
};
|
||||||
let context_descriptor = device.create_context_descriptor(&context_attributes).unwrap();
|
let context_descriptor = device
|
||||||
|
.create_context_descriptor(&context_attributes)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Make the OpenGL context via `surfman`, and load OpenGL functions.
|
// Make the OpenGL context via `surfman`, and load OpenGL functions.
|
||||||
let surface_type = SurfaceType::Widget { native_widget };
|
let surface_type = SurfaceType::Widget { native_widget };
|
||||||
let mut context = device.create_context(&context_descriptor).unwrap();
|
let mut context = device.create_context(&context_descriptor).unwrap();
|
||||||
let surface = device.create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
|
let surface = device
|
||||||
|
.create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
|
||||||
|
.unwrap();
|
||||||
|
device
|
||||||
|
.bind_surface_to_context(&mut context, surface)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
device.bind_surface_to_context(&mut context, surface).unwrap();
|
|
||||||
device.make_context_current(&context).unwrap();
|
device.make_context_current(&context).unwrap();
|
||||||
gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));
|
gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));
|
||||||
|
|
||||||
|
@ -65,7 +75,8 @@ fn main() {
|
||||||
let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);
|
let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);
|
||||||
|
|
||||||
// Create a Pathfinder GL device.
|
// Create a Pathfinder GL device.
|
||||||
let default_framebuffer = device.context_surface_info(&context)
|
let default_framebuffer = device
|
||||||
|
.context_surface_info(&context)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.framebuffer_object;
|
.framebuffer_object;
|
||||||
|
@ -87,17 +98,27 @@ fn main() {
|
||||||
event_loop.run_forever(|event| {
|
event_loop.run_forever(|event| {
|
||||||
let mut should_render = is_first_render;
|
let mut should_render = is_first_render;
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } |
|
Event::WindowEvent {
|
||||||
Event::WindowEvent { event: WindowEvent::KeyboardInput { .. }, .. } => return ControlFlow::Break,
|
event: WindowEvent::CloseRequested,
|
||||||
Event::WindowEvent { event: WindowEvent::Refresh, .. } => {
|
..
|
||||||
|
}
|
||||||
|
| Event::WindowEvent {
|
||||||
|
event: WindowEvent::KeyboardInput { .. },
|
||||||
|
..
|
||||||
|
} => return ControlFlow::Break,
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::Refresh,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
should_render = true;
|
should_render = true;
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_render {
|
if should_render {
|
||||||
// Make a canvas. We're going to draw a house.
|
// Make a canvas. We're going to draw a house.
|
||||||
let mut canvas = Canvas::new(framebuffer_size.to_f32()).get_context_2d(font_context.clone());
|
let mut canvas =
|
||||||
|
Canvas::new(framebuffer_size.to_f32()).get_context_2d(font_context.clone());
|
||||||
|
|
||||||
// Set line width.
|
// Set line width.
|
||||||
canvas.set_line_width(10.0);
|
canvas.set_line_width(10.0);
|
||||||
|
@ -117,15 +138,22 @@ fn main() {
|
||||||
canvas.stroke_path(path);
|
canvas.stroke_path(path);
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let mut scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(),
|
let mut scene = SceneProxy::from_scene(
|
||||||
|
canvas.into_canvas().into_scene(),
|
||||||
renderer.mode().level,
|
renderer.mode().level,
|
||||||
RayonExecutor);
|
RayonExecutor,
|
||||||
|
);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
|
|
||||||
// Present the surface.
|
// Present the surface.
|
||||||
let mut surface = device.unbind_surface_from_context(&mut context).unwrap().unwrap();
|
let mut surface = device
|
||||||
|
.unbind_surface_from_context(&mut context)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
device.present_surface(&mut context, &mut surface).unwrap();
|
device.present_surface(&mut context, &mut surface).unwrap();
|
||||||
device.bind_surface_to_context(&mut context, surface).unwrap();
|
device
|
||||||
|
.bind_surface_to_context(&mut context, surface)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
is_first_render = false;
|
is_first_render = false;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillStyle, Path2D};
|
use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillStyle, Path2D};
|
||||||
use pathfinder_color::{ColorF, ColorU};
|
use pathfinder_color::{ColorF, ColorU};
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
|
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F, Vector2I};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
|
@ -19,9 +19,11 @@ use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererO
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
use std::f32::consts::PI;
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use surfman::{Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion};
|
use std::f32::consts::PI;
|
||||||
|
use surfman::{
|
||||||
|
Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion,
|
||||||
|
};
|
||||||
use surfman::{SurfaceAccess, SurfaceType};
|
use surfman::{SurfaceAccess, SurfaceType};
|
||||||
use winit::dpi::LogicalSize;
|
use winit::dpi::LogicalSize;
|
||||||
use winit::{Event, EventsLoop, WindowBuilder, WindowEvent};
|
use winit::{Event, EventsLoop, WindowBuilder, WindowEvent};
|
||||||
|
@ -43,7 +45,8 @@ fn main() {
|
||||||
let mut event_loop = EventsLoop::new();
|
let mut event_loop = EventsLoop::new();
|
||||||
let window_size = Size2D::new(1067, 800);
|
let window_size = Size2D::new(1067, 800);
|
||||||
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
||||||
let window = WindowBuilder::new().with_title("Moire example")
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("Moire example")
|
||||||
.with_dimensions(logical_size)
|
.with_dimensions(logical_size)
|
||||||
.build(&event_loop)
|
.build(&event_loop)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -52,7 +55,9 @@ fn main() {
|
||||||
// Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
|
// Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
|
||||||
// GPU.
|
// GPU.
|
||||||
let connection = Connection::from_winit_window(&window).unwrap();
|
let connection = Connection::from_winit_window(&window).unwrap();
|
||||||
let native_widget = connection.create_native_widget_from_winit_window(&window).unwrap();
|
let native_widget = connection
|
||||||
|
.create_native_widget_from_winit_window(&window)
|
||||||
|
.unwrap();
|
||||||
let adapter = connection.create_low_power_adapter().unwrap();
|
let adapter = connection.create_low_power_adapter().unwrap();
|
||||||
let mut device = connection.create_device(&adapter).unwrap();
|
let mut device = connection.create_device(&adapter).unwrap();
|
||||||
|
|
||||||
|
@ -61,14 +66,19 @@ fn main() {
|
||||||
version: SurfmanGLVersion::new(3, 0),
|
version: SurfmanGLVersion::new(3, 0),
|
||||||
flags: ContextAttributeFlags::ALPHA,
|
flags: ContextAttributeFlags::ALPHA,
|
||||||
};
|
};
|
||||||
let context_descriptor = device.create_context_descriptor(&context_attributes).unwrap();
|
let context_descriptor = device
|
||||||
|
.create_context_descriptor(&context_attributes)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Make the OpenGL context via `surfman`, and load OpenGL functions.
|
// Make the OpenGL context via `surfman`, and load OpenGL functions.
|
||||||
let surface_type = SurfaceType::Widget { native_widget };
|
let surface_type = SurfaceType::Widget { native_widget };
|
||||||
let mut gl_context = device.create_context(&context_descriptor).unwrap();
|
let mut gl_context = device.create_context(&context_descriptor).unwrap();
|
||||||
let surface = device.create_surface(&gl_context, SurfaceAccess::GPUOnly, surface_type)
|
let surface = device
|
||||||
|
.create_surface(&gl_context, SurfaceAccess::GPUOnly, surface_type)
|
||||||
|
.unwrap();
|
||||||
|
device
|
||||||
|
.bind_surface_to_context(&mut gl_context, surface)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
device.bind_surface_to_context(&mut gl_context, surface).unwrap();
|
|
||||||
device.make_context_current(&gl_context).unwrap();
|
device.make_context_current(&gl_context).unwrap();
|
||||||
gl::load_with(|symbol_name| device.get_proc_address(&gl_context, symbol_name));
|
gl::load_with(|symbol_name| device.get_proc_address(&gl_context, symbol_name));
|
||||||
|
|
||||||
|
@ -78,7 +88,8 @@ fn main() {
|
||||||
let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);
|
let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);
|
||||||
|
|
||||||
// Create a Pathfinder GL device.
|
// Create a Pathfinder GL device.
|
||||||
let default_framebuffer = device.context_surface_info(&gl_context)
|
let default_framebuffer = device
|
||||||
|
.context_surface_info(&gl_context)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.framebuffer_object;
|
.framebuffer_object;
|
||||||
|
@ -101,16 +112,27 @@ fn main() {
|
||||||
moire_renderer.render();
|
moire_renderer.render();
|
||||||
|
|
||||||
// Present the rendered canvas via `surfman`.
|
// Present the rendered canvas via `surfman`.
|
||||||
let mut surface = device.unbind_surface_from_context(&mut gl_context).unwrap().unwrap();
|
let mut surface = device
|
||||||
device.present_surface(&mut gl_context, &mut surface).unwrap();
|
.unbind_surface_from_context(&mut gl_context)
|
||||||
device.bind_surface_to_context(&mut gl_context, surface).unwrap();
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
device
|
||||||
|
.present_surface(&mut gl_context, &mut surface)
|
||||||
|
.unwrap();
|
||||||
|
device
|
||||||
|
.bind_surface_to_context(&mut gl_context, surface)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
event_loop.poll_events(|event| {
|
event_loop.poll_events(|event| match event {
|
||||||
match event {
|
Event::WindowEvent {
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } |
|
event: WindowEvent::CloseRequested,
|
||||||
Event::WindowEvent { event: WindowEvent::KeyboardInput { .. }, .. } => exit = true,
|
..
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
| Event::WindowEvent {
|
||||||
|
event: WindowEvent::KeyboardInput { .. },
|
||||||
|
..
|
||||||
|
} => exit = true,
|
||||||
|
_ => {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,8 +149,11 @@ struct MoireRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoireRenderer {
|
impl MoireRenderer {
|
||||||
fn new(renderer: Renderer<GLDevice>, window_size: Vector2I, drawable_size: Vector2I)
|
fn new(
|
||||||
-> MoireRenderer {
|
renderer: Renderer<GLDevice>,
|
||||||
|
window_size: Vector2I,
|
||||||
|
drawable_size: Vector2I,
|
||||||
|
) -> MoireRenderer {
|
||||||
let level = renderer.mode().level;
|
let level = renderer.mode().level;
|
||||||
MoireRenderer {
|
MoireRenderer {
|
||||||
renderer,
|
renderer,
|
||||||
|
@ -171,7 +196,8 @@ impl MoireRenderer {
|
||||||
|
|
||||||
// Build and render scene.
|
// Build and render scene.
|
||||||
self.scene.replace_scene(canvas.into_canvas().into_scene());
|
self.scene.replace_scene(canvas.into_canvas().into_scene());
|
||||||
self.scene.build_and_render(&mut self.renderer, BuildOptions::default());
|
self.scene
|
||||||
|
.build_and_render(&mut self.renderer, BuildOptions::default());
|
||||||
|
|
||||||
self.frame += 1;
|
self.frame += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
arrayvec = "0.5"
|
arrayvec = "0.5"
|
||||||
font-kit = "0.6"
|
font-kit = "0.13"
|
||||||
gl = "0.14"
|
gl = "0.14"
|
||||||
|
|
||||||
[dependencies.euclid]
|
[dependencies.euclid]
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
font-kit = "0.6"
|
font-kit = "0.13"
|
||||||
gl = "0.14"
|
gl = "0.14"
|
||||||
sdl2 = "0.33"
|
sdl2 = "0.33"
|
||||||
sdl2-sys = "0.33"
|
sdl2-sys = "0.33"
|
||||||
|
|
|
@ -18,8 +18,8 @@ use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
use pathfinder_resources::ResourceLoader;
|
|
||||||
use pathfinder_resources::fs::FilesystemResourceLoader;
|
use pathfinder_resources::fs::FilesystemResourceLoader;
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
use sdl2::event::{Event, WindowEvent};
|
use sdl2::event::{Event, WindowEvent};
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
use sdl2::video::GLProfile;
|
use sdl2::video::GLProfile;
|
||||||
|
@ -36,13 +36,16 @@ fn main() {
|
||||||
let gl_attributes = video.gl_attr();
|
let gl_attributes = video.gl_attr();
|
||||||
gl_attributes.set_context_profile(GLProfile::Core);
|
gl_attributes.set_context_profile(GLProfile::Core);
|
||||||
gl_attributes.set_context_version(4, 1);
|
gl_attributes.set_context_version(4, 1);
|
||||||
gl_attributes.set_context_flags()
|
gl_attributes.set_context_flags().forward_compatible().set();
|
||||||
.forward_compatible()
|
|
||||||
.set();
|
|
||||||
|
|
||||||
// Open a window.
|
// Open a window.
|
||||||
let window_size = vec2i(640, 480);
|
let window_size = vec2i(640, 480);
|
||||||
let window = video.window("Text example", window_size.x() as u32, window_size.y() as u32)
|
let window = video
|
||||||
|
.window(
|
||||||
|
"Text example",
|
||||||
|
window_size.x() as u32,
|
||||||
|
window_size.y() as u32,
|
||||||
|
)
|
||||||
.opengl()
|
.opengl()
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -75,10 +78,21 @@ fn main() {
|
||||||
let mut fps_buf = String::new();
|
let mut fps_buf = String::new();
|
||||||
loop {
|
loop {
|
||||||
match event_pump.poll_event() {
|
match event_pump.poll_event() {
|
||||||
Some(Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. }) => return,
|
Some(
|
||||||
Some(Event::Window { win_event: WindowEvent::Exposed, .. }) | None => {
|
Event::Quit { .. }
|
||||||
|
| Event::KeyDown {
|
||||||
|
keycode: Some(Keycode::Escape),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => return,
|
||||||
|
Some(Event::Window {
|
||||||
|
win_event: WindowEvent::Exposed,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| None => {
|
||||||
// Make a canvas.
|
// Make a canvas.
|
||||||
let mut canvas = Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone());
|
let mut canvas =
|
||||||
|
Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone());
|
||||||
|
|
||||||
// Draw the text.
|
// Draw the text.
|
||||||
canvas.set_font("Overpass-Regular").unwrap();
|
canvas.set_font("Overpass-Regular").unwrap();
|
||||||
|
@ -87,7 +101,9 @@ fn main() {
|
||||||
let elapsed = now.duration_since(last_update);
|
let elapsed = now.duration_since(last_update);
|
||||||
if elapsed >= Duration::from_millis(50) {
|
if elapsed >= Duration::from_millis(50) {
|
||||||
last_update = now;
|
last_update = now;
|
||||||
let fps = (n as f64) * ((Duration::from_secs(1).as_micros() as f64) / (elapsed.as_micros() as f64));
|
let fps = (n as f64)
|
||||||
|
* ((Duration::from_secs(1).as_micros() as f64)
|
||||||
|
/ (elapsed.as_micros() as f64));
|
||||||
fps_buf.clear();
|
fps_buf.clear();
|
||||||
fps_buf.push_str("FPS: ");
|
fps_buf.push_str("FPS: ");
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
@ -100,14 +116,16 @@ fn main() {
|
||||||
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
|
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let mut scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(),
|
let mut scene = SceneProxy::from_scene(
|
||||||
|
canvas.into_canvas().into_scene(),
|
||||||
renderer.mode().level,
|
renderer.mode().level,
|
||||||
RayonExecutor);
|
RayonExecutor,
|
||||||
|
);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
window.gl_swap_window();
|
window.gl_swap_window();
|
||||||
|
|
||||||
n += 1;
|
n += 1;
|
||||||
},
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
use pathfinder_webgl::WebGlDevice;
|
use pathfinder_webgl::WebGlDevice;
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::{self, HtmlCanvasElement, WebGl2RenderingContext};
|
use web_sys::{self, HtmlCanvasElement, WebGl2RenderingContext};
|
||||||
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
@ -32,7 +32,8 @@ pub fn rust_main() {
|
||||||
let canvas = document.get_element_by_id("c").unwrap();
|
let canvas = document.get_element_by_id("c").unwrap();
|
||||||
let canvas: HtmlCanvasElement = canvas.dyn_into::<HtmlCanvasElement>().unwrap();
|
let canvas: HtmlCanvasElement = canvas.dyn_into::<HtmlCanvasElement>().unwrap();
|
||||||
|
|
||||||
let context = canvas.get_context("webgl2")
|
let context = canvas
|
||||||
|
.get_context("webgl2")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.dyn_into::<WebGl2RenderingContext>()
|
.dyn_into::<WebGl2RenderingContext>()
|
||||||
|
|
|
@ -10,20 +10,20 @@
|
||||||
|
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f, vec2i};
|
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::options::{RenderTransform, BuildOptions};
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
|
||||||
|
use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
|
use pathfinder_swf::{draw_paths_into_scene, process_swf_tags};
|
||||||
use sdl2::event::Event;
|
use sdl2::event::Event;
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
use sdl2::video::GLProfile;
|
use sdl2::video::GLProfile;
|
||||||
use pathfinder_renderer::scene::Scene;
|
|
||||||
use pathfinder_swf::{draw_paths_into_scene, process_swf_tags};
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::read;
|
use std::fs::read;
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ fn main() {
|
||||||
match read(path) {
|
match read(path) {
|
||||||
Ok(bytes) => {
|
Ok(bytes) => {
|
||||||
swf_bytes = bytes;
|
swf_bytes = bytes;
|
||||||
},
|
}
|
||||||
Err(e) => panic!("{}", e)
|
Err(e) => panic!("{}", e),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// NOTE(jon): This is a version of the ghostscript tiger graphic flattened to a single
|
// NOTE(jon): This is a version of the ghostscript tiger graphic flattened to a single
|
||||||
|
@ -83,13 +83,21 @@ fn main() {
|
||||||
|
|
||||||
// Open a window.
|
// Open a window.
|
||||||
let window_size = vec2i(stage.width(), stage.height());
|
let window_size = vec2i(stage.width(), stage.height());
|
||||||
let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32)
|
let window = video
|
||||||
|
.window(
|
||||||
|
"Minimal example",
|
||||||
|
window_size.x() as u32,
|
||||||
|
window_size.y() as u32,
|
||||||
|
)
|
||||||
.opengl()
|
.opengl()
|
||||||
.allow_highdpi()
|
.allow_highdpi()
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let pixel_size = vec2i(window.drawable_size().0 as i32, window.drawable_size().1 as i32);
|
let pixel_size = vec2i(
|
||||||
|
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;
|
let device_pixel_ratio = pixel_size.x() as f32 / window_size.x() as f32;
|
||||||
|
|
||||||
// Create the GL context, and make it current.
|
// Create the GL context, and make it current.
|
||||||
|
@ -109,9 +117,10 @@ fn main() {
|
||||||
|
|
||||||
// Clear to swf stage background color.
|
// Clear to swf stage background color.
|
||||||
let mut scene = Scene::new();
|
let mut scene = Scene::new();
|
||||||
scene.set_view_box(RectF::new(Vector2F::zero(),
|
scene.set_view_box(RectF::new(
|
||||||
vec2f(stage.width() as f32,
|
Vector2F::zero(),
|
||||||
stage.height() as f32) * device_pixel_ratio));
|
vec2f(stage.width() as f32, stage.height() as f32) * device_pixel_ratio,
|
||||||
|
));
|
||||||
draw_paths_into_scene(&library, &mut scene);
|
draw_paths_into_scene(&library, &mut scene);
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
|
@ -126,7 +135,11 @@ fn main() {
|
||||||
let mut event_pump = sdl_context.event_pump().unwrap();
|
let mut event_pump = sdl_context.event_pump().unwrap();
|
||||||
loop {
|
loop {
|
||||||
match event_pump.wait_event() {
|
match event_pump.wait_event() {
|
||||||
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return,
|
Event::Quit { .. }
|
||||||
|
| Event::KeyDown {
|
||||||
|
keycode: Some(Keycode::Escape),
|
||||||
|
..
|
||||||
|
} => return,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use pathfinder_content::outline::ContourIterFlags;
|
use pathfinder_content::outline::ContourIterFlags;
|
||||||
use pathfinder_content::segment::SegmentKind;
|
use pathfinder_content::segment::SegmentKind;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
use pathfinder_renderer::scene::{DrawPathId, Scene};
|
use pathfinder_renderer::scene::{DrawPathId, Scene};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
@ -39,7 +39,7 @@ impl Export for Scene {
|
||||||
match format {
|
match format {
|
||||||
FileFormat::SVG => export_svg(self, writer),
|
FileFormat::SVG => export_svg(self, writer),
|
||||||
FileFormat::PDF => export_pdf(self, writer),
|
FileFormat::PDF => export_pdf(self, writer),
|
||||||
FileFormat::PS => export_ps(self, writer)
|
FileFormat::PS => export_ps(self, writer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,12 @@ fn export_svg<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
if !draw_path.name.is_empty() {
|
if !draw_path.name.is_empty() {
|
||||||
write!(writer, " id=\"{}\"", draw_path.name)?;
|
write!(writer, " id=\"{}\"", draw_path.name)?;
|
||||||
}
|
}
|
||||||
writeln!(writer, " fill=\"{:?}\" d=\"{:?}\" />", paint.base_color(), draw_path.outline)?;
|
writeln!(
|
||||||
|
writer,
|
||||||
|
" fill=\"{:?}\" d=\"{:?}\" />",
|
||||||
|
paint.base_color(),
|
||||||
|
draw_path.outline
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
writeln!(writer, "</svg>")?;
|
writeln!(writer, "</svg>")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -107,11 +112,11 @@ fn export_pdf<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
let c2 = c * (2.0 / 3.0) + p * (1.0 / 3.0);
|
let c2 = c * (2.0 / 3.0) + p * (1.0 / 3.0);
|
||||||
pdf.cubic_to(c1, c2, p);
|
pdf.cubic_to(c1, c2, p);
|
||||||
}
|
}
|
||||||
SegmentKind::Cubic => {
|
SegmentKind::Cubic => pdf.cubic_to(
|
||||||
pdf.cubic_to(tr(segment.ctrl.from()),
|
tr(segment.ctrl.from()),
|
||||||
tr(segment.ctrl.to()),
|
tr(segment.ctrl.to()),
|
||||||
tr(segment.baseline.to()))
|
tr(segment.baseline.to()),
|
||||||
}
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +141,15 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
|
|
||||||
let view_box = scene.view_box();
|
let view_box = scene.view_box();
|
||||||
writeln!(writer, "%!PS-Adobe-3.0 EPSF-3.0")?;
|
writeln!(writer, "%!PS-Adobe-3.0 EPSF-3.0")?;
|
||||||
writeln!(writer, "%%BoundingBox: {:.0} {:.0}",
|
writeln!(
|
||||||
|
writer,
|
||||||
|
"%%BoundingBox: {:.0} {:.0}",
|
||||||
P(view_box.origin()),
|
P(view_box.origin()),
|
||||||
P(view_box.size()),
|
P(view_box.size()),
|
||||||
)?;
|
)?;
|
||||||
writeln!(writer, "%%HiResBoundingBox: {} {}",
|
writeln!(
|
||||||
|
writer,
|
||||||
|
"%%HiResBoundingBox: {} {}",
|
||||||
P(view_box.origin()),
|
P(view_box.origin()),
|
||||||
P(view_box.size()),
|
P(view_box.size()),
|
||||||
)?;
|
)?;
|
||||||
|
@ -176,7 +185,9 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
writeln!(writer, "{} {} {} curveto", P(c1), P(c2), P(p))?;
|
writeln!(writer, "{} {} {} curveto", P(c1), P(c2), P(p))?;
|
||||||
}
|
}
|
||||||
SegmentKind::Cubic => {
|
SegmentKind::Cubic => {
|
||||||
writeln!(writer, "{} {} {} curveto",
|
writeln!(
|
||||||
|
writer,
|
||||||
|
"{} {} {} curveto",
|
||||||
P(segment.ctrl.from()),
|
P(segment.ctrl.from()),
|
||||||
P(segment.ctrl.to()),
|
P(segment.ctrl.to()),
|
||||||
P(segment.baseline.to())
|
P(segment.baseline.to())
|
||||||
|
@ -202,5 +213,3 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
writeln!(writer, "showpage")?;
|
writeln!(writer, "showpage")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,14 +18,11 @@ use std::io::{self, Write};
|
||||||
|
|
||||||
struct Counter<T> {
|
struct Counter<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
count: u64
|
count: u64,
|
||||||
}
|
}
|
||||||
impl<T> Counter<T> {
|
impl<T> Counter<T> {
|
||||||
pub fn new(inner: T) -> Counter<T> {
|
pub fn new(inner: T) -> Counter<T> {
|
||||||
Counter {
|
Counter { inner, count: 0 }
|
||||||
inner,
|
|
||||||
count: 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn pos(&self) -> u64 {
|
pub fn pos(&self) -> u64 {
|
||||||
self.count
|
self.count
|
||||||
|
@ -37,8 +34,8 @@ impl<W: Write> Write for Counter<W> {
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
self.count += n as u64;
|
self.count += n as u64;
|
||||||
Ok(n)
|
Ok(n)
|
||||||
},
|
}
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
@ -95,7 +92,7 @@ impl Pdf {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
page_size: None,
|
page_size: None,
|
||||||
compression: Some(Compression::Fast)
|
compression: Some(Compression::Fast),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,11 +110,14 @@ impl Pdf {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fill_color(&mut self, color: ColorU) {
|
pub fn set_fill_color(&mut self, color: ColorU) {
|
||||||
let norm = |color| f32::from(color) / 255.0;
|
let norm = |color| f32::from(color) / 255.0;
|
||||||
writeln!(self.page_buffer, "{} {} {} rg",
|
writeln!(
|
||||||
|
self.page_buffer,
|
||||||
|
"{} {} {} rg",
|
||||||
norm(color.r),
|
norm(color.r),
|
||||||
norm(color.g),
|
norm(color.g),
|
||||||
norm(color.b)
|
norm(color.b)
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move to a new page in the PDF document
|
/// Move to a new page in the PDF document
|
||||||
|
@ -143,7 +143,17 @@ impl Pdf {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cubic_to(&mut self, c1: Vector2F, c2: Vector2F, p: Vector2F) {
|
pub fn cubic_to(&mut self, c1: Vector2F, c2: Vector2F, p: Vector2F) {
|
||||||
writeln!(self.page_buffer, "{} {} {} {} {} {} c", c1.x(), c1.y(), c2.x(), c2.y(), p.x(), p.y()).unwrap();
|
writeln!(
|
||||||
|
self.page_buffer,
|
||||||
|
"{} {} {} {} {} {} c",
|
||||||
|
c1.x(),
|
||||||
|
c1.y(),
|
||||||
|
c2.x(),
|
||||||
|
c2.y(),
|
||||||
|
p.x(),
|
||||||
|
p.y()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
pub fn fill(&mut self) {
|
pub fn fill(&mut self) {
|
||||||
writeln!(self.page_buffer, "f").unwrap();
|
writeln!(self.page_buffer, "f").unwrap();
|
||||||
|
@ -156,7 +166,7 @@ impl Pdf {
|
||||||
fn end_page(&mut self) {
|
fn end_page(&mut self) {
|
||||||
let size = match self.page_size.take() {
|
let size = match self.page_size.take() {
|
||||||
Some(size) => size,
|
Some(size) => size,
|
||||||
None => return // no page started
|
None => return, // no page started
|
||||||
};
|
};
|
||||||
let page_stream = if let Some(level) = self.compression {
|
let page_stream = if let Some(level) = self.compression {
|
||||||
let compressed = deflate::deflate_bytes_zlib_conf(&self.page_buffer, level);
|
let compressed = deflate::deflate_bytes_zlib_conf(&self.page_buffer, level);
|
||||||
|
@ -185,22 +195,31 @@ impl Pdf {
|
||||||
/Resources <<\n"
|
/Resources <<\n"
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
|
||||||
for (idx, _obj) in self.objects.iter().enumerate().filter(|&(_, o)| o.is_xobject) {
|
for (idx, _obj) in self
|
||||||
|
.objects
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, o)| o.is_xobject)
|
||||||
|
{
|
||||||
write!(page_object, "/XObject {} 0 R ", idx + 1).unwrap();
|
write!(page_object, "/XObject {} 0 R ", idx + 1).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(page_object,
|
write!(
|
||||||
" >>\n \
|
page_object,
|
||||||
/MediaBox [0 0 {} {}]\n \
|
" >>\n /MediaBox [0 0 {} {}]\n /Contents {} 0 R\n>>\n",
|
||||||
/Contents {} 0 R\n\
|
size.x(),
|
||||||
>>\n",
|
size.y(),
|
||||||
size.x(), size.y(), stream_object_id
|
stream_object_id
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
self.add_object(page_object, true, false);
|
self.add_object(page_object, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the in-memory PDF representation to disk
|
/// Write the in-memory PDF representation to disk
|
||||||
pub fn write_to<W>(&mut self, writer: W) -> io::Result<()> where W: Write {
|
pub fn write_to<W>(&mut self, writer: W) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
let mut out = Counter::new(writer);
|
let mut out = Counter::new(writer);
|
||||||
out.write_all(b"%PDF-1.7\n%\xB5\xED\xAE\xFB\n")?;
|
out.write_all(b"%PDF-1.7\n%\xB5\xED\xAE\xFB\n")?;
|
||||||
|
|
||||||
|
@ -220,12 +239,18 @@ impl Pdf {
|
||||||
self.objects[1].offset = Some(out.pos());
|
self.objects[1].offset = Some(out.pos());
|
||||||
out.write_all(b"2 0 obj\n")?;
|
out.write_all(b"2 0 obj\n")?;
|
||||||
out.write_all(b"<< /Type /Pages\n")?;
|
out.write_all(b"<< /Type /Pages\n")?;
|
||||||
write!(out,
|
write!(
|
||||||
|
out,
|
||||||
"/Count {}\n",
|
"/Count {}\n",
|
||||||
self.objects.iter().filter(|o| o.is_page).count()
|
self.objects.iter().filter(|o| o.is_page).count()
|
||||||
)?;
|
)?;
|
||||||
out.write_all(b"/Kids [")?;
|
out.write_all(b"/Kids [")?;
|
||||||
for (idx, _obj) in self.objects.iter().enumerate().filter(|&(_, obj)| obj.is_page) {
|
for (idx, _obj) in self
|
||||||
|
.objects
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, obj)| obj.is_page)
|
||||||
|
{
|
||||||
write!(out, "{} 0 R ", idx + 1)?;
|
write!(out, "{} 0 R ", idx + 1)?;
|
||||||
}
|
}
|
||||||
out.write_all(b"] >>\nendobj\n")?;
|
out.write_all(b"] >>\nendobj\n")?;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use crate::transform2d::Matrix2x2F;
|
use crate::transform2d::Matrix2x2F;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::vector::{Vector2F, vec2f};
|
use crate::vector::{vec2f, Vector2F};
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::{Add, Mul, MulAssign, Sub};
|
use std::ops::{Add, Mul, MulAssign, Sub};
|
||||||
|
|
||||||
|
|
|
@ -91,13 +91,19 @@ impl RectF {
|
||||||
pub fn contains_point(self, point: Vector2F) -> bool {
|
pub fn contains_point(self, point: Vector2F) -> bool {
|
||||||
// self.origin <= point && point <= self.lower_right
|
// self.origin <= point && point <= self.lower_right
|
||||||
let point = point.0.to_f32x4();
|
let point = point.0.to_f32x4();
|
||||||
self.0.concat_xy_xy(point).packed_le(point.concat_xy_zw(self.0)).all_true()
|
self.0
|
||||||
|
.concat_xy_xy(point)
|
||||||
|
.packed_le(point.concat_xy_zw(self.0))
|
||||||
|
.all_true()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains_rect(self, other: RectF) -> bool {
|
pub fn contains_rect(self, other: RectF) -> bool {
|
||||||
// self.origin <= other.origin && other.lower_right <= self.lower_right
|
// self.origin <= other.origin && other.lower_right <= self.lower_right
|
||||||
self.0.concat_xy_zw(other.0).packed_le(other.0.concat_xy_zw(self.0)).all_true()
|
self.0
|
||||||
|
.concat_xy_zw(other.0)
|
||||||
|
.packed_le(other.0.concat_xy_zw(self.0))
|
||||||
|
.all_true()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -121,7 +127,10 @@ impl RectF {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn intersects(self, other: RectF) -> bool {
|
pub fn intersects(self, other: RectF) -> bool {
|
||||||
// self.origin < other.lower_right && other.origin < self.lower_right
|
// self.origin < other.lower_right && other.origin < self.lower_right
|
||||||
self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).all_true()
|
self.0
|
||||||
|
.concat_xy_xy(other.0)
|
||||||
|
.packed_lt(other.0.concat_zw_zw(self.0))
|
||||||
|
.all_true()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -173,13 +182,19 @@ impl RectF {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dilate<A>(self, amount: A) -> RectF where A: IntoVector2F {
|
pub fn dilate<A>(self, amount: A) -> RectF
|
||||||
|
where
|
||||||
|
A: IntoVector2F,
|
||||||
|
{
|
||||||
let amount = amount.into_vector_2f();
|
let amount = amount.into_vector_2f();
|
||||||
RectF::from_points(self.origin() - amount, self.lower_right() + amount)
|
RectF::from_points(self.origin() - amount, self.lower_right() + amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contract<A>(self, amount: A) -> RectF where A: IntoVector2F {
|
pub fn contract<A>(self, amount: A) -> RectF
|
||||||
|
where
|
||||||
|
A: IntoVector2F,
|
||||||
|
{
|
||||||
let amount = amount.into_vector_2f();
|
let amount = amount.into_vector_2f();
|
||||||
RectF::from_points(self.origin() + amount, self.lower_right() - amount)
|
RectF::from_points(self.origin() + amount, self.lower_right() - amount)
|
||||||
}
|
}
|
||||||
|
@ -380,7 +395,10 @@ impl RectI {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn intersects(self, other: RectI) -> bool {
|
pub fn intersects(self, other: RectI) -> bool {
|
||||||
// self.origin < other.lower_right && other.origin < self.lower_right
|
// self.origin < other.lower_right && other.origin < self.lower_right
|
||||||
self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).all_true()
|
self.0
|
||||||
|
.concat_xy_xy(other.0)
|
||||||
|
.packed_lt(other.0.concat_zw_zw(self.0))
|
||||||
|
.all_true()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::line_segment::LineSegment2F;
|
||||||
use crate::rect::RectF;
|
use crate::rect::RectF;
|
||||||
use crate::transform3d::Transform4F;
|
use crate::transform3d::Transform4F;
|
||||||
use crate::unit_vector::UnitVector;
|
use crate::unit_vector::UnitVector;
|
||||||
use crate::vector::{IntoVector2F, Vector2F, vec2f};
|
use crate::vector::{vec2f, IntoVector2F, Vector2F};
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::ops::{Mul, MulAssign, Sub};
|
use std::ops::{Mul, MulAssign, Sub};
|
||||||
|
|
||||||
|
@ -31,7 +31,10 @@ impl Default for Matrix2x2F {
|
||||||
|
|
||||||
impl Matrix2x2F {
|
impl Matrix2x2F {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_scale<S>(scale: S) -> Matrix2x2F where S: IntoVector2F {
|
pub fn from_scale<S>(scale: S) -> Matrix2x2F
|
||||||
|
where
|
||||||
|
S: IntoVector2F,
|
||||||
|
{
|
||||||
let scale = scale.into_vector_2f();
|
let scale = scale.into_vector_2f();
|
||||||
Matrix2x2F(F32x4::new(scale.x(), 0.0, 0.0, scale.y()))
|
Matrix2x2F(F32x4::new(scale.x(), 0.0, 0.0, scale.y()))
|
||||||
}
|
}
|
||||||
|
@ -145,7 +148,10 @@ impl Default for Transform2F {
|
||||||
|
|
||||||
impl Transform2F {
|
impl Transform2F {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_scale<S>(scale: S) -> Transform2F where S: IntoVector2F {
|
pub fn from_scale<S>(scale: S) -> Transform2F
|
||||||
|
where
|
||||||
|
S: IntoVector2F,
|
||||||
|
{
|
||||||
let scale = scale.into_vector_2f();
|
let scale = scale.into_vector_2f();
|
||||||
Transform2F {
|
Transform2F {
|
||||||
matrix: Matrix2x2F::from_scale(scale),
|
matrix: Matrix2x2F::from_scale(scale),
|
||||||
|
@ -171,12 +177,21 @@ impl Transform2F {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_translation(vector: Vector2F) -> Transform2F {
|
pub fn from_translation(vector: Vector2F) -> Transform2F {
|
||||||
Transform2F { matrix: Matrix2x2F::default(), vector }
|
Transform2F {
|
||||||
|
matrix: Matrix2x2F::default(),
|
||||||
|
vector,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_scale_rotation_translation<S>(scale: S, theta: f32, translation: Vector2F)
|
pub fn from_scale_rotation_translation<S>(
|
||||||
-> Transform2F where S: IntoVector2F {
|
scale: S,
|
||||||
|
theta: f32,
|
||||||
|
translation: Vector2F,
|
||||||
|
) -> Transform2F
|
||||||
|
where
|
||||||
|
S: IntoVector2F,
|
||||||
|
{
|
||||||
let scale = scale.into_vector_2f();
|
let scale = scale.into_vector_2f();
|
||||||
let rotation = Transform2F::from_rotation(theta);
|
let rotation = Transform2F::from_rotation(theta);
|
||||||
let translation = Transform2F::from_translation(translation);
|
let translation = Transform2F::from_translation(translation);
|
||||||
|
@ -261,7 +276,10 @@ impl Transform2F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale<S>(&self, scale: S) -> Transform2F where S: IntoVector2F {
|
pub fn scale<S>(&self, scale: S) -> Transform2F
|
||||||
|
where
|
||||||
|
S: IntoVector2F,
|
||||||
|
{
|
||||||
let scale = scale.into_vector_2f();
|
let scale = scale.into_vector_2f();
|
||||||
Transform2F::from_scale(scale) * *self
|
Transform2F::from_scale(scale) * *self
|
||||||
}
|
}
|
||||||
|
@ -294,7 +312,10 @@ impl Transform2F {
|
||||||
pub fn inverse(&self) -> Transform2F {
|
pub fn inverse(&self) -> Transform2F {
|
||||||
let matrix_inv = self.matrix.inverse();
|
let matrix_inv = self.matrix.inverse();
|
||||||
let vector_inv = -(matrix_inv * self.vector);
|
let vector_inv = -(matrix_inv * self.vector);
|
||||||
Transform2F { matrix: matrix_inv, vector: vector_inv }
|
Transform2F {
|
||||||
|
matrix: matrix_inv,
|
||||||
|
vector: vector_inv,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,10 @@ impl Transform4F {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_translation(mut translation: Vector4F) -> Transform4F {
|
pub fn from_translation(mut translation: Vector4F) -> Transform4F {
|
||||||
translation.set_w(1.0);
|
translation.set_w(1.0);
|
||||||
Transform4F { c3: translation.0, ..Transform4F::default() }
|
Transform4F {
|
||||||
|
c3: translation.0,
|
||||||
|
..Transform4F::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Optimize.
|
// TODO(pcwalton): Optimize.
|
||||||
|
@ -212,11 +215,24 @@ impl Transform4F {
|
||||||
|
|
||||||
// TODO(pcwalton): Use SIMD. This needs a matrix transpose:
|
// TODO(pcwalton): Use SIMD. This needs a matrix transpose:
|
||||||
// https://fgiesen.wordpress.com/2013/07/09/simd-transposes-1/
|
// https://fgiesen.wordpress.com/2013/07/09/simd-transposes-1/
|
||||||
let transform = Transform4F::row_major(s.x(), s.y(), s.z(), 0.0,
|
let transform = Transform4F::row_major(
|
||||||
u.x(), u.y(), u.z(), 0.0,
|
s.x(),
|
||||||
minus_f.x(), minus_f.y(), minus_f.z(), 0.0,
|
s.y(),
|
||||||
0.0, 0.0, 0.0, 1.0) *
|
s.z(),
|
||||||
Transform4F::from_translation((-eye).to_4d());
|
0.0,
|
||||||
|
u.x(),
|
||||||
|
u.y(),
|
||||||
|
u.z(),
|
||||||
|
0.0,
|
||||||
|
minus_f.x(),
|
||||||
|
minus_f.y(),
|
||||||
|
minus_f.z(),
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
) * Transform4F::from_translation((-eye).to_4d());
|
||||||
transform
|
transform
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,8 +441,8 @@ impl Mul<RectF> for Perspective {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::vector::Vector4F;
|
|
||||||
use crate::transform3d::Transform4F;
|
use crate::transform3d::Transform4F;
|
||||||
|
use crate::vector::Vector4F;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_post_mul() {
|
fn test_post_mul() {
|
||||||
|
|
|
@ -26,14 +26,20 @@ impl UnitVector {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rotate_by(&self, other: UnitVector) -> UnitVector {
|
pub fn rotate_by(&self, other: UnitVector) -> UnitVector {
|
||||||
let products = (self.0).0.to_f32x4().xyyx() * (other.0).0.to_f32x4().xyxy();
|
let products = (self.0).0.to_f32x4().xyyx() * (other.0).0.to_f32x4().xyxy();
|
||||||
UnitVector(Vector2F::new(products[0] - products[1], products[2] + products[3]))
|
UnitVector(Vector2F::new(
|
||||||
|
products[0] - products[1],
|
||||||
|
products[2] + products[3],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Angle subtraction formula.
|
/// Angle subtraction formula.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rev_rotate_by(&self, other: UnitVector) -> UnitVector {
|
pub fn rev_rotate_by(&self, other: UnitVector) -> UnitVector {
|
||||||
let products = (self.0).0.to_f32x4().xyyx() * (other.0).0.to_f32x4().xyxy();
|
let products = (self.0).0.to_f32x4().xyyx() * (other.0).0.to_f32x4().xyxy();
|
||||||
UnitVector(Vector2F::new(products[0] + products[1], products[2] - products[3]))
|
UnitVector(Vector2F::new(
|
||||||
|
products[0] + products[1],
|
||||||
|
products[2] - products[3],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Half angle formula.
|
/// Half angle formula.
|
||||||
|
@ -41,7 +47,10 @@ impl UnitVector {
|
||||||
pub fn halve_angle(&self) -> UnitVector {
|
pub fn halve_angle(&self) -> UnitVector {
|
||||||
let x = self.0.x();
|
let x = self.0.x();
|
||||||
let term = F32x2::new(x, -x);
|
let term = F32x2::new(x, -x);
|
||||||
UnitVector(Vector2F((F32x2::splat(0.5) * (F32x2::splat(1.0) + term)).max(F32x2::default())
|
UnitVector(Vector2F(
|
||||||
.sqrt()))
|
(F32x2::splat(0.5) * (F32x2::splat(1.0) + term))
|
||||||
|
.max(F32x2::default())
|
||||||
|
.sqrt(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,20 @@ impl Vector2F {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_3d(self) -> Vector3F {
|
pub fn to_3d(self) -> Vector3F {
|
||||||
Vector3F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 0.0)))
|
Vector3F(
|
||||||
|
self.0
|
||||||
|
.to_f32x4()
|
||||||
|
.concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 0.0)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_4d(self) -> Vector4F {
|
pub fn to_4d(self) -> Vector4F {
|
||||||
Vector4F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 1.0)))
|
Vector4F(
|
||||||
|
self.0
|
||||||
|
.to_f32x4()
|
||||||
|
.concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 1.0)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -458,7 +466,10 @@ impl Eq for Vector2I {}
|
||||||
|
|
||||||
impl Hash for Vector2I {
|
impl Hash for Vector2I {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
fn hash<H>(&self, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
self.x().hash(state);
|
self.x().hash(state);
|
||||||
self.y().hash(state);
|
self.y().hash(state);
|
||||||
}
|
}
|
||||||
|
|
752
gl/src/lib.rs
752
gl/src/lib.rs
File diff suppressed because it is too large
Load Diff
|
@ -11,8 +11,8 @@
|
||||||
//! GPU memory management.
|
//! GPU memory management.
|
||||||
|
|
||||||
use crate::{BufferData, BufferTarget, BufferUploadMode, Device, TextureFormat};
|
use crate::{BufferData, BufferTarget, BufferUploadMode, Device, TextureFormat};
|
||||||
use instant::Instant;
|
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
|
use instant::Instant;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
@ -31,7 +31,10 @@ const DECAY_TIME: f32 = 0.250;
|
||||||
// This helps avoid stalls. This is admittedly a bit of a hack.
|
// This helps avoid stalls. This is admittedly a bit of a hack.
|
||||||
const REUSE_TIME: f32 = 0.015;
|
const REUSE_TIME: f32 = 0.015;
|
||||||
|
|
||||||
pub struct GPUMemoryAllocator<D> where D: Device {
|
pub struct GPUMemoryAllocator<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
general_buffers_in_use: FxHashMap<GeneralBufferID, BufferAllocation<D>>,
|
general_buffers_in_use: FxHashMap<GeneralBufferID, BufferAllocation<D>>,
|
||||||
index_buffers_in_use: FxHashMap<IndexBufferID, BufferAllocation<D>>,
|
index_buffers_in_use: FxHashMap<IndexBufferID, BufferAllocation<D>>,
|
||||||
textures_in_use: FxHashMap<TextureID, TextureAllocation<D>>,
|
textures_in_use: FxHashMap<TextureID, TextureAllocation<D>>,
|
||||||
|
@ -45,34 +48,61 @@ pub struct GPUMemoryAllocator<D> where D: Device {
|
||||||
bytes_allocated: u64,
|
bytes_allocated: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BufferAllocation<D> where D: Device {
|
struct BufferAllocation<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
buffer: D::Buffer,
|
buffer: D::Buffer,
|
||||||
size: u64,
|
size: u64,
|
||||||
tag: BufferTag,
|
tag: BufferTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TextureAllocation<D> where D: Device {
|
struct TextureAllocation<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
texture: D::Texture,
|
texture: D::Texture,
|
||||||
descriptor: TextureDescriptor,
|
descriptor: TextureDescriptor,
|
||||||
tag: TextureTag,
|
tag: TextureTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FramebufferAllocation<D> where D: Device {
|
struct FramebufferAllocation<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
framebuffer: D::Framebuffer,
|
framebuffer: D::Framebuffer,
|
||||||
descriptor: TextureDescriptor,
|
descriptor: TextureDescriptor,
|
||||||
tag: FramebufferTag,
|
tag: FramebufferTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FreeObject<D> where D: Device {
|
struct FreeObject<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
timestamp: Instant,
|
timestamp: Instant,
|
||||||
kind: FreeObjectKind<D>,
|
kind: FreeObjectKind<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FreeObjectKind<D> where D: Device {
|
enum FreeObjectKind<D>
|
||||||
GeneralBuffer { id: GeneralBufferID, allocation: BufferAllocation<D> },
|
where
|
||||||
IndexBuffer { id: IndexBufferID, allocation: BufferAllocation<D> },
|
D: Device,
|
||||||
Texture { id: TextureID, allocation: TextureAllocation<D> },
|
{
|
||||||
Framebuffer { id: FramebufferID, allocation: FramebufferAllocation<D> },
|
GeneralBuffer {
|
||||||
|
id: GeneralBufferID,
|
||||||
|
allocation: BufferAllocation<D>,
|
||||||
|
},
|
||||||
|
IndexBuffer {
|
||||||
|
id: IndexBufferID,
|
||||||
|
allocation: BufferAllocation<D>,
|
||||||
|
},
|
||||||
|
Texture {
|
||||||
|
id: TextureID,
|
||||||
|
allocation: TextureAllocation<D>,
|
||||||
|
},
|
||||||
|
Framebuffer {
|
||||||
|
id: FramebufferID,
|
||||||
|
allocation: FramebufferAllocation<D>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -108,7 +138,10 @@ pub struct TextureTag(pub &'static str);
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct FramebufferTag(pub &'static str);
|
pub struct FramebufferTag(pub &'static str);
|
||||||
|
|
||||||
impl<D> GPUMemoryAllocator<D> where D: Device {
|
impl<D> GPUMemoryAllocator<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub fn new() -> GPUMemoryAllocator<D> {
|
pub fn new() -> GPUMemoryAllocator<D> {
|
||||||
GPUMemoryAllocator {
|
GPUMemoryAllocator {
|
||||||
general_buffers_in_use: FxHashMap::default(),
|
general_buffers_in_use: FxHashMap::default(),
|
||||||
|
@ -125,8 +158,12 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_general_buffer<T>(&mut self, device: &D, size: u64, tag: BufferTag)
|
pub fn allocate_general_buffer<T>(
|
||||||
-> GeneralBufferID {
|
&mut self,
|
||||||
|
device: &D,
|
||||||
|
size: u64,
|
||||||
|
tag: BufferTag,
|
||||||
|
) -> GeneralBufferID {
|
||||||
let mut byte_size = size * mem::size_of::<T>() as u64;
|
let mut byte_size = size * mem::size_of::<T>() as u64;
|
||||||
if byte_size < MAX_BUFFER_SIZE_CLASS {
|
if byte_size < MAX_BUFFER_SIZE_CLASS {
|
||||||
byte_size = byte_size.next_power_of_two();
|
byte_size = byte_size.next_power_of_two();
|
||||||
|
@ -139,8 +176,8 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
FreeObject {
|
FreeObject {
|
||||||
ref timestamp,
|
ref timestamp,
|
||||||
kind: FreeObjectKind::GeneralBuffer { ref allocation, .. },
|
kind: FreeObjectKind::GeneralBuffer { ref allocation, .. },
|
||||||
} if allocation.size == byte_size &&
|
} if allocation.size == byte_size
|
||||||
(now - *timestamp).as_secs_f32() >= REUSE_TIME => {}
|
&& (now - *timestamp).as_secs_f32() >= REUSE_TIME => {}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,9 +185,7 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
Some(FreeObject {
|
Some(FreeObject {
|
||||||
kind: FreeObjectKind::GeneralBuffer { id, allocation },
|
kind: FreeObjectKind::GeneralBuffer { id, allocation },
|
||||||
..
|
..
|
||||||
}) => {
|
}) => (id, allocation),
|
||||||
(id, allocation)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -161,29 +196,44 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
let buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
||||||
device.allocate_buffer::<u8>(&buffer,
|
device.allocate_buffer::<u8>(
|
||||||
|
&buffer,
|
||||||
BufferData::Uninitialized(byte_size as usize),
|
BufferData::Uninitialized(byte_size as usize),
|
||||||
BufferTarget::Vertex);
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
|
||||||
let id = self.next_general_buffer_id;
|
let id = self.next_general_buffer_id;
|
||||||
self.next_general_buffer_id.0 += 1;
|
self.next_general_buffer_id.0 += 1;
|
||||||
|
|
||||||
debug!("mapping general buffer: {:?} {} ({}x{}) {:?}",
|
debug!(
|
||||||
|
"mapping general buffer: {:?} {} ({}x{}) {:?}",
|
||||||
id,
|
id,
|
||||||
byte_size,
|
byte_size,
|
||||||
size,
|
size,
|
||||||
mem::size_of::<T>(),
|
mem::size_of::<T>(),
|
||||||
tag);
|
tag
|
||||||
|
);
|
||||||
|
|
||||||
self.general_buffers_in_use.insert(id, BufferAllocation { buffer, size: byte_size, tag });
|
self.general_buffers_in_use.insert(
|
||||||
|
id,
|
||||||
|
BufferAllocation {
|
||||||
|
buffer,
|
||||||
|
size: byte_size,
|
||||||
|
tag,
|
||||||
|
},
|
||||||
|
);
|
||||||
self.bytes_allocated += byte_size;
|
self.bytes_allocated += byte_size;
|
||||||
self.bytes_committed += byte_size;
|
self.bytes_committed += byte_size;
|
||||||
|
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_index_buffer<T>(&mut self, device: &D, size: u64, tag: BufferTag)
|
pub fn allocate_index_buffer<T>(
|
||||||
-> IndexBufferID {
|
&mut self,
|
||||||
|
device: &D,
|
||||||
|
size: u64,
|
||||||
|
tag: BufferTag,
|
||||||
|
) -> IndexBufferID {
|
||||||
let mut byte_size = size * mem::size_of::<T>() as u64;
|
let mut byte_size = size * mem::size_of::<T>() as u64;
|
||||||
if byte_size < MAX_BUFFER_SIZE_CLASS {
|
if byte_size < MAX_BUFFER_SIZE_CLASS {
|
||||||
byte_size = byte_size.next_power_of_two();
|
byte_size = byte_size.next_power_of_two();
|
||||||
|
@ -196,15 +246,16 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
FreeObject {
|
FreeObject {
|
||||||
ref timestamp,
|
ref timestamp,
|
||||||
kind: FreeObjectKind::IndexBuffer { ref allocation, .. },
|
kind: FreeObjectKind::IndexBuffer { ref allocation, .. },
|
||||||
} if allocation.size == byte_size &&
|
} if allocation.size == byte_size
|
||||||
(now - *timestamp).as_secs_f32() >= REUSE_TIME => {}
|
&& (now - *timestamp).as_secs_f32() >= REUSE_TIME => {}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
||||||
Some(FreeObject { kind: FreeObjectKind::IndexBuffer { id, allocation }, .. }) => {
|
Some(FreeObject {
|
||||||
(id, allocation)
|
kind: FreeObjectKind::IndexBuffer { id, allocation },
|
||||||
}
|
..
|
||||||
|
}) => (id, allocation),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -215,33 +266,45 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
let buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
||||||
device.allocate_buffer::<u8>(&buffer,
|
device.allocate_buffer::<u8>(
|
||||||
|
&buffer,
|
||||||
BufferData::Uninitialized(byte_size as usize),
|
BufferData::Uninitialized(byte_size as usize),
|
||||||
BufferTarget::Index);
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
let id = self.next_index_buffer_id;
|
let id = self.next_index_buffer_id;
|
||||||
self.next_index_buffer_id.0 += 1;
|
self.next_index_buffer_id.0 += 1;
|
||||||
|
|
||||||
debug!("mapping index buffer: {:?} {} ({}x{}) {:?}",
|
debug!(
|
||||||
|
"mapping index buffer: {:?} {} ({}x{}) {:?}",
|
||||||
id,
|
id,
|
||||||
byte_size,
|
byte_size,
|
||||||
size,
|
size,
|
||||||
mem::size_of::<T>(),
|
mem::size_of::<T>(),
|
||||||
tag);
|
tag
|
||||||
|
);
|
||||||
|
|
||||||
self.index_buffers_in_use.insert(id, BufferAllocation { buffer, size: byte_size, tag });
|
self.index_buffers_in_use.insert(
|
||||||
|
id,
|
||||||
|
BufferAllocation {
|
||||||
|
buffer,
|
||||||
|
size: byte_size,
|
||||||
|
tag,
|
||||||
|
},
|
||||||
|
);
|
||||||
self.bytes_allocated += byte_size;
|
self.bytes_allocated += byte_size;
|
||||||
self.bytes_committed += byte_size;
|
self.bytes_committed += byte_size;
|
||||||
|
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_texture(&mut self,
|
pub fn allocate_texture(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
size: Vector2I,
|
size: Vector2I,
|
||||||
format: TextureFormat,
|
format: TextureFormat,
|
||||||
tag: TextureTag)
|
tag: TextureTag,
|
||||||
-> TextureID {
|
) -> TextureID {
|
||||||
let descriptor = TextureDescriptor {
|
let descriptor = TextureDescriptor {
|
||||||
width: size.x() as u32,
|
width: size.x() as u32,
|
||||||
height: size.y() as u32,
|
height: size.y() as u32,
|
||||||
|
@ -251,15 +314,18 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
|
|
||||||
for free_object_index in 0..self.free_objects.len() {
|
for free_object_index in 0..self.free_objects.len() {
|
||||||
match self.free_objects[free_object_index] {
|
match self.free_objects[free_object_index] {
|
||||||
FreeObject { kind: FreeObjectKind::Texture { ref allocation, .. }, .. } if
|
FreeObject {
|
||||||
allocation.descriptor == descriptor => {}
|
kind: FreeObjectKind::Texture { ref allocation, .. },
|
||||||
|
..
|
||||||
|
} if allocation.descriptor == descriptor => {}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
||||||
Some(FreeObject { kind: FreeObjectKind::Texture { id, allocation }, .. }) => {
|
Some(FreeObject {
|
||||||
(id, allocation)
|
kind: FreeObjectKind::Texture { id, allocation },
|
||||||
}
|
..
|
||||||
|
}) => (id, allocation),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -275,7 +341,14 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
let id = self.next_texture_id;
|
let id = self.next_texture_id;
|
||||||
self.next_texture_id.0 += 1;
|
self.next_texture_id.0 += 1;
|
||||||
|
|
||||||
self.textures_in_use.insert(id, TextureAllocation { texture, descriptor, tag });
|
self.textures_in_use.insert(
|
||||||
|
id,
|
||||||
|
TextureAllocation {
|
||||||
|
texture,
|
||||||
|
descriptor,
|
||||||
|
tag,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
self.bytes_allocated += byte_size;
|
self.bytes_allocated += byte_size;
|
||||||
self.bytes_committed += byte_size;
|
self.bytes_committed += byte_size;
|
||||||
|
@ -283,12 +356,13 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_framebuffer(&mut self,
|
pub fn allocate_framebuffer(
|
||||||
|
&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
size: Vector2I,
|
size: Vector2I,
|
||||||
format: TextureFormat,
|
format: TextureFormat,
|
||||||
tag: FramebufferTag)
|
tag: FramebufferTag,
|
||||||
-> FramebufferID {
|
) -> FramebufferID {
|
||||||
let descriptor = TextureDescriptor {
|
let descriptor = TextureDescriptor {
|
||||||
width: size.x() as u32,
|
width: size.x() as u32,
|
||||||
height: size.y() as u32,
|
height: size.y() as u32,
|
||||||
|
@ -298,15 +372,16 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
|
|
||||||
for free_object_index in 0..self.free_objects.len() {
|
for free_object_index in 0..self.free_objects.len() {
|
||||||
match self.free_objects[free_object_index].kind {
|
match self.free_objects[free_object_index].kind {
|
||||||
FreeObjectKind::Framebuffer { ref allocation, .. } if allocation.descriptor ==
|
FreeObjectKind::Framebuffer { ref allocation, .. }
|
||||||
descriptor => {}
|
if allocation.descriptor == descriptor => {}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
||||||
Some(FreeObject { kind: FreeObjectKind::Framebuffer { id, allocation }, .. }) => {
|
Some(FreeObject {
|
||||||
(id, allocation)
|
kind: FreeObjectKind::Framebuffer { id, allocation },
|
||||||
}
|
..
|
||||||
|
}) => (id, allocation),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -323,11 +398,14 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
let id = self.next_framebuffer_id;
|
let id = self.next_framebuffer_id;
|
||||||
self.next_framebuffer_id.0 += 1;
|
self.next_framebuffer_id.0 += 1;
|
||||||
|
|
||||||
self.framebuffers_in_use.insert(id, FramebufferAllocation {
|
self.framebuffers_in_use.insert(
|
||||||
|
id,
|
||||||
|
FramebufferAllocation {
|
||||||
framebuffer,
|
framebuffer,
|
||||||
descriptor,
|
descriptor,
|
||||||
tag,
|
tag,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
self.bytes_allocated += byte_size;
|
self.bytes_allocated += byte_size;
|
||||||
self.bytes_committed += byte_size;
|
self.bytes_committed += byte_size;
|
||||||
|
@ -339,8 +417,8 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
loop {
|
loop {
|
||||||
match self.free_objects.front() {
|
match self.free_objects.front() {
|
||||||
Some(FreeObject { timestamp, .. }) if (now - *timestamp).as_secs_f32() >=
|
Some(FreeObject { timestamp, .. })
|
||||||
DECAY_TIME => {}
|
if (now - *timestamp).as_secs_f32() >= DECAY_TIME => {}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
match self.free_objects.pop_front() {
|
match self.free_objects.pop_front() {
|
||||||
|
@ -352,15 +430,24 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
debug!("purging general buffer: {}", allocation.size);
|
debug!("purging general buffer: {}", allocation.size);
|
||||||
self.bytes_allocated -= allocation.size;
|
self.bytes_allocated -= allocation.size;
|
||||||
}
|
}
|
||||||
Some(FreeObject { kind: FreeObjectKind::IndexBuffer { allocation, .. }, .. }) => {
|
Some(FreeObject {
|
||||||
|
kind: FreeObjectKind::IndexBuffer { allocation, .. },
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
debug!("purging index buffer: {}", allocation.size);
|
debug!("purging index buffer: {}", allocation.size);
|
||||||
self.bytes_allocated -= allocation.size;
|
self.bytes_allocated -= allocation.size;
|
||||||
}
|
}
|
||||||
Some(FreeObject { kind: FreeObjectKind::Texture { allocation, .. }, .. }) => {
|
Some(FreeObject {
|
||||||
|
kind: FreeObjectKind::Texture { allocation, .. },
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
debug!("purging texture: {:?}", allocation.descriptor);
|
debug!("purging texture: {:?}", allocation.descriptor);
|
||||||
self.bytes_allocated -= allocation.descriptor.byte_size();
|
self.bytes_allocated -= allocation.descriptor.byte_size();
|
||||||
}
|
}
|
||||||
Some(FreeObject { kind: FreeObjectKind::Framebuffer { allocation, .. }, .. }) => {
|
Some(FreeObject {
|
||||||
|
kind: FreeObjectKind::Framebuffer { allocation, .. },
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
debug!("purging framebuffer: {:?}", allocation.descriptor);
|
debug!("purging framebuffer: {:?}", allocation.descriptor);
|
||||||
self.bytes_allocated -= allocation.descriptor.byte_size();
|
self.bytes_allocated -= allocation.descriptor.byte_size();
|
||||||
}
|
}
|
||||||
|
@ -369,7 +456,8 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_general_buffer(&mut self, id: GeneralBufferID) {
|
pub fn free_general_buffer(&mut self, id: GeneralBufferID) {
|
||||||
let allocation = self.general_buffers_in_use
|
let allocation = self
|
||||||
|
.general_buffers_in_use
|
||||||
.remove(&id)
|
.remove(&id)
|
||||||
.expect("Attempted to free unallocated general buffer!");
|
.expect("Attempted to free unallocated general buffer!");
|
||||||
self.bytes_committed -= allocation.size;
|
self.bytes_committed -= allocation.size;
|
||||||
|
@ -380,7 +468,8 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_index_buffer(&mut self, id: IndexBufferID) {
|
pub fn free_index_buffer(&mut self, id: IndexBufferID) {
|
||||||
let allocation = self.index_buffers_in_use
|
let allocation = self
|
||||||
|
.index_buffers_in_use
|
||||||
.remove(&id)
|
.remove(&id)
|
||||||
.expect("Attempted to free unallocated index buffer!");
|
.expect("Attempted to free unallocated index buffer!");
|
||||||
self.bytes_committed -= allocation.size;
|
self.bytes_committed -= allocation.size;
|
||||||
|
@ -391,7 +480,8 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_texture(&mut self, id: TextureID) {
|
pub fn free_texture(&mut self, id: TextureID) {
|
||||||
let allocation = self.textures_in_use
|
let allocation = self
|
||||||
|
.textures_in_use
|
||||||
.remove(&id)
|
.remove(&id)
|
||||||
.expect("Attempted to free unallocated texture!");
|
.expect("Attempted to free unallocated texture!");
|
||||||
let byte_size = allocation.descriptor.byte_size();
|
let byte_size = allocation.descriptor.byte_size();
|
||||||
|
@ -403,7 +493,8 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_framebuffer(&mut self, id: FramebufferID) {
|
pub fn free_framebuffer(&mut self, id: FramebufferID) {
|
||||||
let allocation = self.framebuffers_in_use
|
let allocation = self
|
||||||
|
.framebuffers_in_use
|
||||||
.remove(&id)
|
.remove(&id)
|
||||||
.expect("Attempted to free unallocated framebuffer!");
|
.expect("Attempted to free unallocated framebuffer!");
|
||||||
let byte_size = allocation.descriptor.byte_size();
|
let byte_size = allocation.descriptor.byte_size();
|
||||||
|
@ -450,7 +541,10 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
ids.sort();
|
ids.sort();
|
||||||
for id in ids {
|
for id in ids {
|
||||||
let allocation = &self.general_buffers_in_use[&id];
|
let allocation = &self.general_buffers_in_use[&id];
|
||||||
println!("id {:?}: {:?} ({:?} B)", id, allocation.tag, allocation.size);
|
println!(
|
||||||
|
"id {:?}: {:?} ({:?} B)",
|
||||||
|
id, allocation.tag, allocation.size
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Index buffers:");
|
println!("Index buffers:");
|
||||||
|
@ -458,7 +552,10 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
ids.sort();
|
ids.sort();
|
||||||
for id in ids {
|
for id in ids {
|
||||||
let allocation = &self.index_buffers_in_use[&id];
|
let allocation = &self.index_buffers_in_use[&id];
|
||||||
println!("id {:?}: {:?} ({:?} B)", id, allocation.tag, allocation.size);
|
println!(
|
||||||
|
"id {:?}: {:?} ({:?} B)",
|
||||||
|
id, allocation.tag, allocation.size
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Textures:");
|
println!("Textures:");
|
||||||
|
@ -466,13 +563,15 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
ids.sort();
|
ids.sort();
|
||||||
for id in ids {
|
for id in ids {
|
||||||
let allocation = &self.textures_in_use[&id];
|
let allocation = &self.textures_in_use[&id];
|
||||||
println!("id {:?}: {:?} {:?}x{:?} {:?} ({:?} B)",
|
println!(
|
||||||
|
"id {:?}: {:?} {:?}x{:?} {:?} ({:?} B)",
|
||||||
id,
|
id,
|
||||||
allocation.tag,
|
allocation.tag,
|
||||||
allocation.descriptor.width,
|
allocation.descriptor.width,
|
||||||
allocation.descriptor.height,
|
allocation.descriptor.height,
|
||||||
allocation.descriptor.format,
|
allocation.descriptor.format,
|
||||||
allocation.descriptor.byte_size());
|
allocation.descriptor.byte_size()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Framebuffers:");
|
println!("Framebuffers:");
|
||||||
|
@ -480,13 +579,15 @@ impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
ids.sort();
|
ids.sort();
|
||||||
for id in ids {
|
for id in ids {
|
||||||
let allocation = &self.framebuffers_in_use[&id];
|
let allocation = &self.framebuffers_in_use[&id];
|
||||||
println!("id {:?}: {:?} {:?}x{:?} {:?} ({:?} B)",
|
println!(
|
||||||
|
"id {:?}: {:?} {:?}x{:?} {:?} ({:?} B)",
|
||||||
id,
|
id,
|
||||||
allocation.tag,
|
allocation.tag,
|
||||||
allocation.descriptor.width,
|
allocation.descriptor.width,
|
||||||
allocation.descriptor.height,
|
allocation.descriptor.height,
|
||||||
allocation.descriptor.format,
|
allocation.descriptor.format,
|
||||||
allocation.descriptor.byte_size());
|
allocation.descriptor.byte_size()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
144
gpu/src/lib.rs
144
gpu/src/lib.rs
|
@ -22,7 +22,7 @@ use image::ImageFormat;
|
||||||
use pathfinder_color::ColorF;
|
use pathfinder_color::ColorF;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::Transform4F;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{vec2i, Vector2I};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_simd::default::{F32x2, F32x4, I32x2};
|
use pathfinder_simd::default::{F32x2, F32x4, I32x2};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -50,64 +50,95 @@ pub trait Device: Sized {
|
||||||
fn device_name(&self) -> String;
|
fn device_name(&self) -> String;
|
||||||
fn feature_level(&self) -> FeatureLevel;
|
fn feature_level(&self) -> FeatureLevel;
|
||||||
fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture;
|
fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture;
|
||||||
fn create_texture_from_data(&self, format: TextureFormat, size: Vector2I, data: TextureDataRef)
|
fn create_texture_from_data(
|
||||||
-> Self::Texture;
|
&self,
|
||||||
fn create_shader(&self, resources: &dyn ResourceLoader, name: &str, kind: ShaderKind)
|
format: TextureFormat,
|
||||||
-> Self::Shader;
|
size: Vector2I,
|
||||||
fn create_shader_from_source(&self, name: &str, source: &[u8], kind: ShaderKind)
|
data: TextureDataRef,
|
||||||
-> Self::Shader;
|
) -> Self::Texture;
|
||||||
fn create_vertex_array(&self) -> Self::VertexArray;
|
fn create_shader(
|
||||||
fn create_program_from_shaders(&self,
|
&self,
|
||||||
resources: &dyn ResourceLoader,
|
resources: &dyn ResourceLoader,
|
||||||
name: &str,
|
name: &str,
|
||||||
shaders: ProgramKind<Self::Shader>)
|
kind: ShaderKind,
|
||||||
-> Self::Program;
|
) -> Self::Shader;
|
||||||
fn set_compute_program_local_size(&self,
|
fn create_shader_from_source(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
source: &[u8],
|
||||||
|
kind: ShaderKind,
|
||||||
|
) -> Self::Shader;
|
||||||
|
fn create_vertex_array(&self) -> Self::VertexArray;
|
||||||
|
fn create_program_from_shaders(
|
||||||
|
&self,
|
||||||
|
resources: &dyn ResourceLoader,
|
||||||
|
name: &str,
|
||||||
|
shaders: ProgramKind<Self::Shader>,
|
||||||
|
) -> Self::Program;
|
||||||
|
fn set_compute_program_local_size(
|
||||||
|
&self,
|
||||||
program: &mut Self::Program,
|
program: &mut Self::Program,
|
||||||
local_size: ComputeDimensions);
|
local_size: ComputeDimensions,
|
||||||
|
);
|
||||||
fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option<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 get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform;
|
||||||
fn get_texture_parameter(&self, program: &Self::Program, name: &str) -> Self::TextureParameter;
|
fn get_texture_parameter(&self, program: &Self::Program, name: &str) -> Self::TextureParameter;
|
||||||
fn get_image_parameter(&self, program: &Self::Program, name: &str) -> Self::ImageParameter;
|
fn get_image_parameter(&self, program: &Self::Program, name: &str) -> Self::ImageParameter;
|
||||||
fn get_storage_buffer(&self, program: &Self::Program, name: &str, binding: u32)
|
fn get_storage_buffer(
|
||||||
-> Self::StorageBuffer;
|
&self,
|
||||||
fn bind_buffer(&self,
|
program: &Self::Program,
|
||||||
|
name: &str,
|
||||||
|
binding: u32,
|
||||||
|
) -> Self::StorageBuffer;
|
||||||
|
fn bind_buffer(
|
||||||
|
&self,
|
||||||
vertex_array: &Self::VertexArray,
|
vertex_array: &Self::VertexArray,
|
||||||
buffer: &Self::Buffer,
|
buffer: &Self::Buffer,
|
||||||
target: BufferTarget);
|
target: BufferTarget,
|
||||||
fn configure_vertex_attr(&self,
|
);
|
||||||
|
fn configure_vertex_attr(
|
||||||
|
&self,
|
||||||
vertex_array: &Self::VertexArray,
|
vertex_array: &Self::VertexArray,
|
||||||
attr: &Self::VertexAttr,
|
attr: &Self::VertexAttr,
|
||||||
descriptor: &VertexAttrDescriptor);
|
descriptor: &VertexAttrDescriptor,
|
||||||
|
);
|
||||||
fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer;
|
fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer;
|
||||||
fn create_buffer(&self, mode: BufferUploadMode) -> Self::Buffer;
|
fn create_buffer(&self, mode: BufferUploadMode) -> Self::Buffer;
|
||||||
fn allocate_buffer<T>(&self,
|
fn allocate_buffer<T>(&self, buffer: &Self::Buffer, data: BufferData<T>, target: BufferTarget);
|
||||||
buffer: &Self::Buffer,
|
fn upload_to_buffer<T>(
|
||||||
data: BufferData<T>,
|
&self,
|
||||||
target: BufferTarget);
|
|
||||||
fn upload_to_buffer<T>(&self,
|
|
||||||
buffer: &Self::Buffer,
|
buffer: &Self::Buffer,
|
||||||
position: usize,
|
position: usize,
|
||||||
data: &[T],
|
data: &[T],
|
||||||
target: BufferTarget);
|
target: BufferTarget,
|
||||||
|
);
|
||||||
fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture;
|
fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture;
|
||||||
fn destroy_framebuffer(&self, framebuffer: Self::Framebuffer) -> Self::Texture;
|
fn destroy_framebuffer(&self, framebuffer: Self::Framebuffer) -> Self::Texture;
|
||||||
fn texture_format(&self, texture: &Self::Texture) -> TextureFormat;
|
fn texture_format(&self, texture: &Self::Texture) -> TextureFormat;
|
||||||
fn texture_size(&self, texture: &Self::Texture) -> Vector2I;
|
fn texture_size(&self, texture: &Self::Texture) -> Vector2I;
|
||||||
fn set_texture_sampling_mode(&self, texture: &Self::Texture, flags: TextureSamplingFlags);
|
fn set_texture_sampling_mode(&self, texture: &Self::Texture, flags: TextureSamplingFlags);
|
||||||
fn upload_to_texture(&self, texture: &Self::Texture, rect: RectI, data: TextureDataRef);
|
fn upload_to_texture(&self, texture: &Self::Texture, rect: RectI, data: TextureDataRef);
|
||||||
fn read_pixels(&self, target: &RenderTarget<Self>, viewport: RectI)
|
fn read_pixels(
|
||||||
-> Self::TextureDataReceiver;
|
&self,
|
||||||
fn read_buffer(&self, buffer: &Self::Buffer, target: BufferTarget, range: Range<usize>)
|
target: &RenderTarget<Self>,
|
||||||
-> Self::BufferDataReceiver;
|
viewport: RectI,
|
||||||
|
) -> Self::TextureDataReceiver;
|
||||||
|
fn read_buffer(
|
||||||
|
&self,
|
||||||
|
buffer: &Self::Buffer,
|
||||||
|
target: BufferTarget,
|
||||||
|
range: Range<usize>,
|
||||||
|
) -> Self::BufferDataReceiver;
|
||||||
fn begin_commands(&self);
|
fn begin_commands(&self);
|
||||||
fn end_commands(&self);
|
fn end_commands(&self);
|
||||||
fn draw_arrays(&self, index_count: u32, render_state: &RenderState<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(&self, index_count: u32, render_state: &RenderState<Self>);
|
||||||
fn draw_elements_instanced(&self,
|
fn draw_elements_instanced(
|
||||||
|
&self,
|
||||||
index_count: u32,
|
index_count: u32,
|
||||||
instance_count: u32,
|
instance_count: u32,
|
||||||
render_state: &RenderState<Self>);
|
render_state: &RenderState<Self>,
|
||||||
|
);
|
||||||
fn dispatch_compute(&self, dimensions: ComputeDimensions, state: &ComputeState<Self>);
|
fn dispatch_compute(&self, dimensions: ComputeDimensions, state: &ComputeState<Self>);
|
||||||
fn add_fence(&self) -> Self::Fence;
|
fn add_fence(&self) -> Self::Fence;
|
||||||
fn wait_for_fence(&self, fence: &Self::Fence);
|
fn wait_for_fence(&self, fence: &Self::Fence);
|
||||||
|
@ -121,11 +152,12 @@ pub trait Device: Sized {
|
||||||
fn try_recv_buffer(&self, receiver: &Self::BufferDataReceiver) -> Option<Vec<u8>>;
|
fn try_recv_buffer(&self, receiver: &Self::BufferDataReceiver) -> Option<Vec<u8>>;
|
||||||
fn recv_buffer(&self, receiver: &Self::BufferDataReceiver) -> Vec<u8>;
|
fn recv_buffer(&self, receiver: &Self::BufferDataReceiver) -> Vec<u8>;
|
||||||
|
|
||||||
fn create_texture_from_png(&self,
|
fn create_texture_from_png(
|
||||||
|
&self,
|
||||||
resources: &dyn ResourceLoader,
|
resources: &dyn ResourceLoader,
|
||||||
name: &str,
|
name: &str,
|
||||||
format: TextureFormat)
|
format: TextureFormat,
|
||||||
-> Self::Texture {
|
) -> Self::Texture {
|
||||||
let data = resources.slurp(&format!("textures/{}.png", name)).unwrap();
|
let data = resources.slurp(&format!("textures/{}.png", name)).unwrap();
|
||||||
let image = image::load_from_memory_with_format(&data, ImageFormat::Png).unwrap();
|
let image = image::load_from_memory_with_format(&data, ImageFormat::Png).unwrap();
|
||||||
match format {
|
match format {
|
||||||
|
@ -143,11 +175,13 @@ pub trait Device: Sized {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_png_to_texture(&self,
|
fn upload_png_to_texture(
|
||||||
|
&self,
|
||||||
resources: &dyn ResourceLoader,
|
resources: &dyn ResourceLoader,
|
||||||
name: &str,
|
name: &str,
|
||||||
texture: &Self::Texture,
|
texture: &Self::Texture,
|
||||||
format: TextureFormat) {
|
format: TextureFormat,
|
||||||
|
) {
|
||||||
let data = resources.slurp(&format!("textures/{}.png", name)).unwrap();
|
let data = resources.slurp(&format!("textures/{}.png", name)).unwrap();
|
||||||
let image = image::load_from_memory_with_format(&data, ImageFormat::Png).unwrap();
|
let image = image::load_from_memory_with_format(&data, ImageFormat::Png).unwrap();
|
||||||
match format {
|
match format {
|
||||||
|
@ -174,12 +208,10 @@ pub trait Device: Sized {
|
||||||
shader_names: ProgramKind<&str>,
|
shader_names: ProgramKind<&str>,
|
||||||
) -> Self::Program {
|
) -> Self::Program {
|
||||||
let shaders = match shader_names {
|
let shaders = match shader_names {
|
||||||
ProgramKind::Raster { vertex, fragment } => {
|
ProgramKind::Raster { vertex, fragment } => ProgramKind::Raster {
|
||||||
ProgramKind::Raster {
|
|
||||||
vertex: self.create_shader(resources, vertex, ShaderKind::Vertex),
|
vertex: self.create_shader(resources, vertex, ShaderKind::Vertex),
|
||||||
fragment: self.create_shader(resources, fragment, ShaderKind::Fragment),
|
fragment: self.create_shader(resources, fragment, ShaderKind::Fragment),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
ProgramKind::Compute(compute) => {
|
ProgramKind::Compute(compute) => {
|
||||||
ProgramKind::Compute(self.create_shader(resources, compute, ShaderKind::Compute))
|
ProgramKind::Compute(self.create_shader(resources, compute, ShaderKind::Compute))
|
||||||
}
|
}
|
||||||
|
@ -188,7 +220,10 @@ pub trait Device: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_raster_program(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Program {
|
fn create_raster_program(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Program {
|
||||||
let shaders = ProgramKind::Raster { vertex: name, fragment: name };
|
let shaders = ProgramKind::Raster {
|
||||||
|
vertex: name,
|
||||||
|
fragment: name,
|
||||||
|
};
|
||||||
self.create_program_from_shader_names(resources, name, shaders)
|
self.create_program_from_shader_names(resources, name, shaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,10 +288,7 @@ pub enum ShaderKind {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum ProgramKind<T> {
|
pub enum ProgramKind<T> {
|
||||||
Raster {
|
Raster { vertex: T, fragment: T },
|
||||||
vertex: T,
|
|
||||||
fragment: T,
|
|
||||||
},
|
|
||||||
Compute(T),
|
Compute(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +319,10 @@ pub enum Primitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RenderState<'a, D> where D: Device {
|
pub struct RenderState<'a, D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub target: &'a RenderTarget<'a, D>,
|
pub target: &'a RenderTarget<'a, D>,
|
||||||
pub program: &'a D::Program,
|
pub program: &'a D::Program,
|
||||||
pub vertex_array: &'a D::VertexArray,
|
pub vertex_array: &'a D::VertexArray,
|
||||||
|
@ -301,7 +336,10 @@ pub struct RenderState<'a, D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ComputeState<'a, D> where D: Device {
|
pub struct ComputeState<'a, D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub program: &'a D::Program,
|
pub program: &'a D::Program,
|
||||||
pub uniforms: &'a [UniformBinding<'a, D::Uniform>],
|
pub uniforms: &'a [UniformBinding<'a, D::Uniform>],
|
||||||
pub textures: &'a [TextureBinding<'a, D::TextureParameter, D::Texture>],
|
pub textures: &'a [TextureBinding<'a, D::TextureParameter, D::Texture>],
|
||||||
|
@ -332,7 +370,10 @@ pub struct ClearOps {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum RenderTarget<'a, D> where D: Device {
|
pub enum RenderTarget<'a, D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
Default,
|
Default,
|
||||||
Framebuffer(&'a D::Framebuffer),
|
Framebuffer(&'a D::Framebuffer),
|
||||||
}
|
}
|
||||||
|
@ -537,8 +578,11 @@ pub enum ImageAccess {
|
||||||
|
|
||||||
impl<'a> TextureDataRef<'a> {
|
impl<'a> TextureDataRef<'a> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn check_and_extract_data_ptr(self, minimum_size: Vector2I, format: TextureFormat)
|
pub fn check_and_extract_data_ptr(
|
||||||
-> *const c_void {
|
self,
|
||||||
|
minimum_size: Vector2I,
|
||||||
|
format: TextureFormat,
|
||||||
|
) -> *const c_void {
|
||||||
let channels = match (format, self) {
|
let channels = match (format, self) {
|
||||||
(TextureFormat::R8, TextureDataRef::U8(_)) => 1,
|
(TextureFormat::R8, TextureDataRef::U8(_)) => 1,
|
||||||
(TextureFormat::RGBA8, TextureDataRef::U8(_)) => 4,
|
(TextureFormat::RGBA8, TextureDataRef::U8(_)) => 4,
|
||||||
|
|
|
@ -307,7 +307,10 @@ pub struct ShapeKeyframeProperty {
|
||||||
|
|
||||||
impl Lottie {
|
impl Lottie {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_reader<R>(reader: R) -> Result<Lottie, JSONError> where R: Read {
|
pub fn from_reader<R>(reader: R) -> Result<Lottie, JSONError>
|
||||||
|
where
|
||||||
|
R: Read,
|
||||||
|
{
|
||||||
serde_json::from_reader(reader)
|
serde_json::from_reader(reader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
942
metal/src/lib.rs
942
metal/src/lib.rs
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use crate::gpu_data::{TextureLocation, TexturePageId};
|
use crate::gpu_data::{TextureLocation, TexturePageId};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
|
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F, Vector2I};
|
||||||
|
|
||||||
const ATLAS_TEXTURE_LENGTH: u32 = 1024;
|
const ATLAS_TEXTURE_LENGTH: u32 = 1024;
|
||||||
|
|
||||||
|
@ -64,9 +64,10 @@ impl TextureAllocator {
|
||||||
|
|
||||||
pub fn allocate(&mut self, requested_size: Vector2I, mode: AllocationMode) -> TextureLocation {
|
pub fn allocate(&mut self, requested_size: Vector2I, mode: AllocationMode) -> TextureLocation {
|
||||||
// If requested, or if the image is too big, use a separate page.
|
// If requested, or if the image is too big, use a separate page.
|
||||||
if mode == AllocationMode::OwnPage ||
|
if mode == AllocationMode::OwnPage
|
||||||
requested_size.x() > ATLAS_TEXTURE_LENGTH as i32 ||
|
|| requested_size.x() > ATLAS_TEXTURE_LENGTH as i32
|
||||||
requested_size.y() > ATLAS_TEXTURE_LENGTH as i32 {
|
|| requested_size.y() > ATLAS_TEXTURE_LENGTH as i32
|
||||||
|
{
|
||||||
return self.allocate_image(requested_size);
|
return self.allocate_image(requested_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,19 +75,17 @@ impl TextureAllocator {
|
||||||
let mut first_free_page_index = self.pages.len();
|
let mut first_free_page_index = self.pages.len();
|
||||||
for (page_index, page) in self.pages.iter_mut().enumerate() {
|
for (page_index, page) in self.pages.iter_mut().enumerate() {
|
||||||
match *page {
|
match *page {
|
||||||
Some(ref mut page) => {
|
Some(ref mut page) => match page.allocator {
|
||||||
match page.allocator {
|
|
||||||
TexturePageAllocator::Image { .. } => {}
|
TexturePageAllocator::Image { .. } => {}
|
||||||
TexturePageAllocator::Atlas(ref mut allocator) => {
|
TexturePageAllocator::Atlas(ref mut allocator) => {
|
||||||
if let Some(rect) = allocator.allocate(requested_size) {
|
if let Some(rect) = allocator.allocate(requested_size) {
|
||||||
return TextureLocation {
|
return TextureLocation {
|
||||||
page: TexturePageId(page_index as u32),
|
page: TexturePageId(page_index as u32),
|
||||||
rect
|
rect,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
None => first_free_page_index = first_free_page_index.min(page_index),
|
None => first_free_page_index = first_free_page_index.min(page_index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +93,9 @@ impl TextureAllocator {
|
||||||
// Add a new atlas.
|
// Add a new atlas.
|
||||||
let page = self.get_first_free_page_id();
|
let page = self.get_first_free_page_id();
|
||||||
let mut allocator = TextureAtlasAllocator::new();
|
let mut allocator = TextureAtlasAllocator::new();
|
||||||
let rect = allocator.allocate(requested_size).expect("Allocation failed!");
|
let rect = allocator
|
||||||
|
.allocate(requested_size)
|
||||||
|
.expect("Allocation failed!");
|
||||||
while (page.0 as usize) >= self.pages.len() {
|
while (page.0 as usize) >= self.pages.len() {
|
||||||
self.pages.push(None);
|
self.pages.push(None);
|
||||||
}
|
}
|
||||||
|
@ -132,7 +133,8 @@ impl TextureAllocator {
|
||||||
match self.pages[location.page.0 as usize]
|
match self.pages[location.page.0 as usize]
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.expect("Texture page is not allocated!")
|
.expect("Texture page is not allocated!")
|
||||||
.allocator {
|
.allocator
|
||||||
|
{
|
||||||
TexturePageAllocator::Image { size } => {
|
TexturePageAllocator::Image { size } => {
|
||||||
debug_assert_eq!(location.rect, RectI::new(Vector2I::default(), size));
|
debug_assert_eq!(location.rect, RectI::new(Vector2I::default(), size));
|
||||||
}
|
}
|
||||||
|
@ -151,7 +153,11 @@ impl TextureAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn page_size(&self, page_id: TexturePageId) -> Vector2I {
|
pub fn page_size(&self, page_id: TexturePageId) -> Vector2I {
|
||||||
match self.pages[page_id.0 as usize].as_ref().expect("No such texture page!").allocator {
|
match self.pages[page_id.0 as usize]
|
||||||
|
.as_ref()
|
||||||
|
.expect("No such texture page!")
|
||||||
|
.allocator
|
||||||
|
{
|
||||||
TexturePageAllocator::Atlas(ref atlas) => Vector2I::splat(atlas.size as i32),
|
TexturePageAllocator::Atlas(ref atlas) => Vector2I::splat(atlas.size as i32),
|
||||||
TexturePageAllocator::Image { size, .. } => size,
|
TexturePageAllocator::Image { size, .. } => size,
|
||||||
}
|
}
|
||||||
|
@ -162,7 +168,10 @@ impl TextureAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn page_is_new(&self, page_id: TexturePageId) -> bool {
|
pub fn page_is_new(&self, page_id: TexturePageId) -> bool {
|
||||||
self.pages[page_id.0 as usize].as_ref().expect("No such texture page!").is_new
|
self.pages[page_id.0 as usize]
|
||||||
|
.as_ref()
|
||||||
|
.expect("No such texture page!")
|
||||||
|
.is_new
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_all_pages_as_allocated(&mut self) {
|
pub fn mark_all_pages_as_allocated(&mut self) {
|
||||||
|
@ -178,7 +187,10 @@ impl TextureAllocator {
|
||||||
while first_index < self.pages.len() && self.pages[first_index].is_none() {
|
while first_index < self.pages.len() && self.pages[first_index].is_none() {
|
||||||
first_index += 1;
|
first_index += 1;
|
||||||
}
|
}
|
||||||
TexturePageIter { allocator: self, next_index: first_index }
|
TexturePageIter {
|
||||||
|
allocator: self,
|
||||||
|
next_index: first_index,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,20 +202,29 @@ impl TextureAtlasAllocator {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_length(length: u32) -> TextureAtlasAllocator {
|
fn with_length(length: u32) -> TextureAtlasAllocator {
|
||||||
TextureAtlasAllocator { root: TreeNode::EmptyLeaf, size: length }
|
TextureAtlasAllocator {
|
||||||
|
root: TreeNode::EmptyLeaf,
|
||||||
|
size: length,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn allocate(&mut self, requested_size: Vector2I) -> Option<RectI> {
|
fn allocate(&mut self, requested_size: Vector2I) -> Option<RectI> {
|
||||||
let requested_length =
|
let requested_length =
|
||||||
(requested_size.x().max(requested_size.y()) as u32).next_power_of_two();
|
(requested_size.x().max(requested_size.y()) as u32).next_power_of_two();
|
||||||
self.root.allocate(Vector2I::default(), self.size, requested_length)
|
self.root
|
||||||
|
.allocate(Vector2I::default(), self.size, requested_length)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn free(&mut self, rect: RectI) {
|
fn free(&mut self, rect: RectI) {
|
||||||
let requested_length = rect.width() as u32;
|
let requested_length = rect.width() as u32;
|
||||||
self.root.free(Vector2I::default(), self.size, rect.origin(), requested_length)
|
self.root.free(
|
||||||
|
Vector2I::default(),
|
||||||
|
self.size,
|
||||||
|
rect.origin(),
|
||||||
|
requested_length,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -218,8 +239,12 @@ impl TextureAtlasAllocator {
|
||||||
|
|
||||||
impl TreeNode {
|
impl TreeNode {
|
||||||
// Invariant: `requested_size` must be a power of two.
|
// Invariant: `requested_size` must be a power of two.
|
||||||
fn allocate(&mut self, this_origin: Vector2I, this_size: u32, requested_size: u32)
|
fn allocate(
|
||||||
-> Option<RectI> {
|
&mut self,
|
||||||
|
this_origin: Vector2I,
|
||||||
|
this_size: u32,
|
||||||
|
requested_size: u32,
|
||||||
|
) -> Option<RectI> {
|
||||||
if let TreeNode::FullLeaf = *self {
|
if let TreeNode::FullLeaf = *self {
|
||||||
// No room here.
|
// No room here.
|
||||||
return None;
|
return None;
|
||||||
|
@ -253,19 +278,23 @@ impl TreeNode {
|
||||||
if let Some(origin) = kids[0].allocate(this_origin, kid_size, requested_size) {
|
if let Some(origin) = kids[0].allocate(this_origin, kid_size, requested_size) {
|
||||||
return Some(origin);
|
return Some(origin);
|
||||||
}
|
}
|
||||||
if let Some(origin) = kids[1].allocate(this_origin + vec2i(kid_size as i32, 0),
|
if let Some(origin) = kids[1].allocate(
|
||||||
|
this_origin + vec2i(kid_size as i32, 0),
|
||||||
kid_size,
|
kid_size,
|
||||||
requested_size) {
|
requested_size,
|
||||||
|
) {
|
||||||
return Some(origin);
|
return Some(origin);
|
||||||
}
|
}
|
||||||
if let Some(origin) = kids[2].allocate(this_origin + vec2i(0, kid_size as i32),
|
if let Some(origin) = kids[2].allocate(
|
||||||
|
this_origin + vec2i(0, kid_size as i32),
|
||||||
kid_size,
|
kid_size,
|
||||||
requested_size) {
|
requested_size,
|
||||||
|
) {
|
||||||
return Some(origin);
|
return Some(origin);
|
||||||
}
|
}
|
||||||
if let Some(origin) = kids[3].allocate(this_origin + kid_size as i32,
|
if let Some(origin) =
|
||||||
kid_size,
|
kids[3].allocate(this_origin + kid_size as i32, kid_size, requested_size)
|
||||||
requested_size) {
|
{
|
||||||
return Some(origin);
|
return Some(origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,11 +306,13 @@ impl TreeNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn free(&mut self,
|
fn free(
|
||||||
|
&mut self,
|
||||||
this_origin: Vector2I,
|
this_origin: Vector2I,
|
||||||
this_size: u32,
|
this_size: u32,
|
||||||
requested_origin: Vector2I,
|
requested_origin: Vector2I,
|
||||||
requested_size: u32) {
|
requested_size: u32,
|
||||||
|
) {
|
||||||
if this_size <= requested_size {
|
if this_size <= requested_size {
|
||||||
if this_size == requested_size && this_origin == requested_origin {
|
if this_size == requested_size && this_origin == requested_origin {
|
||||||
*self = TreeNode::EmptyLeaf;
|
*self = TreeNode::EmptyLeaf;
|
||||||
|
@ -324,11 +355,9 @@ impl TreeNode {
|
||||||
fn merge_if_necessary(&mut self) {
|
fn merge_if_necessary(&mut self) {
|
||||||
match *self {
|
match *self {
|
||||||
TreeNode::Parent(ref mut kids) => {
|
TreeNode::Parent(ref mut kids) => {
|
||||||
if kids.iter().all(|kid| {
|
if kids.iter().all(|kid| match **kid {
|
||||||
match **kid {
|
|
||||||
TreeNode::EmptyLeaf => true,
|
TreeNode::EmptyLeaf => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
|
||||||
}) {
|
}) {
|
||||||
*self = TreeNode::EmptyLeaf;
|
*self = TreeNode::EmptyLeaf;
|
||||||
}
|
}
|
||||||
|
@ -353,8 +382,9 @@ impl<'a> Iterator for TexturePageIter<'a> {
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
self.next_index += 1;
|
self.next_index += 1;
|
||||||
if self.next_index >= self.allocator.pages.len() ||
|
if self.next_index >= self.allocator.pages.len()
|
||||||
self.allocator.pages[self.next_index as usize].is_some() {
|
|| self.allocator.pages[self.next_index as usize].is_some()
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -372,8 +402,9 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_allocation_and_freeing() {
|
fn test_allocation_and_freeing() {
|
||||||
quickcheck::quickcheck(prop_allocation_and_freeing_work as
|
quickcheck::quickcheck(
|
||||||
fn(u32, Vec<(u32, u32)>) -> bool);
|
prop_allocation_and_freeing_work as fn(u32, Vec<(u32, u32)>) -> bool,
|
||||||
|
);
|
||||||
|
|
||||||
fn prop_allocation_and_freeing_work(mut length: u32, mut sizes: Vec<(u32, u32)>) -> bool {
|
fn prop_allocation_and_freeing_work(mut length: u32, mut sizes: Vec<(u32, u32)>) -> bool {
|
||||||
length = u32::next_power_of_two(length).max(1);
|
length = u32::next_power_of_two(length).max(1);
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::concurrent::executor::Executor;
|
||||||
use crate::gpu::blend::BlendModeExt;
|
use crate::gpu::blend::BlendModeExt;
|
||||||
use crate::gpu::options::RendererLevel;
|
use crate::gpu::options::RendererLevel;
|
||||||
use crate::gpu_data::{AlphaTileId, BackdropInfoD3D11, Clip, ClippedPathInfo, DiceMetadataD3D11};
|
use crate::gpu_data::{AlphaTileId, BackdropInfoD3D11, Clip, ClippedPathInfo, DiceMetadataD3D11};
|
||||||
use crate::gpu_data::{DrawTileBatch, DrawTileBatchD3D9, DrawTileBatchD3D11, Fill, GlobalPathId};
|
use crate::gpu_data::{DrawTileBatch, DrawTileBatchD3D11, DrawTileBatchD3D9, Fill, GlobalPathId};
|
||||||
use crate::gpu_data::{PathBatchIndex, PathSource, PrepareTilesInfoD3D11, PropagateMetadataD3D11};
|
use crate::gpu_data::{PathBatchIndex, PathSource, PrepareTilesInfoD3D11, PropagateMetadataD3D11};
|
||||||
use crate::gpu_data::{RenderCommand, SegmentIndicesD3D11, SegmentsD3D11, TileBatchDataD3D11};
|
use crate::gpu_data::{RenderCommand, SegmentIndicesD3D11, SegmentsD3D11, TileBatchDataD3D11};
|
||||||
use crate::gpu_data::{TileBatchId, TileBatchTexture, TileObjectPrimitive, TilePathInfoD3D11};
|
use crate::gpu_data::{TileBatchId, TileBatchTexture, TileObjectPrimitive, TilePathInfoD3D11};
|
||||||
|
@ -24,7 +24,7 @@ use crate::scene::{ClipPathId, DisplayItem, DrawPath, DrawPathId, LastSceneInfo,
|
||||||
use crate::scene::{Scene, SceneSink};
|
use crate::scene::{Scene, SceneSink};
|
||||||
use crate::tile_map::DenseTileMap;
|
use crate::tile_map::DenseTileMap;
|
||||||
use crate::tiler::Tiler;
|
use crate::tiler::Tiler;
|
||||||
use crate::tiles::{self, DrawTilingPathInfo, TILE_HEIGHT, TILE_WIDTH, TilingPathInfo};
|
use crate::tiles::{self, DrawTilingPathInfo, TilingPathInfo, TILE_HEIGHT, TILE_WIDTH};
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
use pathfinder_content::effects::{BlendMode, Filter};
|
use pathfinder_content::effects::{BlendMode, Filter};
|
||||||
|
@ -33,7 +33,7 @@ use pathfinder_content::outline::{Outline, PointFlags};
|
||||||
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU16};
|
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU16};
|
||||||
use pathfinder_geometry::rect::{RectF, RectI};
|
use pathfinder_geometry::rect::{RectF, RectI};
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{vec2i, Vector2I};
|
||||||
use pathfinder_gpu::TextureSamplingFlags;
|
use pathfinder_gpu::TextureSamplingFlags;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -77,8 +77,11 @@ struct BuiltDrawPath {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltDrawPath {
|
impl BuiltDrawPath {
|
||||||
fn new(built_path: BuiltPath, path_object: &DrawPath, paint_metadata: &PaintMetadata)
|
fn new(
|
||||||
-> BuiltDrawPath {
|
built_path: BuiltPath,
|
||||||
|
path_object: &DrawPath,
|
||||||
|
paint_metadata: &PaintMetadata,
|
||||||
|
) -> BuiltDrawPath {
|
||||||
let blend_mode = path_object.blend_mode();
|
let blend_mode = path_object.blend_mode();
|
||||||
let occludes = paint_metadata.is_opaque && blend_mode.occludes_backdrop();
|
let occludes = paint_metadata.is_opaque && blend_mode.occludes_backdrop();
|
||||||
BuiltDrawPath {
|
BuiltDrawPath {
|
||||||
|
@ -133,10 +136,11 @@ pub(crate) struct Occluder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
pub(crate) fn new(scene: &'a mut Scene,
|
pub(crate) fn new(
|
||||||
|
scene: &'a mut Scene,
|
||||||
built_options: &'b PreparedBuildOptions,
|
built_options: &'b PreparedBuildOptions,
|
||||||
sink: &'c mut SceneSink<'d>)
|
sink: &'c mut SceneSink<'d>,
|
||||||
-> SceneBuilder<'a, 'b, 'c, 'd> {
|
) -> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
SceneBuilder {
|
SceneBuilder {
|
||||||
scene,
|
scene,
|
||||||
built_options,
|
built_options,
|
||||||
|
@ -145,7 +149,10 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build<E>(&mut self, executor: &E) where E: Executor {
|
pub fn build<E>(&mut self, executor: &E)
|
||||||
|
where
|
||||||
|
E: Executor,
|
||||||
|
{
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
|
|
||||||
// Send the start rendering command.
|
// Send the start rendering command.
|
||||||
|
@ -167,14 +174,16 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
|
|
||||||
let render_transform = match self.built_options.transform {
|
let render_transform = match self.built_options.transform {
|
||||||
PreparedRenderTransform::Transform2D(transform) => transform.inverse(),
|
PreparedRenderTransform::Transform2D(transform) => transform.inverse(),
|
||||||
_ => Transform2F::default()
|
_ => Transform2F::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build paint data.
|
// Build paint data.
|
||||||
let PaintInfo {
|
let PaintInfo {
|
||||||
render_commands,
|
render_commands,
|
||||||
paint_metadata,
|
paint_metadata,
|
||||||
} = self.scene.build_paint_info(&mut self.sink.paint_texture_manager, render_transform);
|
} = self
|
||||||
|
.scene
|
||||||
|
.build_paint_info(&mut self.sink.paint_texture_manager, render_transform);
|
||||||
for render_command in render_commands {
|
for render_command in render_commands {
|
||||||
self.sink.listener.send(render_command);
|
self.sink.listener.send(render_command);
|
||||||
}
|
}
|
||||||
|
@ -189,11 +198,14 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
// TODO(pcwalton): Do this earlier?
|
// TODO(pcwalton): Do this earlier?
|
||||||
let scene_is_dirty = match (&prepare_mode, &self.sink.last_scene) {
|
let scene_is_dirty = match (&prepare_mode, &self.sink.last_scene) {
|
||||||
(&PrepareMode::GPU { .. }, &None) => true,
|
(&PrepareMode::GPU { .. }, &None) => true,
|
||||||
(&PrepareMode::GPU { .. }, &Some(LastSceneInfo {
|
(
|
||||||
|
&PrepareMode::GPU { .. },
|
||||||
|
&Some(LastSceneInfo {
|
||||||
scene_id: ref last_scene_id,
|
scene_id: ref last_scene_id,
|
||||||
scene_epoch: ref last_scene_epoch,
|
scene_epoch: ref last_scene_epoch,
|
||||||
..
|
..
|
||||||
})) => *last_scene_id != self.scene.id() || *last_scene_epoch != self.scene.epoch(),
|
}),
|
||||||
|
) => *last_scene_id != self.scene.id() || *last_scene_epoch != self.scene.epoch(),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -214,15 +226,20 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
self.finish_building(&paint_metadata, built_paths, &prepare_mode);
|
self.finish_building(&paint_metadata, built_paths, &prepare_mode);
|
||||||
|
|
||||||
let cpu_build_time = Instant::now() - start_time;
|
let cpu_build_time = Instant::now() - start_time;
|
||||||
self.sink.listener.send(RenderCommand::Finish { cpu_build_time });
|
self.sink
|
||||||
|
.listener
|
||||||
|
.send(RenderCommand::Finish { cpu_build_time });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_paths_on_cpu<E>(&mut self,
|
fn build_paths_on_cpu<E>(
|
||||||
|
&mut self,
|
||||||
executor: &E,
|
executor: &E,
|
||||||
paint_metadata: &[PaintMetadata],
|
paint_metadata: &[PaintMetadata],
|
||||||
prepare_mode: &PrepareMode)
|
prepare_mode: &PrepareMode,
|
||||||
-> BuiltPaths
|
) -> BuiltPaths
|
||||||
where E: Executor {
|
where
|
||||||
|
E: Executor,
|
||||||
|
{
|
||||||
let clip_path_count = self.scene.clip_paths().len();
|
let clip_path_count = self.scene.clip_paths().len();
|
||||||
let draw_path_count = self.scene.draw_paths().len();
|
let draw_path_count = self.scene.draw_paths().len();
|
||||||
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
||||||
|
@ -251,15 +268,24 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
BuiltPaths { draw: built_draw_paths }
|
BuiltPaths {
|
||||||
|
draw: built_draw_paths,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_clip_path_on_cpu(&self, params: PathBuildParams) -> BuiltPath {
|
fn build_clip_path_on_cpu(&self, params: PathBuildParams) -> BuiltPath {
|
||||||
let PathBuildParams { path_id, view_box, built_options, scene, prepare_mode } = params;
|
let PathBuildParams {
|
||||||
|
path_id,
|
||||||
|
view_box,
|
||||||
|
built_options,
|
||||||
|
scene,
|
||||||
|
prepare_mode,
|
||||||
|
} = params;
|
||||||
let path_object = &scene.get_clip_path(path_id.to_clip_path_id());
|
let path_object = &scene.get_clip_path(path_id.to_clip_path_id());
|
||||||
let outline = scene.apply_render_options(path_object.outline(), built_options);
|
let outline = scene.apply_render_options(path_object.outline(), built_options);
|
||||||
|
|
||||||
let mut tiler = Tiler::new(self,
|
let mut tiler = Tiler::new(
|
||||||
|
self,
|
||||||
path_id,
|
path_id,
|
||||||
&outline,
|
&outline,
|
||||||
path_object.fill_rule(),
|
path_object.fill_rule(),
|
||||||
|
@ -267,7 +293,8 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
&prepare_mode,
|
&prepare_mode,
|
||||||
path_object.clip_path(),
|
path_object.clip_path(),
|
||||||
&[],
|
&[],
|
||||||
TilingPathInfo::Clip);
|
TilingPathInfo::Clip,
|
||||||
|
);
|
||||||
|
|
||||||
tiler.generate_tiles();
|
tiler.generate_tiles();
|
||||||
self.send_fills(tiler.object_builder.fills);
|
self.send_fills(tiler.object_builder.fills);
|
||||||
|
@ -276,7 +303,8 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
|
|
||||||
fn build_draw_path_on_cpu(&self, params: DrawPathBuildParams) -> BuiltDrawPath {
|
fn build_draw_path_on_cpu(&self, params: DrawPathBuildParams) -> BuiltDrawPath {
|
||||||
let DrawPathBuildParams {
|
let DrawPathBuildParams {
|
||||||
path_build_params: PathBuildParams {
|
path_build_params:
|
||||||
|
PathBuildParams {
|
||||||
path_id,
|
path_id,
|
||||||
view_box,
|
view_box,
|
||||||
built_options,
|
built_options,
|
||||||
|
@ -293,7 +321,8 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
let paint_id = path_object.paint();
|
let paint_id = path_object.paint();
|
||||||
let paint_metadata = &paint_metadata[paint_id.0 as usize];
|
let paint_metadata = &paint_metadata[paint_id.0 as usize];
|
||||||
|
|
||||||
let mut tiler = Tiler::new(self,
|
let mut tiler = Tiler::new(
|
||||||
|
self,
|
||||||
path_id,
|
path_id,
|
||||||
&outline,
|
&outline,
|
||||||
path_object.fill_rule(),
|
path_object.fill_rule(),
|
||||||
|
@ -305,7 +334,8 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
paint_id,
|
paint_id,
|
||||||
blend_mode: path_object.blend_mode(),
|
blend_mode: path_object.blend_mode(),
|
||||||
fill_rule: path_object.fill_rule(),
|
fill_rule: path_object.fill_rule(),
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
tiler.generate_tiles();
|
tiler.generate_tiles();
|
||||||
self.send_fills(tiler.object_builder.fills);
|
self.send_fills(tiler.object_builder.fills);
|
||||||
|
@ -319,22 +349,23 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_tile_batches(&mut self,
|
fn build_tile_batches(
|
||||||
|
&mut self,
|
||||||
paint_metadata: &[PaintMetadata],
|
paint_metadata: &[PaintMetadata],
|
||||||
prepare_mode: &PrepareMode,
|
prepare_mode: &PrepareMode,
|
||||||
built_paths: Option<BuiltPaths>) {
|
built_paths: Option<BuiltPaths>,
|
||||||
|
) {
|
||||||
let mut tile_batch_builder = TileBatchBuilder::new(built_paths);
|
let mut tile_batch_builder = TileBatchBuilder::new(built_paths);
|
||||||
|
|
||||||
// Prepare display items.
|
// Prepare display items.
|
||||||
for display_item in self.scene.display_list() {
|
for display_item in self.scene.display_list() {
|
||||||
match *display_item {
|
match *display_item {
|
||||||
DisplayItem::PushRenderTarget(render_target_id) => {
|
DisplayItem::PushRenderTarget(render_target_id) => tile_batch_builder
|
||||||
tile_batch_builder.draw_commands
|
.draw_commands
|
||||||
.push(RenderCommand::PushRenderTarget(render_target_id))
|
.push(RenderCommand::PushRenderTarget(render_target_id)),
|
||||||
}
|
DisplayItem::PopRenderTarget => tile_batch_builder
|
||||||
DisplayItem::PopRenderTarget => {
|
.draw_commands
|
||||||
tile_batch_builder.draw_commands.push(RenderCommand::PopRenderTarget)
|
.push(RenderCommand::PopRenderTarget),
|
||||||
}
|
|
||||||
DisplayItem::DrawPaths(ref path_id_range) => {
|
DisplayItem::DrawPaths(ref path_id_range) => {
|
||||||
tile_batch_builder.build_tile_batches_for_draw_path_display_item(
|
tile_batch_builder.build_tile_batches_for_draw_path_display_item(
|
||||||
&self.scene,
|
&self.scene,
|
||||||
|
@ -342,7 +373,8 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
self.built_options,
|
self.built_options,
|
||||||
path_id_range.start..path_id_range.end,
|
path_id_range.start..path_id_range.end,
|
||||||
paint_metadata,
|
paint_metadata,
|
||||||
prepare_mode);
|
prepare_mode,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,10 +383,12 @@ impl<'a, 'b, 'c, 'd> SceneBuilder<'a, 'b, 'c, 'd> {
|
||||||
tile_batch_builder.send_to(&self.sink);
|
tile_batch_builder.send_to(&self.sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_building(&mut self,
|
fn finish_building(
|
||||||
|
&mut self,
|
||||||
paint_metadata: &[PaintMetadata],
|
paint_metadata: &[PaintMetadata],
|
||||||
built_paths: Option<BuiltPaths>,
|
built_paths: Option<BuiltPaths>,
|
||||||
prepare_mode: &PrepareMode) {
|
prepare_mode: &PrepareMode,
|
||||||
|
) {
|
||||||
match self.sink.renderer_level {
|
match self.sink.renderer_level {
|
||||||
RendererLevel::D3D9 => self.sink.listener.send(RenderCommand::FlushFillsD3D9),
|
RendererLevel::D3D9 => self.sink.listener.send(RenderCommand::FlushFillsD3D9),
|
||||||
RendererLevel::D3D11 => {}
|
RendererLevel::D3D11 => {}
|
||||||
|
@ -406,14 +440,15 @@ struct DrawPathBuildParams<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltPath {
|
impl BuiltPath {
|
||||||
fn new(path_id: PathId,
|
fn new(
|
||||||
|
path_id: PathId,
|
||||||
path_bounds: RectF,
|
path_bounds: RectF,
|
||||||
view_box_bounds: RectF,
|
view_box_bounds: RectF,
|
||||||
fill_rule: FillRule,
|
fill_rule: FillRule,
|
||||||
prepare_mode: &PrepareMode,
|
prepare_mode: &PrepareMode,
|
||||||
clip_path_id: Option<ClipPathId>,
|
clip_path_id: Option<ClipPathId>,
|
||||||
tiling_path_info: &TilingPathInfo)
|
tiling_path_info: &TilingPathInfo,
|
||||||
-> BuiltPath {
|
) -> BuiltPath {
|
||||||
let paint_id = match *tiling_path_info {
|
let paint_id = match *tiling_path_info {
|
||||||
TilingPathInfo::Draw(ref draw_tiling_path_info) => draw_tiling_path_info.paint_id,
|
TilingPathInfo::Draw(ref draw_tiling_path_info) => draw_tiling_path_info.paint_id,
|
||||||
TilingPathInfo::Clip => PaintId(0),
|
TilingPathInfo::Clip => PaintId(0),
|
||||||
|
@ -430,11 +465,10 @@ impl BuiltPath {
|
||||||
let tile_bounds = tiles::round_rect_out_to_tile_bounds(tile_map_bounds);
|
let tile_bounds = tiles::round_rect_out_to_tile_bounds(tile_map_bounds);
|
||||||
|
|
||||||
let data = match *prepare_mode {
|
let data = match *prepare_mode {
|
||||||
PrepareMode::CPU => {
|
PrepareMode::CPU => BuiltPathData::CPU(BuiltPathBinCPUData {
|
||||||
BuiltPathData::CPU(BuiltPathBinCPUData {
|
|
||||||
backdrops: vec![0; tile_bounds.width() as usize],
|
backdrops: vec![0; tile_bounds.width() as usize],
|
||||||
tiles: DenseTileMap::from_builder(|tile_coord| {
|
tiles: DenseTileMap::from_builder(
|
||||||
TileObjectPrimitive {
|
|tile_coord| TileObjectPrimitive {
|
||||||
tile_x: tile_coord.x() as i16,
|
tile_x: tile_coord.x() as i16,
|
||||||
tile_y: tile_coord.y() as i16,
|
tile_y: tile_coord.y() as i16,
|
||||||
alpha_tile_id: AlphaTileId(!0),
|
alpha_tile_id: AlphaTileId(!0),
|
||||||
|
@ -442,23 +476,24 @@ impl BuiltPath {
|
||||||
color: paint_id.0,
|
color: paint_id.0,
|
||||||
backdrop: 0,
|
backdrop: 0,
|
||||||
ctrl: ctrl_byte,
|
ctrl: ctrl_byte,
|
||||||
}
|
},
|
||||||
}, tile_bounds),
|
tile_bounds,
|
||||||
|
),
|
||||||
clip_tiles: match *tiling_path_info {
|
clip_tiles: match *tiling_path_info {
|
||||||
TilingPathInfo::Draw(_) if clip_path_id.is_some() => {
|
TilingPathInfo::Draw(_) if clip_path_id.is_some() => {
|
||||||
Some(DenseTileMap::from_builder(|_| {
|
Some(DenseTileMap::from_builder(
|
||||||
Clip {
|
|_| Clip {
|
||||||
dest_tile_id: AlphaTileId(!0),
|
dest_tile_id: AlphaTileId(!0),
|
||||||
dest_backdrop: 0,
|
dest_backdrop: 0,
|
||||||
src_tile_id: AlphaTileId(!0),
|
src_tile_id: AlphaTileId(!0),
|
||||||
src_backdrop: 0,
|
src_backdrop: 0,
|
||||||
}
|
},
|
||||||
}, tile_bounds))
|
tile_bounds,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
PrepareMode::TransformCPUBinGPU => {
|
PrepareMode::TransformCPUBinGPU => {
|
||||||
BuiltPathData::TransformCPUBinGPU(BuiltPathTransformCPUBinGPUData {
|
BuiltPathData::TransformCPUBinGPU(BuiltPathTransformCPUBinGPUData {
|
||||||
outline: Outline::new(),
|
outline: Outline::new(),
|
||||||
|
@ -482,28 +517,37 @@ impl BuiltPath {
|
||||||
|
|
||||||
impl ObjectBuilder {
|
impl ObjectBuilder {
|
||||||
// If `outline` is `None`, then tiling is being done on CPU. Otherwise, it's done on GPU.
|
// If `outline` is `None`, then tiling is being done on CPU. Otherwise, it's done on GPU.
|
||||||
pub(crate) fn new(path_id: PathId,
|
pub(crate) fn new(
|
||||||
|
path_id: PathId,
|
||||||
path_bounds: RectF,
|
path_bounds: RectF,
|
||||||
view_box_bounds: RectF,
|
view_box_bounds: RectF,
|
||||||
fill_rule: FillRule,
|
fill_rule: FillRule,
|
||||||
prepare_mode: &PrepareMode,
|
prepare_mode: &PrepareMode,
|
||||||
clip_path_id: Option<ClipPathId>,
|
clip_path_id: Option<ClipPathId>,
|
||||||
tiling_path_info: &TilingPathInfo)
|
tiling_path_info: &TilingPathInfo,
|
||||||
-> ObjectBuilder {
|
) -> ObjectBuilder {
|
||||||
let built_path = BuiltPath::new(path_id,
|
let built_path = BuiltPath::new(
|
||||||
|
path_id,
|
||||||
path_bounds,
|
path_bounds,
|
||||||
view_box_bounds,
|
view_box_bounds,
|
||||||
fill_rule,
|
fill_rule,
|
||||||
prepare_mode,
|
prepare_mode,
|
||||||
clip_path_id,
|
clip_path_id,
|
||||||
tiling_path_info);
|
tiling_path_info,
|
||||||
ObjectBuilder { built_path, bounds: path_bounds, fills: vec![] }
|
);
|
||||||
|
ObjectBuilder {
|
||||||
|
built_path,
|
||||||
|
bounds: path_bounds,
|
||||||
|
fills: vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_fill(&mut self,
|
pub(crate) fn add_fill(
|
||||||
|
&mut self,
|
||||||
scene_builder: &SceneBuilder,
|
scene_builder: &SceneBuilder,
|
||||||
segment: LineSegment2F,
|
segment: LineSegment2F,
|
||||||
tile_coords: Vector2I) {
|
tile_coords: Vector2I,
|
||||||
|
) {
|
||||||
debug!("add_fill({:?} ({:?}))", segment, tile_coords);
|
debug!("add_fill({:?} ({:?}))", segment, tile_coords);
|
||||||
|
|
||||||
// Ensure this fill is in bounds. If not, cull it.
|
// Ensure this fill is in bounds. If not, cull it.
|
||||||
|
@ -519,7 +563,10 @@ impl ObjectBuilder {
|
||||||
|
|
||||||
// Convert to 8.8 fixed point.
|
// Convert to 8.8 fixed point.
|
||||||
let segment = (segment.0 - tile_upper_left) * F32x4::splat(256.0);
|
let segment = (segment.0 - tile_upper_left) * F32x4::splat(256.0);
|
||||||
let (min, max) = (F32x4::default(), F32x4::splat((TILE_WIDTH * 256 - 1) as f32));
|
let (min, max) = (
|
||||||
|
F32x4::default(),
|
||||||
|
F32x4::splat((TILE_WIDTH * 256 - 1) as f32),
|
||||||
|
);
|
||||||
let segment = segment.clamp(min, max).to_i32x4();
|
let segment = segment.clamp(min, max).to_i32x4();
|
||||||
let (from_x, from_y, to_x, to_y) = (segment[0], segment[1], segment[2], segment[3]);
|
let (from_x, from_y, to_x, to_y) = (segment[0], segment[1], segment[2], segment[3]);
|
||||||
|
|
||||||
|
@ -546,10 +593,11 @@ impl ObjectBuilder {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_or_allocate_alpha_tile_index(&mut self,
|
fn get_or_allocate_alpha_tile_index(
|
||||||
|
&mut self,
|
||||||
scene_builder: &SceneBuilder,
|
scene_builder: &SceneBuilder,
|
||||||
tile_coords: Vector2I)
|
tile_coords: Vector2I,
|
||||||
-> AlphaTileId {
|
) -> AlphaTileId {
|
||||||
let local_tile_index = self.tile_coords_to_local_index_unchecked(tile_coords) as usize;
|
let local_tile_index = self.tile_coords_to_local_index_unchecked(tile_coords) as usize;
|
||||||
|
|
||||||
let tiles = match self.built_path.data {
|
let tiles = match self.built_path.data {
|
||||||
|
@ -595,8 +643,10 @@ impl ObjectBuilder {
|
||||||
};
|
};
|
||||||
|
|
||||||
let tile_offset = tile_coords - tiles.rect.origin();
|
let tile_offset = tile_coords - tiles.rect.origin();
|
||||||
if tile_offset.x() < 0 || tile_offset.x() >= tiles.rect.width() ||
|
if tile_offset.x() < 0
|
||||||
tile_offset.y() >= tiles.rect.height() {
|
|| tile_offset.x() >= tiles.rect.width()
|
||||||
|
|| tile_offset.y() >= tiles.rect.height()
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,8 +661,11 @@ impl ObjectBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileBatchDataD3D11 {
|
impl TileBatchDataD3D11 {
|
||||||
fn new(batch_id: TileBatchId, mode: &PrepareMode, path_source: PathSource)
|
fn new(
|
||||||
-> TileBatchDataD3D11 {
|
batch_id: TileBatchId,
|
||||||
|
mode: &PrepareMode,
|
||||||
|
path_source: PathSource,
|
||||||
|
) -> TileBatchDataD3D11 {
|
||||||
TileBatchDataD3D11 {
|
TileBatchDataD3D11 {
|
||||||
batch_id,
|
batch_id,
|
||||||
path_count: 0,
|
path_count: 0,
|
||||||
|
@ -621,40 +674,39 @@ impl TileBatchDataD3D11 {
|
||||||
path_source,
|
path_source,
|
||||||
prepare_info: match *mode {
|
prepare_info: match *mode {
|
||||||
PrepareMode::CPU => unimplemented!(),
|
PrepareMode::CPU => unimplemented!(),
|
||||||
PrepareMode::TransformCPUBinGPU => {
|
PrepareMode::TransformCPUBinGPU => PrepareTilesInfoD3D11 {
|
||||||
PrepareTilesInfoD3D11 {
|
|
||||||
backdrops: vec![],
|
backdrops: vec![],
|
||||||
propagate_metadata: vec![],
|
propagate_metadata: vec![],
|
||||||
dice_metadata: vec![],
|
dice_metadata: vec![],
|
||||||
tile_path_info: vec![],
|
tile_path_info: vec![],
|
||||||
transform: Transform2F::default(),
|
transform: Transform2F::default(),
|
||||||
}
|
},
|
||||||
}
|
PrepareMode::GPU { ref transform } => PrepareTilesInfoD3D11 {
|
||||||
PrepareMode::GPU { ref transform } => {
|
|
||||||
PrepareTilesInfoD3D11 {
|
|
||||||
backdrops: vec![],
|
backdrops: vec![],
|
||||||
propagate_metadata: vec![],
|
propagate_metadata: vec![],
|
||||||
dice_metadata: vec![],
|
dice_metadata: vec![],
|
||||||
tile_path_info: vec![],
|
tile_path_info: vec![],
|
||||||
transform: *transform,
|
transform: *transform,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
},
|
},
|
||||||
clipped_path_info: None,
|
clipped_path_info: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self,
|
fn push(
|
||||||
|
&mut self,
|
||||||
path: &BuiltPath,
|
path: &BuiltPath,
|
||||||
global_path_id: PathId,
|
global_path_id: PathId,
|
||||||
batch_clip_path_id: Option<GlobalPathId>,
|
batch_clip_path_id: Option<GlobalPathId>,
|
||||||
z_write: bool,
|
z_write: bool,
|
||||||
sink: &SceneSink)
|
sink: &SceneSink,
|
||||||
-> PathBatchIndex {
|
) -> PathBatchIndex {
|
||||||
let batch_path_index = PathBatchIndex(self.path_count);
|
let batch_path_index = PathBatchIndex(self.path_count);
|
||||||
self.path_count += 1;
|
self.path_count += 1;
|
||||||
|
|
||||||
self.prepare_info.propagate_metadata.push(PropagateMetadataD3D11 {
|
self.prepare_info
|
||||||
|
.propagate_metadata
|
||||||
|
.push(PropagateMetadataD3D11 {
|
||||||
tile_rect: path.tile_bounds,
|
tile_rect: path.tile_bounds,
|
||||||
tile_offset: self.tile_count,
|
tile_offset: self.tile_count,
|
||||||
path_index: batch_path_index,
|
path_index: batch_path_index,
|
||||||
|
@ -681,9 +733,11 @@ impl TileBatchDataD3D11 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BuiltPathData::TransformCPUBinGPU(_) | BuiltPathData::GPU => {
|
BuiltPathData::TransformCPUBinGPU(_) | BuiltPathData::GPU => {
|
||||||
init_backdrops(&mut self.prepare_info.backdrops,
|
init_backdrops(
|
||||||
|
&mut self.prepare_info.backdrops,
|
||||||
batch_path_index,
|
batch_path_index,
|
||||||
path.tile_bounds);
|
path.tile_bounds,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,11 +807,17 @@ impl TileBatchDataD3D11 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_backdrops(backdrops: &mut Vec<BackdropInfoD3D11>,
|
fn init_backdrops(
|
||||||
|
backdrops: &mut Vec<BackdropInfoD3D11>,
|
||||||
path_index: PathBatchIndex,
|
path_index: PathBatchIndex,
|
||||||
tile_rect: RectI) {
|
tile_rect: RectI,
|
||||||
|
) {
|
||||||
for tile_x_offset in 0..tile_rect.width() {
|
for tile_x_offset in 0..tile_rect.width() {
|
||||||
backdrops.push(BackdropInfoD3D11 { initial_backdrop: 0, path_index, tile_x_offset });
|
backdrops.push(BackdropInfoD3D11 {
|
||||||
|
initial_backdrop: 0,
|
||||||
|
path_index,
|
||||||
|
tile_x_offset,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,7 +852,10 @@ impl BuiltSegments {
|
||||||
|
|
||||||
impl SegmentsD3D11 {
|
impl SegmentsD3D11 {
|
||||||
fn new() -> SegmentsD3D11 {
|
fn new() -> SegmentsD3D11 {
|
||||||
SegmentsD3D11 { points: vec![], indices: vec![] }
|
SegmentsD3D11 {
|
||||||
|
points: vec![],
|
||||||
|
indices: vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_path(&mut self, outline: &Outline) -> Range<u32> {
|
fn add_path(&mut self, outline: &Outline) -> Range<u32> {
|
||||||
|
@ -802,15 +865,21 @@ impl SegmentsD3D11 {
|
||||||
self.points.reserve(point_count as usize);
|
self.points.reserve(point_count as usize);
|
||||||
|
|
||||||
for point_index in 0..point_count {
|
for point_index in 0..point_count {
|
||||||
if !contour.flags_of(point_index).intersects(PointFlags::CONTROL_POINT_0 |
|
if !contour
|
||||||
PointFlags::CONTROL_POINT_1) {
|
.flags_of(point_index)
|
||||||
|
.intersects(PointFlags::CONTROL_POINT_0 | PointFlags::CONTROL_POINT_1)
|
||||||
|
{
|
||||||
let mut flags = 0;
|
let mut flags = 0;
|
||||||
if point_index + 1 < point_count &&
|
if point_index + 1 < point_count
|
||||||
contour.flags_of(point_index + 1)
|
&& contour
|
||||||
.contains(PointFlags::CONTROL_POINT_0) {
|
.flags_of(point_index + 1)
|
||||||
if point_index + 2 < point_count &&
|
.contains(PointFlags::CONTROL_POINT_0)
|
||||||
contour.flags_of(point_index + 2)
|
{
|
||||||
.contains(PointFlags::CONTROL_POINT_1) {
|
if point_index + 2 < point_count
|
||||||
|
&& contour
|
||||||
|
.flags_of(point_index + 2)
|
||||||
|
.contains(PointFlags::CONTROL_POINT_1)
|
||||||
|
{
|
||||||
flags = CURVE_IS_CUBIC
|
flags = CURVE_IS_CUBIC
|
||||||
} else {
|
} else {
|
||||||
flags = CURVE_IS_QUADRATIC
|
flags = CURVE_IS_QUADRATIC
|
||||||
|
@ -854,12 +923,10 @@ impl TileBatchBuilder {
|
||||||
draw_commands: vec![],
|
draw_commands: vec![],
|
||||||
next_batch_id: TileBatchId(MAX_CLIP_BATCHES),
|
next_batch_id: TileBatchId(MAX_CLIP_BATCHES),
|
||||||
clip_batches_d3d11: match built_paths {
|
clip_batches_d3d11: match built_paths {
|
||||||
None => {
|
None => Some(ClipBatchesD3D11 {
|
||||||
Some(ClipBatchesD3D11 {
|
|
||||||
prepare_batches: vec![],
|
prepare_batches: vec![],
|
||||||
clip_id_to_path_batch_index: FxHashMap::default(),
|
clip_id_to_path_batch_index: FxHashMap::default(),
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
Some(_) => None,
|
Some(_) => None,
|
||||||
},
|
},
|
||||||
level: match built_paths {
|
level: match built_paths {
|
||||||
|
@ -869,23 +936,27 @@ impl TileBatchBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_tile_batches_for_draw_path_display_item(&mut self,
|
fn build_tile_batches_for_draw_path_display_item(
|
||||||
|
&mut self,
|
||||||
scene: &Scene,
|
scene: &Scene,
|
||||||
sink: &SceneSink,
|
sink: &SceneSink,
|
||||||
built_options: &PreparedBuildOptions,
|
built_options: &PreparedBuildOptions,
|
||||||
draw_path_id_range: Range<DrawPathId>,
|
draw_path_id_range: Range<DrawPathId>,
|
||||||
paint_metadata: &[PaintMetadata],
|
paint_metadata: &[PaintMetadata],
|
||||||
prepare_mode: &PrepareMode) {
|
prepare_mode: &PrepareMode,
|
||||||
|
) {
|
||||||
let mut draw_tile_batch = None;
|
let mut draw_tile_batch = None;
|
||||||
for draw_path_id in draw_path_id_range.start.0..draw_path_id_range.end.0 {
|
for draw_path_id in draw_path_id_range.start.0..draw_path_id_range.end.0 {
|
||||||
let draw_path_id = DrawPathId(draw_path_id);
|
let draw_path_id = DrawPathId(draw_path_id);
|
||||||
let draw_path = match self.level {
|
let draw_path = match self.level {
|
||||||
TileBatchBuilderLevel::D3D11 { .. } => {
|
TileBatchBuilderLevel::D3D11 { .. } => {
|
||||||
match self.prepare_draw_path_for_gpu_binning(scene,
|
match self.prepare_draw_path_for_gpu_binning(
|
||||||
|
scene,
|
||||||
built_options,
|
built_options,
|
||||||
draw_path_id,
|
draw_path_id,
|
||||||
prepare_mode,
|
prepare_mode,
|
||||||
paint_metadata) {
|
paint_metadata,
|
||||||
|
) {
|
||||||
None => continue,
|
None => continue,
|
||||||
Some(built_draw_path) => Cow::Owned(built_draw_path),
|
Some(built_draw_path) => Cow::Owned(built_draw_path),
|
||||||
}
|
}
|
||||||
|
@ -898,12 +969,16 @@ impl TileBatchBuilder {
|
||||||
// Try to reuse the current batch if we can.
|
// Try to reuse the current batch if we can.
|
||||||
let flush_needed = match draw_tile_batch {
|
let flush_needed = match draw_tile_batch {
|
||||||
Some(DrawTileBatch::D3D11(ref mut existing_batch)) => {
|
Some(DrawTileBatch::D3D11(ref mut existing_batch)) => {
|
||||||
!fixup_batch_for_new_path_if_possible(&mut existing_batch.color_texture,
|
!fixup_batch_for_new_path_if_possible(
|
||||||
&draw_path)
|
&mut existing_batch.color_texture,
|
||||||
|
&draw_path,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Some(DrawTileBatch::D3D9(ref mut existing_batch)) => {
|
Some(DrawTileBatch::D3D9(ref mut existing_batch)) => {
|
||||||
!fixup_batch_for_new_path_if_possible(&mut existing_batch.color_texture,
|
!fixup_batch_for_new_path_if_possible(
|
||||||
&draw_path)
|
&mut existing_batch.color_texture,
|
||||||
|
&draw_path,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
|
@ -912,10 +987,12 @@ impl TileBatchBuilder {
|
||||||
if flush_needed {
|
if flush_needed {
|
||||||
match draw_tile_batch.take() {
|
match draw_tile_batch.take() {
|
||||||
Some(DrawTileBatch::D3D11(batch_to_flush)) => {
|
Some(DrawTileBatch::D3D11(batch_to_flush)) => {
|
||||||
self.draw_commands.push(RenderCommand::DrawTilesD3D11(batch_to_flush));
|
self.draw_commands
|
||||||
|
.push(RenderCommand::DrawTilesD3D11(batch_to_flush));
|
||||||
}
|
}
|
||||||
Some(DrawTileBatch::D3D9(batch_to_flush)) => {
|
Some(DrawTileBatch::D3D9(batch_to_flush)) => {
|
||||||
self.draw_commands.push(RenderCommand::DrawTilesD3D9(batch_to_flush));
|
self.draw_commands
|
||||||
|
.push(RenderCommand::DrawTilesD3D9(batch_to_flush));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -937,9 +1014,11 @@ impl TileBatchBuilder {
|
||||||
}
|
}
|
||||||
TileBatchBuilderLevel::D3D11 { .. } => {
|
TileBatchBuilderLevel::D3D11 { .. } => {
|
||||||
Some(DrawTileBatch::D3D11(DrawTileBatchD3D11 {
|
Some(DrawTileBatch::D3D11(DrawTileBatchD3D11 {
|
||||||
tile_batch_data: TileBatchDataD3D11::new(self.next_batch_id,
|
tile_batch_data: TileBatchDataD3D11::new(
|
||||||
|
self.next_batch_id,
|
||||||
&prepare_mode,
|
&prepare_mode,
|
||||||
PathSource::Draw),
|
PathSource::Draw,
|
||||||
|
),
|
||||||
color_texture: draw_path.color_texture,
|
color_texture: draw_path.color_texture,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -950,25 +1029,27 @@ impl TileBatchBuilder {
|
||||||
// Add clip path if necessary.
|
// Add clip path if necessary.
|
||||||
let clip_path = match self.clip_batches_d3d11 {
|
let clip_path = match self.clip_batches_d3d11 {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref mut clip_batches_d3d11) => {
|
Some(ref mut clip_batches_d3d11) => add_clip_path_to_batch(
|
||||||
add_clip_path_to_batch(scene,
|
scene,
|
||||||
sink,
|
sink,
|
||||||
built_options,
|
built_options,
|
||||||
draw_path.clip_path_id,
|
draw_path.clip_path_id,
|
||||||
prepare_mode,
|
prepare_mode,
|
||||||
0,
|
0,
|
||||||
clip_batches_d3d11)
|
clip_batches_d3d11,
|
||||||
}
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let draw_tile_batch = draw_tile_batch.as_mut().unwrap();
|
let draw_tile_batch = draw_tile_batch.as_mut().unwrap();
|
||||||
match *draw_tile_batch {
|
match *draw_tile_batch {
|
||||||
DrawTileBatch::D3D11(ref mut draw_tile_batch) => {
|
DrawTileBatch::D3D11(ref mut draw_tile_batch) => {
|
||||||
draw_tile_batch.tile_batch_data.push(&draw_path.path,
|
draw_tile_batch.tile_batch_data.push(
|
||||||
|
&draw_path.path,
|
||||||
draw_path_id.to_path_id(),
|
draw_path_id.to_path_id(),
|
||||||
clip_path,
|
clip_path,
|
||||||
draw_path.occludes,
|
draw_path.occludes,
|
||||||
sink);
|
sink,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
DrawTileBatch::D3D9(ref mut draw_tile_batch) => {
|
DrawTileBatch::D3D9(ref mut draw_tile_batch) => {
|
||||||
let built_paths = match self.level {
|
let built_paths = match self.level {
|
||||||
|
@ -995,7 +1076,8 @@ impl TileBatchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tile_coords = vec2i(tile.tile_x as i32, tile.tile_y as i32);
|
let tile_coords = vec2i(tile.tile_x as i32, tile.tile_y as i32);
|
||||||
let z_value = draw_tile_batch.z_buffer_data
|
let z_value = draw_tile_batch
|
||||||
|
.z_buffer_data
|
||||||
.get_mut(tile_coords)
|
.get_mut(tile_coords)
|
||||||
.expect("Z value out of bounds!");
|
.expect("Z value out of bounds!");
|
||||||
*z_value = (*z_value).max(draw_path_id.0 as i32);
|
*z_value = (*z_value).max(draw_path_id.0 as i32);
|
||||||
|
@ -1006,8 +1088,9 @@ impl TileBatchBuilder {
|
||||||
Some(ref clip_tiles) => clip_tiles,
|
Some(ref clip_tiles) => clip_tiles,
|
||||||
};
|
};
|
||||||
for clip_tile in &clip_tiles.data {
|
for clip_tile in &clip_tiles.data {
|
||||||
if clip_tile.dest_tile_id != AlphaTileId(!0) &&
|
if clip_tile.dest_tile_id != AlphaTileId(!0)
|
||||||
clip_tile.src_tile_id != AlphaTileId(!0) {
|
&& clip_tile.src_tile_id != AlphaTileId(!0)
|
||||||
|
{
|
||||||
draw_tile_batch.clips.push(*clip_tile);
|
draw_tile_batch.clips.push(*clip_tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1017,22 +1100,25 @@ impl TileBatchBuilder {
|
||||||
|
|
||||||
match draw_tile_batch {
|
match draw_tile_batch {
|
||||||
Some(DrawTileBatch::D3D11(draw_tile_batch)) => {
|
Some(DrawTileBatch::D3D11(draw_tile_batch)) => {
|
||||||
self.draw_commands.push(RenderCommand::DrawTilesD3D11(draw_tile_batch));
|
self.draw_commands
|
||||||
|
.push(RenderCommand::DrawTilesD3D11(draw_tile_batch));
|
||||||
}
|
}
|
||||||
Some(DrawTileBatch::D3D9(draw_tile_batch)) => {
|
Some(DrawTileBatch::D3D9(draw_tile_batch)) => {
|
||||||
self.draw_commands.push(RenderCommand::DrawTilesD3D9(draw_tile_batch));
|
self.draw_commands
|
||||||
|
.push(RenderCommand::DrawTilesD3D9(draw_tile_batch));
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_draw_path_for_gpu_binning(&self,
|
fn prepare_draw_path_for_gpu_binning(
|
||||||
|
&self,
|
||||||
scene: &Scene,
|
scene: &Scene,
|
||||||
built_options: &PreparedBuildOptions,
|
built_options: &PreparedBuildOptions,
|
||||||
draw_path_id: DrawPathId,
|
draw_path_id: DrawPathId,
|
||||||
prepare_mode: &PrepareMode,
|
prepare_mode: &PrepareMode,
|
||||||
paint_metadata: &[PaintMetadata])
|
paint_metadata: &[PaintMetadata],
|
||||||
-> Option<BuiltDrawPath> {
|
) -> Option<BuiltDrawPath> {
|
||||||
let transform = match *prepare_mode {
|
let transform = match *prepare_mode {
|
||||||
PrepareMode::GPU { transform } => transform,
|
PrepareMode::GPU { transform } => transform,
|
||||||
PrepareMode::CPU | PrepareMode::TransformCPUBinGPU => {
|
PrepareMode::CPU | PrepareMode::TransformCPUBinGPU => {
|
||||||
|
@ -1051,7 +1137,8 @@ impl TileBatchBuilder {
|
||||||
|
|
||||||
let paint_id = draw_path.paint();
|
let paint_id = draw_path.paint();
|
||||||
let paint_metadata = &paint_metadata[paint_id.0 as usize];
|
let paint_metadata = &paint_metadata[paint_id.0 as usize];
|
||||||
let built_path = BuiltPath::new(draw_path_id.to_path_id(),
|
let built_path = BuiltPath::new(
|
||||||
|
draw_path_id.to_path_id(),
|
||||||
path_bounds,
|
path_bounds,
|
||||||
effective_view_box,
|
effective_view_box,
|
||||||
draw_path.fill_rule(),
|
draw_path.fill_rule(),
|
||||||
|
@ -1061,7 +1148,8 @@ impl TileBatchBuilder {
|
||||||
paint_id,
|
paint_id,
|
||||||
blend_mode: draw_path.blend_mode(),
|
blend_mode: draw_path.blend_mode(),
|
||||||
fill_rule: draw_path.fill_rule(),
|
fill_rule: draw_path.fill_rule(),
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
Some(BuiltDrawPath::new(built_path, draw_path, paint_metadata))
|
Some(BuiltDrawPath::new(built_path, draw_path, paint_metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1069,7 +1157,8 @@ impl TileBatchBuilder {
|
||||||
if let Some(clip_batches_d3d11) = self.clip_batches_d3d11 {
|
if let Some(clip_batches_d3d11) = self.clip_batches_d3d11 {
|
||||||
for prepare_batch in clip_batches_d3d11.prepare_batches.into_iter().rev() {
|
for prepare_batch in clip_batches_d3d11.prepare_batches.into_iter().rev() {
|
||||||
if prepare_batch.path_count > 0 {
|
if prepare_batch.path_count > 0 {
|
||||||
sink.listener.send(RenderCommand::PrepareClipTilesD3D11(prepare_batch));
|
sink.listener
|
||||||
|
.send(RenderCommand::PrepareClipTilesD3D11(prepare_batch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1089,52 +1178,61 @@ struct ClipBatchesD3D11 {
|
||||||
clip_id_to_path_batch_index: FxHashMap<ClipPathId, PathBatchIndex>,
|
clip_id_to_path_batch_index: FxHashMap<ClipPathId, PathBatchIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_clip_path_to_batch(scene: &Scene,
|
fn add_clip_path_to_batch(
|
||||||
|
scene: &Scene,
|
||||||
sink: &SceneSink,
|
sink: &SceneSink,
|
||||||
built_options: &PreparedBuildOptions,
|
built_options: &PreparedBuildOptions,
|
||||||
clip_path_id: Option<ClipPathId>,
|
clip_path_id: Option<ClipPathId>,
|
||||||
prepare_mode: &PrepareMode,
|
prepare_mode: &PrepareMode,
|
||||||
clip_level: usize,
|
clip_level: usize,
|
||||||
clip_batches_d3d11: &mut ClipBatchesD3D11)
|
clip_batches_d3d11: &mut ClipBatchesD3D11,
|
||||||
-> Option<GlobalPathId> {
|
) -> Option<GlobalPathId> {
|
||||||
match clip_path_id {
|
match clip_path_id {
|
||||||
None => None,
|
None => None,
|
||||||
Some(clip_path_id) => {
|
Some(clip_path_id) => {
|
||||||
match clip_batches_d3d11.clip_id_to_path_batch_index.get(&clip_path_id) {
|
match clip_batches_d3d11
|
||||||
Some(&clip_path_batch_index) => {
|
.clip_id_to_path_batch_index
|
||||||
Some(GlobalPathId {
|
.get(&clip_path_id)
|
||||||
|
{
|
||||||
|
Some(&clip_path_batch_index) => Some(GlobalPathId {
|
||||||
batch_id: TileBatchId(clip_level as u32),
|
batch_id: TileBatchId(clip_level as u32),
|
||||||
path_index: clip_path_batch_index,
|
path_index: clip_path_batch_index,
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
let PreparedClipPath {
|
let PreparedClipPath {
|
||||||
built_path: clip_path,
|
built_path: clip_path,
|
||||||
subclip_id
|
subclip_id,
|
||||||
} = prepare_clip_path_for_gpu_binning(scene,
|
} = prepare_clip_path_for_gpu_binning(
|
||||||
|
scene,
|
||||||
sink,
|
sink,
|
||||||
built_options,
|
built_options,
|
||||||
clip_path_id,
|
clip_path_id,
|
||||||
prepare_mode,
|
prepare_mode,
|
||||||
clip_level,
|
clip_level,
|
||||||
clip_batches_d3d11);
|
clip_batches_d3d11,
|
||||||
|
);
|
||||||
while clip_level >= clip_batches_d3d11.prepare_batches.len() {
|
while clip_level >= clip_batches_d3d11.prepare_batches.len() {
|
||||||
let clip_tile_batch_id =
|
let clip_tile_batch_id =
|
||||||
TileBatchId(clip_batches_d3d11.prepare_batches.len() as u32);
|
TileBatchId(clip_batches_d3d11.prepare_batches.len() as u32);
|
||||||
clip_batches_d3d11.prepare_batches
|
clip_batches_d3d11
|
||||||
.push(TileBatchDataD3D11::new(clip_tile_batch_id,
|
.prepare_batches
|
||||||
|
.push(TileBatchDataD3D11::new(
|
||||||
|
clip_tile_batch_id,
|
||||||
&prepare_mode,
|
&prepare_mode,
|
||||||
PathSource::Clip));
|
PathSource::Clip,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
let clip_path_batch_index =
|
let clip_path_batch_index = clip_batches_d3d11.prepare_batches[clip_level]
|
||||||
clip_batches_d3d11.prepare_batches[clip_level]
|
.push(
|
||||||
.push(&clip_path,
|
&clip_path,
|
||||||
clip_path_id.to_path_id(),
|
clip_path_id.to_path_id(),
|
||||||
subclip_id,
|
subclip_id,
|
||||||
true,
|
true,
|
||||||
sink);
|
sink,
|
||||||
clip_batches_d3d11.clip_id_to_path_batch_index.insert(clip_path_id,
|
);
|
||||||
clip_path_batch_index);
|
clip_batches_d3d11
|
||||||
|
.clip_id_to_path_batch_index
|
||||||
|
.insert(clip_path_id, clip_path_batch_index);
|
||||||
Some(GlobalPathId {
|
Some(GlobalPathId {
|
||||||
batch_id: TileBatchId(clip_level as u32),
|
batch_id: TileBatchId(clip_level as u32),
|
||||||
path_index: clip_path_batch_index,
|
path_index: clip_path_batch_index,
|
||||||
|
@ -1145,14 +1243,15 @@ fn add_clip_path_to_batch(scene: &Scene,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_clip_path_for_gpu_binning(scene: &Scene,
|
fn prepare_clip_path_for_gpu_binning(
|
||||||
|
scene: &Scene,
|
||||||
sink: &SceneSink,
|
sink: &SceneSink,
|
||||||
built_options: &PreparedBuildOptions,
|
built_options: &PreparedBuildOptions,
|
||||||
clip_path_id: ClipPathId,
|
clip_path_id: ClipPathId,
|
||||||
prepare_mode: &PrepareMode,
|
prepare_mode: &PrepareMode,
|
||||||
clip_level: usize,
|
clip_level: usize,
|
||||||
clip_batches_d3d11: &mut ClipBatchesD3D11)
|
clip_batches_d3d11: &mut ClipBatchesD3D11,
|
||||||
-> PreparedClipPath {
|
) -> PreparedClipPath {
|
||||||
let transform = match *prepare_mode {
|
let transform = match *prepare_mode {
|
||||||
PrepareMode::GPU { transform } => transform,
|
PrepareMode::GPU { transform } => transform,
|
||||||
PrepareMode::CPU | PrepareMode::TransformCPUBinGPU => {
|
PrepareMode::CPU | PrepareMode::TransformCPUBinGPU => {
|
||||||
|
@ -1163,27 +1262,34 @@ fn prepare_clip_path_for_gpu_binning(scene: &Scene,
|
||||||
let clip_path = scene.get_clip_path(clip_path_id);
|
let clip_path = scene.get_clip_path(clip_path_id);
|
||||||
|
|
||||||
// Add subclip path if necessary.
|
// Add subclip path if necessary.
|
||||||
let subclip_id = add_clip_path_to_batch(scene,
|
let subclip_id = add_clip_path_to_batch(
|
||||||
|
scene,
|
||||||
sink,
|
sink,
|
||||||
built_options,
|
built_options,
|
||||||
clip_path.clip_path(),
|
clip_path.clip_path(),
|
||||||
prepare_mode,
|
prepare_mode,
|
||||||
clip_level + 1,
|
clip_level + 1,
|
||||||
clip_batches_d3d11);
|
clip_batches_d3d11,
|
||||||
|
);
|
||||||
|
|
||||||
let path_bounds = transform * clip_path.outline().bounds();
|
let path_bounds = transform * clip_path.outline().bounds();
|
||||||
|
|
||||||
// TODO(pcwalton): Clip to view box!
|
// TODO(pcwalton): Clip to view box!
|
||||||
|
|
||||||
let built_path = BuiltPath::new(clip_path_id.to_path_id(),
|
let built_path = BuiltPath::new(
|
||||||
|
clip_path_id.to_path_id(),
|
||||||
path_bounds,
|
path_bounds,
|
||||||
effective_view_box,
|
effective_view_box,
|
||||||
clip_path.fill_rule(),
|
clip_path.fill_rule(),
|
||||||
&prepare_mode,
|
&prepare_mode,
|
||||||
clip_path.clip_path(),
|
clip_path.clip_path(),
|
||||||
&TilingPathInfo::Clip);
|
&TilingPathInfo::Clip,
|
||||||
|
);
|
||||||
|
|
||||||
PreparedClipPath { built_path, subclip_id }
|
PreparedClipPath {
|
||||||
|
built_path,
|
||||||
|
subclip_id,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PreparedClipPath {
|
struct PreparedClipPath {
|
||||||
|
@ -1191,18 +1297,20 @@ struct PreparedClipPath {
|
||||||
subclip_id: Option<GlobalPathId>,
|
subclip_id: Option<GlobalPathId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fixup_batch_for_new_path_if_possible(batch_color_texture: &mut Option<TileBatchTexture>,
|
fn fixup_batch_for_new_path_if_possible(
|
||||||
draw_path: &BuiltDrawPath)
|
batch_color_texture: &mut Option<TileBatchTexture>,
|
||||||
-> bool {
|
draw_path: &BuiltDrawPath,
|
||||||
|
) -> bool {
|
||||||
if draw_path.color_texture.is_some() {
|
if draw_path.color_texture.is_some() {
|
||||||
if batch_color_texture.is_none() {
|
if batch_color_texture.is_none() {
|
||||||
*batch_color_texture = draw_path.color_texture;
|
*batch_color_texture = draw_path.color_texture;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if draw_path.color_texture != *batch_color_texture {
|
if draw_path.color_texture != *batch_color_texture {
|
||||||
debug!("batch break: path color texture {:?} batch color texture {:?}",
|
debug!(
|
||||||
draw_path.color_texture,
|
"batch break: path color texture {:?} batch color texture {:?}",
|
||||||
batch_color_texture);
|
draw_path.color_texture, batch_color_texture
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ pub trait Executor {
|
||||||
/// (0..length).into_par_iter().map(builder).collect()
|
/// (0..length).into_par_iter().map(builder).collect()
|
||||||
/// ```
|
/// ```
|
||||||
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
|
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
|
||||||
where T: Send, F: Fn(usize) -> T + Send + Sync;
|
where
|
||||||
|
T: Send,
|
||||||
|
F: Fn(usize) -> T + Send + Sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An executor that simply executes tasks sequentially in the same thread.
|
/// An executor that simply executes tasks sequentially in the same thread.
|
||||||
|
@ -26,7 +28,10 @@ pub struct SequentialExecutor;
|
||||||
|
|
||||||
impl Executor for SequentialExecutor {
|
impl Executor for SequentialExecutor {
|
||||||
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
|
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
|
||||||
where T: Send, F: Fn(usize) -> T + Send + Sync {
|
where
|
||||||
|
T: Send,
|
||||||
|
F: Fn(usize) -> T + Send + Sync,
|
||||||
|
{
|
||||||
(0..length).into_iter().map(builder).collect()
|
(0..length).into_iter().map(builder).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,10 @@ pub struct RayonExecutor;
|
||||||
|
|
||||||
impl Executor for RayonExecutor {
|
impl Executor for RayonExecutor {
|
||||||
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
|
fn build_vector<T, F>(&self, length: usize, builder: F) -> Vec<T>
|
||||||
where T: Send, F: Fn(usize) -> T + Send + Sync {
|
where
|
||||||
|
T: Send,
|
||||||
|
F: Fn(usize) -> T + Send + Sync,
|
||||||
|
{
|
||||||
(0..length).into_par_iter().map(builder).collect()
|
(0..length).into_par_iter().map(builder).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,9 @@ impl SceneProxy {
|
||||||
/// want to use a single thread (perhaps because you're in a WebAssembly environment), pass a
|
/// want to use a single thread (perhaps because you're in a WebAssembly environment), pass a
|
||||||
/// `SequentialExecutor`.
|
/// `SequentialExecutor`.
|
||||||
pub fn new<E>(renderer_level: RendererLevel, executor: E) -> SceneProxy
|
pub fn new<E>(renderer_level: RendererLevel, executor: E) -> SceneProxy
|
||||||
where E: Executor + Send + 'static {
|
where
|
||||||
|
E: Executor + Send + 'static,
|
||||||
|
{
|
||||||
SceneProxy::from_scene(Scene::new(), renderer_level, executor)
|
SceneProxy::from_scene(Scene::new(), renderer_level, executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,9 +58,10 @@ impl SceneProxy {
|
||||||
/// If you want to use multiple threads, you typically pass in a `RayonExecutor` here. If you
|
/// If you want to use multiple threads, you typically pass in a `RayonExecutor` here. If you
|
||||||
/// want to use a single thread (perhaps because you're in a WebAssembly environment), pass a
|
/// want to use a single thread (perhaps because you're in a WebAssembly environment), pass a
|
||||||
/// `SequentialExecutor`.
|
/// `SequentialExecutor`.
|
||||||
pub fn from_scene<E>(scene: Scene, renderer_level: RendererLevel, executor: E)
|
pub fn from_scene<E>(scene: Scene, renderer_level: RendererLevel, executor: E) -> SceneProxy
|
||||||
-> SceneProxy
|
where
|
||||||
where E: Executor + Send + 'static {
|
E: Executor + Send + 'static,
|
||||||
|
{
|
||||||
let (main_to_worker_sender, main_to_worker_receiver) =
|
let (main_to_worker_sender, main_to_worker_receiver) =
|
||||||
flume::bounded(MAX_MESSAGES_IN_FLIGHT);
|
flume::bounded(MAX_MESSAGES_IN_FLIGHT);
|
||||||
let (worker_to_main_sender, worker_to_main_receiver) =
|
let (worker_to_main_sender, worker_to_main_receiver) =
|
||||||
|
@ -68,19 +71,26 @@ impl SceneProxy {
|
||||||
}));
|
}));
|
||||||
let sink = SceneSink::new(listener, renderer_level);
|
let sink = SceneSink::new(listener, renderer_level);
|
||||||
thread::spawn(move || scene_thread(scene, executor, sink, main_to_worker_receiver));
|
thread::spawn(move || scene_thread(scene, executor, sink, main_to_worker_receiver));
|
||||||
SceneProxy { sender: main_to_worker_sender, receiver: worker_to_main_receiver }
|
SceneProxy {
|
||||||
|
sender: main_to_worker_sender,
|
||||||
|
receiver: worker_to_main_receiver,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the wrapped scene with a new one, discarding the old scene.
|
/// Replaces the wrapped scene with a new one, discarding the old scene.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn replace_scene(&self, new_scene: Scene) {
|
pub fn replace_scene(&self, new_scene: Scene) {
|
||||||
self.sender.send(MainToWorkerMsg::ReplaceScene(new_scene)).unwrap();
|
self.sender
|
||||||
|
.send(MainToWorkerMsg::ReplaceScene(new_scene))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the view box of the scene, which defines the visible rectangle.
|
/// Sets the view box of the scene, which defines the visible rectangle.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_view_box(&self, new_view_box: RectF) {
|
pub fn set_view_box(&self, new_view_box: RectF) {
|
||||||
self.sender.send(MainToWorkerMsg::SetViewBox(new_view_box)).unwrap();
|
self.sender
|
||||||
|
.send(MainToWorkerMsg::SetViewBox(new_view_box))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a scene and queues up the commands needed to render it.
|
/// Constructs a scene and queues up the commands needed to render it.
|
||||||
|
@ -91,7 +101,10 @@ impl SceneProxy {
|
||||||
|
|
||||||
/// Sends all queued commands to the given renderer to render the wrapped scene.
|
/// Sends all queued commands to the given renderer to render the wrapped scene.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn render<D>(&mut self, renderer: &mut Renderer<D>) where D: Device {
|
pub fn render<D>(&mut self, renderer: &mut Renderer<D>)
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
renderer.begin_scene();
|
renderer.begin_scene();
|
||||||
while let Ok(command) = self.receiver.recv() {
|
while let Ok(command) = self.receiver.recv() {
|
||||||
renderer.render_command(&command);
|
renderer.render_command(&command);
|
||||||
|
@ -114,7 +127,9 @@ impl SceneProxy {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_and_render<D>(&mut self, renderer: &mut Renderer<D>, build_options: BuildOptions)
|
pub fn build_and_render<D>(&mut self, renderer: &mut Renderer<D>, build_options: BuildOptions)
|
||||||
where D: Device {
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
self.build(build_options);
|
self.build(build_options);
|
||||||
self.render(renderer);
|
self.render(renderer);
|
||||||
}
|
}
|
||||||
|
@ -123,16 +138,21 @@ impl SceneProxy {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn copy_scene(&self) -> Scene {
|
pub fn copy_scene(&self) -> Scene {
|
||||||
let (sender, receiver) = flume::bounded(MAX_MESSAGES_IN_FLIGHT);
|
let (sender, receiver) = flume::bounded(MAX_MESSAGES_IN_FLIGHT);
|
||||||
self.sender.send(MainToWorkerMsg::CopyScene(sender)).unwrap();
|
self.sender
|
||||||
|
.send(MainToWorkerMsg::CopyScene(sender))
|
||||||
|
.unwrap();
|
||||||
receiver.recv().unwrap()
|
receiver.recv().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scene_thread<E>(mut scene: Scene,
|
fn scene_thread<E>(
|
||||||
|
mut scene: Scene,
|
||||||
executor: E,
|
executor: E,
|
||||||
mut sink: SceneSink<'static>,
|
mut sink: SceneSink<'static>,
|
||||||
main_to_worker_receiver: Receiver<MainToWorkerMsg>)
|
main_to_worker_receiver: Receiver<MainToWorkerMsg>,
|
||||||
where E: Executor {
|
) where
|
||||||
|
E: Executor,
|
||||||
|
{
|
||||||
while let Ok(msg) = main_to_worker_receiver.recv() {
|
while let Ok(msg) = main_to_worker_receiver.recv() {
|
||||||
match msg {
|
match msg {
|
||||||
MainToWorkerMsg::ReplaceScene(new_scene) => scene = new_scene,
|
MainToWorkerMsg::ReplaceScene(new_scene) => scene = new_scene,
|
||||||
|
|
|
@ -42,121 +42,99 @@ pub(crate) trait ToBlendState {
|
||||||
impl ToBlendState for BlendMode {
|
impl ToBlendState for BlendMode {
|
||||||
fn to_blend_state(self) -> Option<BlendState> {
|
fn to_blend_state(self) -> Option<BlendState> {
|
||||||
match self {
|
match self {
|
||||||
BlendMode::Clear => {
|
BlendMode::Clear => Some(BlendState {
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::Zero,
|
src_rgb_factor: BlendFactor::Zero,
|
||||||
dest_rgb_factor: BlendFactor::Zero,
|
dest_rgb_factor: BlendFactor::Zero,
|
||||||
src_alpha_factor: BlendFactor::Zero,
|
src_alpha_factor: BlendFactor::Zero,
|
||||||
dest_alpha_factor: BlendFactor::Zero,
|
dest_alpha_factor: BlendFactor::Zero,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::SrcOver => Some(BlendState {
|
||||||
BlendMode::SrcOver => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::One,
|
src_rgb_factor: BlendFactor::One,
|
||||||
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
src_alpha_factor: BlendFactor::One,
|
src_alpha_factor: BlendFactor::One,
|
||||||
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::DestOver => Some(BlendState {
|
||||||
BlendMode::DestOver => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_rgb_factor: BlendFactor::One,
|
dest_rgb_factor: BlendFactor::One,
|
||||||
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_alpha_factor: BlendFactor::One,
|
dest_alpha_factor: BlendFactor::One,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::SrcIn => Some(BlendState {
|
||||||
BlendMode::SrcIn => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::DestAlpha,
|
src_rgb_factor: BlendFactor::DestAlpha,
|
||||||
dest_rgb_factor: BlendFactor::Zero,
|
dest_rgb_factor: BlendFactor::Zero,
|
||||||
src_alpha_factor: BlendFactor::DestAlpha,
|
src_alpha_factor: BlendFactor::DestAlpha,
|
||||||
dest_alpha_factor: BlendFactor::Zero,
|
dest_alpha_factor: BlendFactor::Zero,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::DestIn => Some(BlendState {
|
||||||
BlendMode::DestIn => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::Zero,
|
src_rgb_factor: BlendFactor::Zero,
|
||||||
dest_rgb_factor: BlendFactor::SrcAlpha,
|
dest_rgb_factor: BlendFactor::SrcAlpha,
|
||||||
src_alpha_factor: BlendFactor::Zero,
|
src_alpha_factor: BlendFactor::Zero,
|
||||||
dest_alpha_factor: BlendFactor::SrcAlpha,
|
dest_alpha_factor: BlendFactor::SrcAlpha,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::SrcOut => Some(BlendState {
|
||||||
BlendMode::SrcOut => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_rgb_factor: BlendFactor::Zero,
|
dest_rgb_factor: BlendFactor::Zero,
|
||||||
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_alpha_factor: BlendFactor::Zero,
|
dest_alpha_factor: BlendFactor::Zero,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::DestOut => Some(BlendState {
|
||||||
BlendMode::DestOut => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::Zero,
|
src_rgb_factor: BlendFactor::Zero,
|
||||||
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
src_alpha_factor: BlendFactor::Zero,
|
src_alpha_factor: BlendFactor::Zero,
|
||||||
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::SrcAtop => Some(BlendState {
|
||||||
BlendMode::SrcAtop => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::DestAlpha,
|
src_rgb_factor: BlendFactor::DestAlpha,
|
||||||
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
src_alpha_factor: BlendFactor::DestAlpha,
|
src_alpha_factor: BlendFactor::DestAlpha,
|
||||||
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::DestAtop => Some(BlendState {
|
||||||
BlendMode::DestAtop => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_rgb_factor: BlendFactor::SrcAlpha,
|
dest_rgb_factor: BlendFactor::SrcAlpha,
|
||||||
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_alpha_factor: BlendFactor::SrcAlpha,
|
dest_alpha_factor: BlendFactor::SrcAlpha,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::Xor => Some(BlendState {
|
||||||
BlendMode::Xor => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::Lighter => Some(BlendState {
|
||||||
BlendMode::Lighter => {
|
|
||||||
Some(BlendState {
|
|
||||||
src_rgb_factor: BlendFactor::One,
|
src_rgb_factor: BlendFactor::One,
|
||||||
dest_rgb_factor: BlendFactor::One,
|
dest_rgb_factor: BlendFactor::One,
|
||||||
src_alpha_factor: BlendFactor::One,
|
src_alpha_factor: BlendFactor::One,
|
||||||
dest_alpha_factor: BlendFactor::One,
|
dest_alpha_factor: BlendFactor::One,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
})
|
}),
|
||||||
}
|
BlendMode::Copy
|
||||||
BlendMode::Copy |
|
| BlendMode::Darken
|
||||||
BlendMode::Darken |
|
| BlendMode::Lighten
|
||||||
BlendMode::Lighten |
|
| BlendMode::Multiply
|
||||||
BlendMode::Multiply |
|
| BlendMode::Screen
|
||||||
BlendMode::Screen |
|
| BlendMode::HardLight
|
||||||
BlendMode::HardLight |
|
| BlendMode::Overlay
|
||||||
BlendMode::Overlay |
|
| BlendMode::ColorDodge
|
||||||
BlendMode::ColorDodge |
|
| BlendMode::ColorBurn
|
||||||
BlendMode::ColorBurn |
|
| BlendMode::SoftLight
|
||||||
BlendMode::SoftLight |
|
| BlendMode::Difference
|
||||||
BlendMode::Difference |
|
| BlendMode::Exclusion
|
||||||
BlendMode::Exclusion |
|
| BlendMode::Hue
|
||||||
BlendMode::Hue |
|
| BlendMode::Saturation
|
||||||
BlendMode::Saturation |
|
| BlendMode::Color
|
||||||
BlendMode::Color |
|
| BlendMode::Luminosity => {
|
||||||
BlendMode::Luminosity => {
|
|
||||||
// Blending is done manually in the shader.
|
// Blending is done manually in the shader.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -171,18 +149,18 @@ pub(crate) trait ToCompositeCtrl {
|
||||||
impl ToCompositeCtrl for BlendMode {
|
impl ToCompositeCtrl for BlendMode {
|
||||||
fn to_composite_ctrl(&self) -> i32 {
|
fn to_composite_ctrl(&self) -> i32 {
|
||||||
match *self {
|
match *self {
|
||||||
BlendMode::SrcOver |
|
BlendMode::SrcOver
|
||||||
BlendMode::SrcAtop |
|
| BlendMode::SrcAtop
|
||||||
BlendMode::DestOver |
|
| BlendMode::DestOver
|
||||||
BlendMode::DestOut |
|
| BlendMode::DestOut
|
||||||
BlendMode::Xor |
|
| BlendMode::Xor
|
||||||
BlendMode::Lighter |
|
| BlendMode::Lighter
|
||||||
BlendMode::Clear |
|
| BlendMode::Clear
|
||||||
BlendMode::Copy |
|
| BlendMode::Copy
|
||||||
BlendMode::SrcIn |
|
| BlendMode::SrcIn
|
||||||
BlendMode::SrcOut |
|
| BlendMode::SrcOut
|
||||||
BlendMode::DestIn |
|
| BlendMode::DestIn
|
||||||
BlendMode::DestAtop => COMBINER_CTRL_COMPOSITE_NORMAL,
|
| BlendMode::DestAtop => COMBINER_CTRL_COMPOSITE_NORMAL,
|
||||||
BlendMode::Multiply => COMBINER_CTRL_COMPOSITE_MULTIPLY,
|
BlendMode::Multiply => COMBINER_CTRL_COMPOSITE_MULTIPLY,
|
||||||
BlendMode::Darken => COMBINER_CTRL_COMPOSITE_DARKEN,
|
BlendMode::Darken => COMBINER_CTRL_COMPOSITE_DARKEN,
|
||||||
BlendMode::Lighten => COMBINER_CTRL_COMPOSITE_LIGHTEN,
|
BlendMode::Lighten => COMBINER_CTRL_COMPOSITE_LIGHTEN,
|
||||||
|
@ -219,33 +197,33 @@ pub trait BlendModeExt {
|
||||||
impl BlendModeExt for BlendMode {
|
impl BlendModeExt for BlendMode {
|
||||||
fn needs_readable_framebuffer(self) -> bool {
|
fn needs_readable_framebuffer(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
BlendMode::Clear |
|
BlendMode::Clear
|
||||||
BlendMode::SrcOver |
|
| BlendMode::SrcOver
|
||||||
BlendMode::DestOver |
|
| BlendMode::DestOver
|
||||||
BlendMode::SrcIn |
|
| BlendMode::SrcIn
|
||||||
BlendMode::DestIn |
|
| BlendMode::DestIn
|
||||||
BlendMode::SrcOut |
|
| BlendMode::SrcOut
|
||||||
BlendMode::DestOut |
|
| BlendMode::DestOut
|
||||||
BlendMode::SrcAtop |
|
| BlendMode::SrcAtop
|
||||||
BlendMode::DestAtop |
|
| BlendMode::DestAtop
|
||||||
BlendMode::Xor |
|
| BlendMode::Xor
|
||||||
BlendMode::Lighter |
|
| BlendMode::Lighter
|
||||||
BlendMode::Copy => false,
|
| BlendMode::Copy => false,
|
||||||
BlendMode::Lighten |
|
BlendMode::Lighten
|
||||||
BlendMode::Darken |
|
| BlendMode::Darken
|
||||||
BlendMode::Multiply |
|
| BlendMode::Multiply
|
||||||
BlendMode::Screen |
|
| BlendMode::Screen
|
||||||
BlendMode::HardLight |
|
| BlendMode::HardLight
|
||||||
BlendMode::Overlay |
|
| BlendMode::Overlay
|
||||||
BlendMode::ColorDodge |
|
| BlendMode::ColorDodge
|
||||||
BlendMode::ColorBurn |
|
| BlendMode::ColorBurn
|
||||||
BlendMode::SoftLight |
|
| BlendMode::SoftLight
|
||||||
BlendMode::Difference |
|
| BlendMode::Difference
|
||||||
BlendMode::Exclusion |
|
| BlendMode::Exclusion
|
||||||
BlendMode::Hue |
|
| BlendMode::Hue
|
||||||
BlendMode::Saturation |
|
| BlendMode::Saturation
|
||||||
BlendMode::Color |
|
| BlendMode::Color
|
||||||
BlendMode::Luminosity => true,
|
| BlendMode::Luminosity => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -21,7 +21,10 @@ pub(crate) const BIN_WORKGROUP_SIZE: u32 = 64;
|
||||||
pub(crate) const PROPAGATE_WORKGROUP_SIZE: u32 = 64;
|
pub(crate) const PROPAGATE_WORKGROUP_SIZE: u32 = 64;
|
||||||
pub(crate) const SORT_WORKGROUP_SIZE: u32 = 64;
|
pub(crate) const SORT_WORKGROUP_SIZE: u32 = 64;
|
||||||
|
|
||||||
pub(crate) struct ProgramsD3D11<D> where D: Device {
|
pub(crate) struct ProgramsD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) bound_program: BoundProgramD3D11<D>,
|
pub(crate) bound_program: BoundProgramD3D11<D>,
|
||||||
pub(crate) dice_program: DiceProgramD3D11<D>,
|
pub(crate) dice_program: DiceProgramD3D11<D>,
|
||||||
pub(crate) bin_program: BinProgramD3D11<D>,
|
pub(crate) bin_program: BinProgramD3D11<D>,
|
||||||
|
@ -31,7 +34,10 @@ pub(crate) struct ProgramsD3D11<D> where D: Device {
|
||||||
pub(crate) tile_program: TileProgramD3D11<D>,
|
pub(crate) tile_program: TileProgramD3D11<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ProgramsD3D11<D> where D: Device {
|
impl<D> ProgramsD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D11<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D11<D> {
|
||||||
ProgramsD3D11 {
|
ProgramsD3D11 {
|
||||||
bound_program: BoundProgramD3D11::new(device, resources),
|
bound_program: BoundProgramD3D11::new(device, resources),
|
||||||
|
@ -45,7 +51,10 @@ impl<D> ProgramsD3D11<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PropagateProgramD3D11<D> where D: Device {
|
pub(crate) struct PropagateProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) framebuffer_tile_size_uniform: D::Uniform,
|
pub(crate) framebuffer_tile_size_uniform: D::Uniform,
|
||||||
pub(crate) column_count_uniform: D::Uniform,
|
pub(crate) column_count_uniform: D::Uniform,
|
||||||
|
@ -60,10 +69,17 @@ pub(crate) struct PropagateProgramD3D11<D> where D: Device {
|
||||||
pub(crate) alpha_tiles_storage_buffer: D::StorageBuffer,
|
pub(crate) alpha_tiles_storage_buffer: D::StorageBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> PropagateProgramD3D11<D> where D: Device {
|
impl<D> PropagateProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> PropagateProgramD3D11<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> PropagateProgramD3D11<D> {
|
||||||
let mut program = device.create_compute_program(resources, "d3d11/propagate");
|
let mut program = device.create_compute_program(resources, "d3d11/propagate");
|
||||||
let local_size = ComputeDimensions { x: PROPAGATE_WORKGROUP_SIZE, y: 1, z: 1 };
|
let local_size = ComputeDimensions {
|
||||||
|
x: PROPAGATE_WORKGROUP_SIZE,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
device.set_compute_program_local_size(&mut program, local_size);
|
device.set_compute_program_local_size(&mut program, local_size);
|
||||||
|
|
||||||
let framebuffer_tile_size_uniform = device.get_uniform(&program, "FramebufferTileSize");
|
let framebuffer_tile_size_uniform = device.get_uniform(&program, "FramebufferTileSize");
|
||||||
|
@ -95,7 +111,10 @@ impl<D> PropagateProgramD3D11<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FillProgramD3D11<D> where D: Device {
|
pub(crate) struct FillProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) dest_image: D::ImageParameter,
|
pub(crate) dest_image: D::ImageParameter,
|
||||||
pub(crate) area_lut_texture: D::TextureParameter,
|
pub(crate) area_lut_texture: D::TextureParameter,
|
||||||
|
@ -105,10 +124,17 @@ pub(crate) struct FillProgramD3D11<D> where D: Device {
|
||||||
pub(crate) alpha_tiles_storage_buffer: D::StorageBuffer,
|
pub(crate) alpha_tiles_storage_buffer: D::StorageBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> FillProgramD3D11<D> where D: Device {
|
impl<D> FillProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgramD3D11<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgramD3D11<D> {
|
||||||
let mut program = device.create_compute_program(resources, "d3d11/fill");
|
let mut program = device.create_compute_program(resources, "d3d11/fill");
|
||||||
let local_size = ComputeDimensions { x: TILE_WIDTH, y: TILE_HEIGHT / 4, z: 1 };
|
let local_size = ComputeDimensions {
|
||||||
|
x: TILE_WIDTH,
|
||||||
|
y: TILE_HEIGHT / 4,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
device.set_compute_program_local_size(&mut program, local_size);
|
device.set_compute_program_local_size(&mut program, local_size);
|
||||||
|
|
||||||
let dest_image = device.get_image_parameter(&program, "Dest");
|
let dest_image = device.get_image_parameter(&program, "Dest");
|
||||||
|
@ -130,7 +156,10 @@ impl<D> FillProgramD3D11<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct TileProgramD3D11<D> where D: Device {
|
pub(crate) struct TileProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) common: TileProgramCommon<D>,
|
pub(crate) common: TileProgramCommon<D>,
|
||||||
pub(crate) load_action_uniform: D::Uniform,
|
pub(crate) load_action_uniform: D::Uniform,
|
||||||
pub(crate) clear_color_uniform: D::Uniform,
|
pub(crate) clear_color_uniform: D::Uniform,
|
||||||
|
@ -140,11 +169,14 @@ pub(crate) struct TileProgramD3D11<D> where D: Device {
|
||||||
pub(crate) first_tile_map_storage_buffer: D::StorageBuffer,
|
pub(crate) first_tile_map_storage_buffer: D::StorageBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> TileProgramD3D11<D> where D: Device {
|
impl<D> TileProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgramD3D11<D> {
|
fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgramD3D11<D> {
|
||||||
let mut program = device.create_compute_program(resources, "d3d11/tile");
|
let mut program = device.create_compute_program(resources, "d3d11/tile");
|
||||||
device.set_compute_program_local_size(&mut program,
|
device
|
||||||
ComputeDimensions { x: 16, y: 4, z: 1 });
|
.set_compute_program_local_size(&mut program, ComputeDimensions { x: 16, y: 4, z: 1 });
|
||||||
|
|
||||||
let load_action_uniform = device.get_uniform(&program, "LoadAction");
|
let load_action_uniform = device.get_uniform(&program, "LoadAction");
|
||||||
let clear_color_uniform = device.get_uniform(&program, "ClearColor");
|
let clear_color_uniform = device.get_uniform(&program, "ClearColor");
|
||||||
|
@ -166,7 +198,10 @@ impl<D> TileProgramD3D11<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct BinProgramD3D11<D> where D: Device {
|
pub(crate) struct BinProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) microline_count_uniform: D::Uniform,
|
pub(crate) microline_count_uniform: D::Uniform,
|
||||||
pub(crate) max_fill_count_uniform: D::Uniform,
|
pub(crate) max_fill_count_uniform: D::Uniform,
|
||||||
|
@ -178,10 +213,17 @@ pub(crate) struct BinProgramD3D11<D> where D: Device {
|
||||||
pub(crate) backdrops_storage_buffer: D::StorageBuffer,
|
pub(crate) backdrops_storage_buffer: D::StorageBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> BinProgramD3D11<D> where D: Device {
|
impl<D> BinProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BinProgramD3D11<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BinProgramD3D11<D> {
|
||||||
let mut program = device.create_compute_program(resources, "d3d11/bin");
|
let mut program = device.create_compute_program(resources, "d3d11/bin");
|
||||||
let dimensions = ComputeDimensions { x: BIN_WORKGROUP_SIZE, y: 1, z: 1 };
|
let dimensions = ComputeDimensions {
|
||||||
|
x: BIN_WORKGROUP_SIZE,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
device.set_compute_program_local_size(&mut program, dimensions);
|
device.set_compute_program_local_size(&mut program, dimensions);
|
||||||
|
|
||||||
let microline_count_uniform = device.get_uniform(&program, "MicrolineCount");
|
let microline_count_uniform = device.get_uniform(&program, "MicrolineCount");
|
||||||
|
@ -209,7 +251,10 @@ impl<D> BinProgramD3D11<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DiceProgramD3D11<D> where D: Device {
|
pub(crate) struct DiceProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) transform_uniform: D::Uniform,
|
pub(crate) transform_uniform: D::Uniform,
|
||||||
pub(crate) translation_uniform: D::Uniform,
|
pub(crate) translation_uniform: D::Uniform,
|
||||||
|
@ -223,17 +268,24 @@ pub(crate) struct DiceProgramD3D11<D> where D: Device {
|
||||||
pub(crate) microlines_storage_buffer: D::StorageBuffer,
|
pub(crate) microlines_storage_buffer: D::StorageBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> DiceProgramD3D11<D> where D: Device {
|
impl<D> DiceProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> DiceProgramD3D11<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> DiceProgramD3D11<D> {
|
||||||
let mut program = device.create_compute_program(resources, "d3d11/dice");
|
let mut program = device.create_compute_program(resources, "d3d11/dice");
|
||||||
let dimensions = ComputeDimensions { x: DICE_WORKGROUP_SIZE, y: 1, z: 1 };
|
let dimensions = ComputeDimensions {
|
||||||
|
x: DICE_WORKGROUP_SIZE,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
device.set_compute_program_local_size(&mut program, dimensions);
|
device.set_compute_program_local_size(&mut program, dimensions);
|
||||||
|
|
||||||
let transform_uniform = device.get_uniform(&program, "Transform");
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
let translation_uniform = device.get_uniform(&program, "Translation");
|
let translation_uniform = device.get_uniform(&program, "Translation");
|
||||||
let path_count_uniform = device.get_uniform(&program, "PathCount");
|
let path_count_uniform = device.get_uniform(&program, "PathCount");
|
||||||
let last_batch_segment_index_uniform = device.get_uniform(&program,
|
let last_batch_segment_index_uniform =
|
||||||
"LastBatchSegmentIndex");
|
device.get_uniform(&program, "LastBatchSegmentIndex");
|
||||||
let max_microline_count_uniform = device.get_uniform(&program, "MaxMicrolineCount");
|
let max_microline_count_uniform = device.get_uniform(&program, "MaxMicrolineCount");
|
||||||
|
|
||||||
let compute_indirect_params_storage_buffer =
|
let compute_indirect_params_storage_buffer =
|
||||||
|
@ -259,7 +311,10 @@ impl<D> DiceProgramD3D11<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct BoundProgramD3D11<D> where D: Device {
|
pub(crate) struct BoundProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) path_count_uniform: D::Uniform,
|
pub(crate) path_count_uniform: D::Uniform,
|
||||||
pub(crate) tile_count_uniform: D::Uniform,
|
pub(crate) tile_count_uniform: D::Uniform,
|
||||||
|
@ -267,10 +322,17 @@ pub(crate) struct BoundProgramD3D11<D> where D: Device {
|
||||||
pub(crate) tiles_storage_buffer: D::StorageBuffer,
|
pub(crate) tiles_storage_buffer: D::StorageBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> BoundProgramD3D11<D> where D: Device {
|
impl<D> BoundProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BoundProgramD3D11<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BoundProgramD3D11<D> {
|
||||||
let mut program = device.create_compute_program(resources, "d3d11/bound");
|
let mut program = device.create_compute_program(resources, "d3d11/bound");
|
||||||
let dimensions = ComputeDimensions { x: BOUND_WORKGROUP_SIZE, y: 1, z: 1 };
|
let dimensions = ComputeDimensions {
|
||||||
|
x: BOUND_WORKGROUP_SIZE,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
device.set_compute_program_local_size(&mut program, dimensions);
|
device.set_compute_program_local_size(&mut program, dimensions);
|
||||||
|
|
||||||
let path_count_uniform = device.get_uniform(&program, "PathCount");
|
let path_count_uniform = device.get_uniform(&program, "PathCount");
|
||||||
|
@ -289,7 +351,10 @@ impl<D> BoundProgramD3D11<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct SortProgramD3D11<D> where D: Device {
|
pub(crate) struct SortProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) tile_count_uniform: D::Uniform,
|
pub(crate) tile_count_uniform: D::Uniform,
|
||||||
pub(crate) tiles_storage_buffer: D::StorageBuffer,
|
pub(crate) tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
@ -297,10 +362,17 @@ pub(crate) struct SortProgramD3D11<D> where D: Device {
|
||||||
pub(crate) z_buffer_storage_buffer: D::StorageBuffer,
|
pub(crate) z_buffer_storage_buffer: D::StorageBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> SortProgramD3D11<D> where D: Device {
|
impl<D> SortProgramD3D11<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> SortProgramD3D11<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> SortProgramD3D11<D> {
|
||||||
let mut program = device.create_compute_program(resources, "d3d11/sort");
|
let mut program = device.create_compute_program(resources, "d3d11/sort");
|
||||||
let dimensions = ComputeDimensions { x: SORT_WORKGROUP_SIZE, y: 1, z: 1 };
|
let dimensions = ComputeDimensions {
|
||||||
|
x: SORT_WORKGROUP_SIZE,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
device.set_compute_program_local_size(&mut program, dimensions);
|
device.set_compute_program_local_size(&mut program, dimensions);
|
||||||
|
|
||||||
let tile_count_uniform = device.get_uniform(&program, "TileCount");
|
let tile_count_uniform = device.get_uniform(&program, "TileCount");
|
||||||
|
|
|
@ -14,12 +14,12 @@
|
||||||
//! WebGL at least 2.0.
|
//! WebGL at least 2.0.
|
||||||
|
|
||||||
use crate::gpu::blend::{BlendModeExt, ToBlendState};
|
use crate::gpu::blend::{BlendModeExt, ToBlendState};
|
||||||
use crate::gpu::perf::TimeCategory;
|
|
||||||
use crate::gpu::renderer::{FramebufferFlags, MASK_FRAMEBUFFER_HEIGHT, MASK_FRAMEBUFFER_WIDTH};
|
|
||||||
use crate::gpu::renderer::{RendererCore, RendererFlags};
|
|
||||||
use crate::gpu::d3d9::shaders::{ClipTileCombineVertexArrayD3D9, ClipTileCopyVertexArrayD3D9};
|
use crate::gpu::d3d9::shaders::{ClipTileCombineVertexArrayD3D9, ClipTileCopyVertexArrayD3D9};
|
||||||
use crate::gpu::d3d9::shaders::{CopyTileVertexArray, FillVertexArrayD3D9};
|
use crate::gpu::d3d9::shaders::{CopyTileVertexArray, FillVertexArrayD3D9};
|
||||||
use crate::gpu::d3d9::shaders::{ProgramsD3D9, TileVertexArrayD3D9};
|
use crate::gpu::d3d9::shaders::{ProgramsD3D9, TileVertexArrayD3D9};
|
||||||
|
use crate::gpu::perf::TimeCategory;
|
||||||
|
use crate::gpu::renderer::{FramebufferFlags, MASK_FRAMEBUFFER_HEIGHT, MASK_FRAMEBUFFER_WIDTH};
|
||||||
|
use crate::gpu::renderer::{RendererCore, RendererFlags};
|
||||||
use crate::gpu_data::{Clip, DrawTileBatchD3D9, Fill, TileBatchTexture, TileObjectPrimitive};
|
use crate::gpu_data::{Clip, DrawTileBatchD3D9, Fill, TileBatchTexture, TileObjectPrimitive};
|
||||||
use crate::tile_map::DenseTileMap;
|
use crate::tile_map::DenseTileMap;
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
|
@ -28,7 +28,7 @@ use pathfinder_color::ColorF;
|
||||||
use pathfinder_content::effects::BlendMode;
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform3d::Transform4F;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, Vector4F, vec2i};
|
use pathfinder_geometry::vector::{vec2i, Vector2I, Vector4F};
|
||||||
use pathfinder_gpu::allocator::{BufferTag, FramebufferID, FramebufferTag, GeneralBufferID};
|
use pathfinder_gpu::allocator::{BufferTag, FramebufferID, FramebufferTag, GeneralBufferID};
|
||||||
use pathfinder_gpu::allocator::{IndexBufferID, TextureID, TextureTag};
|
use pathfinder_gpu::allocator::{IndexBufferID, TextureID, TextureTag};
|
||||||
use pathfinder_gpu::{BlendFactor, BlendState, BufferTarget, ClearOps, Device, Primitive};
|
use pathfinder_gpu::{BlendFactor, BlendState, BufferTarget, ClearOps, Device, Primitive};
|
||||||
|
@ -40,7 +40,10 @@ use std::u32;
|
||||||
|
|
||||||
const MAX_FILLS_PER_BATCH: usize = 0x10000;
|
const MAX_FILLS_PER_BATCH: usize = 0x10000;
|
||||||
|
|
||||||
pub(crate) struct RendererD3D9<D> where D: Device {
|
pub(crate) struct RendererD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
// Basic data
|
// Basic data
|
||||||
programs: ProgramsD3D9<D>,
|
programs: ProgramsD3D9<D>,
|
||||||
quads_vertex_indices_buffer_id: Option<IndexBufferID>,
|
quads_vertex_indices_buffer_id: Option<IndexBufferID>,
|
||||||
|
@ -54,17 +57,23 @@ pub(crate) struct RendererD3D9<D> where D: Device {
|
||||||
dest_blend_framebuffer_id: FramebufferID,
|
dest_blend_framebuffer_id: FramebufferID,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> RendererD3D9<D> where D: Device {
|
impl<D> RendererD3D9<D>
|
||||||
pub(crate) fn new(core: &mut RendererCore<D>, resources: &dyn ResourceLoader)
|
where
|
||||||
-> RendererD3D9<D> {
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
resources: &dyn ResourceLoader,
|
||||||
|
) -> RendererD3D9<D> {
|
||||||
let programs = ProgramsD3D9::new(&core.device, resources);
|
let programs = ProgramsD3D9::new(&core.device, resources);
|
||||||
|
|
||||||
let window_size = core.options.dest.window_size(&core.device);
|
let window_size = core.options.dest.window_size(&core.device);
|
||||||
let dest_blend_framebuffer_id =
|
let dest_blend_framebuffer_id = core.allocator.allocate_framebuffer(
|
||||||
core.allocator.allocate_framebuffer(&core.device,
|
&core.device,
|
||||||
window_size,
|
window_size,
|
||||||
TextureFormat::RGBA8,
|
TextureFormat::RGBA8,
|
||||||
FramebufferTag("DestBlendD3D9"));
|
FramebufferTag("DestBlendD3D9"),
|
||||||
|
);
|
||||||
|
|
||||||
RendererD3D9 {
|
RendererD3D9 {
|
||||||
programs,
|
programs,
|
||||||
|
@ -78,42 +87,56 @@ impl<D> RendererD3D9<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn upload_and_draw_tiles(&mut self,
|
pub(crate) fn upload_and_draw_tiles(
|
||||||
|
&mut self,
|
||||||
core: &mut RendererCore<D>,
|
core: &mut RendererCore<D>,
|
||||||
batch: &DrawTileBatchD3D9) {
|
batch: &DrawTileBatchD3D9,
|
||||||
|
) {
|
||||||
if !batch.clips.is_empty() {
|
if !batch.clips.is_empty() {
|
||||||
let clip_buffer_info = self.upload_clip_tiles(core, &batch.clips);
|
let clip_buffer_info = self.upload_clip_tiles(core, &batch.clips);
|
||||||
self.clip_tiles(core, &clip_buffer_info);
|
self.clip_tiles(core, &clip_buffer_info);
|
||||||
core.allocator.free_general_buffer(clip_buffer_info.clip_buffer_id);
|
core.allocator
|
||||||
|
.free_general_buffer(clip_buffer_info.clip_buffer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tile_buffer = self.upload_tiles(core, &batch.tiles);
|
let tile_buffer = self.upload_tiles(core, &batch.tiles);
|
||||||
let z_buffer_texture_id = self.upload_z_buffer(core, &batch.z_buffer_data);
|
let z_buffer_texture_id = self.upload_z_buffer(core, &batch.z_buffer_data);
|
||||||
|
|
||||||
self.draw_tiles(core,
|
self.draw_tiles(
|
||||||
|
core,
|
||||||
batch.tiles.len() as u32,
|
batch.tiles.len() as u32,
|
||||||
tile_buffer.tile_vertex_buffer_id,
|
tile_buffer.tile_vertex_buffer_id,
|
||||||
batch.color_texture,
|
batch.color_texture,
|
||||||
batch.blend_mode,
|
batch.blend_mode,
|
||||||
z_buffer_texture_id);
|
z_buffer_texture_id,
|
||||||
|
);
|
||||||
|
|
||||||
core.allocator.free_texture(z_buffer_texture_id);
|
core.allocator.free_texture(z_buffer_texture_id);
|
||||||
core.allocator.free_general_buffer(tile_buffer.tile_vertex_buffer_id);
|
core.allocator
|
||||||
|
.free_general_buffer(tile_buffer.tile_vertex_buffer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_tiles(&mut self, core: &mut RendererCore<D>, tiles: &[TileObjectPrimitive])
|
fn upload_tiles(
|
||||||
-> TileBufferD3D9 {
|
&mut self,
|
||||||
let tile_vertex_buffer_id =
|
core: &mut RendererCore<D>,
|
||||||
core.allocator.allocate_general_buffer::<TileObjectPrimitive>(&core.device,
|
tiles: &[TileObjectPrimitive],
|
||||||
|
) -> TileBufferD3D9 {
|
||||||
|
let tile_vertex_buffer_id = core
|
||||||
|
.allocator
|
||||||
|
.allocate_general_buffer::<TileObjectPrimitive>(
|
||||||
|
&core.device,
|
||||||
tiles.len() as u64,
|
tiles.len() as u64,
|
||||||
BufferTag("TileD3D9"));
|
BufferTag("TileD3D9"),
|
||||||
|
);
|
||||||
let tile_vertex_buffer = &core.allocator.get_general_buffer(tile_vertex_buffer_id);
|
let tile_vertex_buffer = &core.allocator.get_general_buffer(tile_vertex_buffer_id);
|
||||||
core.device.upload_to_buffer(tile_vertex_buffer, 0, tiles, BufferTarget::Vertex);
|
core.device
|
||||||
|
.upload_to_buffer(tile_vertex_buffer, 0, tiles, BufferTarget::Vertex);
|
||||||
self.ensure_index_buffer(core, tiles.len());
|
self.ensure_index_buffer(core, tiles.len());
|
||||||
|
|
||||||
TileBufferD3D9 { tile_vertex_buffer_id }
|
TileBufferD3D9 {
|
||||||
|
tile_vertex_buffer_id,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn ensure_index_buffer(&mut self, core: &mut RendererCore<D>, mut length: usize) {
|
fn ensure_index_buffer(&mut self, core: &mut RendererCore<D>, mut length: usize) {
|
||||||
length = length.next_power_of_two();
|
length = length.next_power_of_two();
|
||||||
|
@ -125,24 +148,33 @@ impl<D> RendererD3D9<D> where D: Device {
|
||||||
let mut indices: Vec<u32> = Vec::with_capacity(length * 6);
|
let mut indices: Vec<u32> = Vec::with_capacity(length * 6);
|
||||||
for index in 0..(length as u32) {
|
for index in 0..(length as u32) {
|
||||||
indices.extend_from_slice(&[
|
indices.extend_from_slice(&[
|
||||||
index * 4 + 0, index * 4 + 1, index * 4 + 2,
|
index * 4 + 0,
|
||||||
index * 4 + 1, index * 4 + 3, index * 4 + 2,
|
index * 4 + 1,
|
||||||
|
index * 4 + 2,
|
||||||
|
index * 4 + 1,
|
||||||
|
index * 4 + 3,
|
||||||
|
index * 4 + 2,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(quads_vertex_indices_buffer_id) = self.quads_vertex_indices_buffer_id.take() {
|
if let Some(quads_vertex_indices_buffer_id) = self.quads_vertex_indices_buffer_id.take() {
|
||||||
core.allocator.free_index_buffer(quads_vertex_indices_buffer_id);
|
core.allocator
|
||||||
|
.free_index_buffer(quads_vertex_indices_buffer_id);
|
||||||
}
|
}
|
||||||
let quads_vertex_indices_buffer_id =
|
let quads_vertex_indices_buffer_id = core.allocator.allocate_index_buffer::<u32>(
|
||||||
core.allocator.allocate_index_buffer::<u32>(&core.device,
|
&core.device,
|
||||||
indices.len() as u64,
|
indices.len() as u64,
|
||||||
BufferTag("QuadsVertexIndicesD3D9"));
|
BufferTag("QuadsVertexIndicesD3D9"),
|
||||||
let quads_vertex_indices_buffer =
|
);
|
||||||
core.allocator.get_index_buffer(quads_vertex_indices_buffer_id);
|
let quads_vertex_indices_buffer = core
|
||||||
core.device.upload_to_buffer(quads_vertex_indices_buffer,
|
.allocator
|
||||||
|
.get_index_buffer(quads_vertex_indices_buffer_id);
|
||||||
|
core.device.upload_to_buffer(
|
||||||
|
quads_vertex_indices_buffer,
|
||||||
0,
|
0,
|
||||||
&indices,
|
&indices,
|
||||||
BufferTarget::Index);
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
self.quads_vertex_indices_buffer_id = Some(quads_vertex_indices_buffer_id);
|
self.quads_vertex_indices_buffer_id = Some(quads_vertex_indices_buffer_id);
|
||||||
self.quads_vertex_indices_length = length;
|
self.quads_vertex_indices_length = length;
|
||||||
}
|
}
|
||||||
|
@ -179,72 +211,102 @@ impl<D> RendererD3D9<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
let fill_storage_info = self.upload_buffered_fills(core);
|
let fill_storage_info = self.upload_buffered_fills(core);
|
||||||
self.draw_fills(core, fill_storage_info.fill_buffer_id, fill_storage_info.fill_count);
|
self.draw_fills(
|
||||||
core.allocator.free_general_buffer(fill_storage_info.fill_buffer_id);
|
core,
|
||||||
|
fill_storage_info.fill_buffer_id,
|
||||||
|
fill_storage_info.fill_count,
|
||||||
|
);
|
||||||
|
core.allocator
|
||||||
|
.free_general_buffer(fill_storage_info.fill_buffer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_buffered_fills(&mut self, core: &mut RendererCore<D>) -> FillBufferInfoD3D9 {
|
fn upload_buffered_fills(&mut self, core: &mut RendererCore<D>) -> FillBufferInfoD3D9 {
|
||||||
let buffered_fills = &mut self.buffered_fills;
|
let buffered_fills = &mut self.buffered_fills;
|
||||||
debug_assert!(!buffered_fills.is_empty());
|
debug_assert!(!buffered_fills.is_empty());
|
||||||
|
|
||||||
let fill_buffer_id = core.allocator
|
let fill_buffer_id = core.allocator.allocate_general_buffer::<Fill>(
|
||||||
.allocate_general_buffer::<Fill>(&core.device,
|
&core.device,
|
||||||
MAX_FILLS_PER_BATCH as u64,
|
MAX_FILLS_PER_BATCH as u64,
|
||||||
BufferTag("Fill"));
|
BufferTag("Fill"),
|
||||||
|
);
|
||||||
let fill_vertex_buffer = core.allocator.get_general_buffer(fill_buffer_id);
|
let fill_vertex_buffer = core.allocator.get_general_buffer(fill_buffer_id);
|
||||||
debug_assert!(buffered_fills.len() <= u32::MAX as usize);
|
debug_assert!(buffered_fills.len() <= u32::MAX as usize);
|
||||||
core.device.upload_to_buffer(fill_vertex_buffer, 0, &buffered_fills, BufferTarget::Vertex);
|
core.device
|
||||||
|
.upload_to_buffer(fill_vertex_buffer, 0, &buffered_fills, BufferTarget::Vertex);
|
||||||
|
|
||||||
let fill_count = buffered_fills.len() as u32;
|
let fill_count = buffered_fills.len() as u32;
|
||||||
buffered_fills.clear();
|
buffered_fills.clear();
|
||||||
|
|
||||||
FillBufferInfoD3D9 { fill_buffer_id, fill_count }
|
FillBufferInfoD3D9 {
|
||||||
|
fill_buffer_id,
|
||||||
|
fill_count,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_fills(&mut self,
|
fn draw_fills(
|
||||||
|
&mut self,
|
||||||
core: &mut RendererCore<D>,
|
core: &mut RendererCore<D>,
|
||||||
fill_buffer_id: GeneralBufferID,
|
fill_buffer_id: GeneralBufferID,
|
||||||
fill_count: u32) {
|
fill_count: u32,
|
||||||
|
) {
|
||||||
let fill_raster_program = &self.programs.fill_program;
|
let fill_raster_program = &self.programs.fill_program;
|
||||||
|
|
||||||
let fill_vertex_buffer = core.allocator.get_general_buffer(fill_buffer_id);
|
let fill_vertex_buffer = core.allocator.get_general_buffer(fill_buffer_id);
|
||||||
let quad_vertex_positions_buffer =
|
let quad_vertex_positions_buffer = core
|
||||||
core.allocator.get_general_buffer(core.quad_vertex_positions_buffer_id);
|
.allocator
|
||||||
let quad_vertex_indices_buffer = core.allocator
|
.get_general_buffer(core.quad_vertex_positions_buffer_id);
|
||||||
|
let quad_vertex_indices_buffer = core
|
||||||
|
.allocator
|
||||||
.get_index_buffer(core.quad_vertex_indices_buffer_id);
|
.get_index_buffer(core.quad_vertex_indices_buffer_id);
|
||||||
|
|
||||||
let area_lut_texture = core.allocator.get_texture(core.area_lut_texture_id);
|
let area_lut_texture = core.allocator.get_texture(core.area_lut_texture_id);
|
||||||
|
|
||||||
let mask_viewport = self.mask_viewport(core);
|
let mask_viewport = self.mask_viewport(core);
|
||||||
let mask_storage = core.mask_storage.as_ref().expect("Where's the mask storage?");
|
let mask_storage = core
|
||||||
|
.mask_storage
|
||||||
|
.as_ref()
|
||||||
|
.expect("Where's the mask storage?");
|
||||||
let mask_framebuffer_id = mask_storage.framebuffer_id;
|
let mask_framebuffer_id = mask_storage.framebuffer_id;
|
||||||
let mask_framebuffer = core.allocator.get_framebuffer(mask_framebuffer_id);
|
let mask_framebuffer = core.allocator.get_framebuffer(mask_framebuffer_id);
|
||||||
|
|
||||||
let fill_vertex_array = FillVertexArrayD3D9::new(&core.device,
|
let fill_vertex_array = FillVertexArrayD3D9::new(
|
||||||
|
&core.device,
|
||||||
fill_raster_program,
|
fill_raster_program,
|
||||||
fill_vertex_buffer,
|
fill_vertex_buffer,
|
||||||
quad_vertex_positions_buffer,
|
quad_vertex_positions_buffer,
|
||||||
quad_vertex_indices_buffer);
|
quad_vertex_indices_buffer,
|
||||||
|
);
|
||||||
|
|
||||||
let mut clear_color = None;
|
let mut clear_color = None;
|
||||||
if !core.framebuffer_flags.contains(FramebufferFlags::MASK_FRAMEBUFFER_IS_DIRTY) {
|
if !core
|
||||||
|
.framebuffer_flags
|
||||||
|
.contains(FramebufferFlags::MASK_FRAMEBUFFER_IS_DIRTY)
|
||||||
|
{
|
||||||
clear_color = Some(ColorF::default());
|
clear_color = Some(ColorF::default());
|
||||||
};
|
};
|
||||||
|
|
||||||
let timer_query = core.timer_query_cache.start_timing_draw_call(&core.device,
|
let timer_query = core
|
||||||
&core.options);
|
.timer_query_cache
|
||||||
|
.start_timing_draw_call(&core.device, &core.options);
|
||||||
|
|
||||||
core.device.draw_elements_instanced(6, fill_count, &RenderState {
|
core.device.draw_elements_instanced(
|
||||||
|
6,
|
||||||
|
fill_count,
|
||||||
|
&RenderState {
|
||||||
target: &RenderTarget::Framebuffer(mask_framebuffer),
|
target: &RenderTarget::Framebuffer(mask_framebuffer),
|
||||||
program: &fill_raster_program.program,
|
program: &fill_raster_program.program,
|
||||||
vertex_array: &fill_vertex_array.vertex_array,
|
vertex_array: &fill_vertex_array.vertex_array,
|
||||||
primitive: Primitive::Triangles,
|
primitive: Primitive::Triangles,
|
||||||
textures: &[(&fill_raster_program.area_lut_texture, area_lut_texture)],
|
textures: &[(&fill_raster_program.area_lut_texture, area_lut_texture)],
|
||||||
uniforms: &[
|
uniforms: &[
|
||||||
(&fill_raster_program.framebuffer_size_uniform,
|
(
|
||||||
UniformData::Vec2(mask_viewport.size().to_f32().0)),
|
&fill_raster_program.framebuffer_size_uniform,
|
||||||
(&fill_raster_program.tile_size_uniform,
|
UniformData::Vec2(mask_viewport.size().to_f32().0),
|
||||||
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
),
|
||||||
|
(
|
||||||
|
&fill_raster_program.tile_size_uniform,
|
||||||
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32)),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
images: &[],
|
images: &[],
|
||||||
storage_buffers: &[],
|
storage_buffers: &[],
|
||||||
|
@ -257,143 +319,197 @@ impl<D> RendererD3D9<D> where D: Device {
|
||||||
dest_alpha_factor: BlendFactor::One,
|
dest_alpha_factor: BlendFactor::One,
|
||||||
..BlendState::default()
|
..BlendState::default()
|
||||||
}),
|
}),
|
||||||
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
clear_ops: ClearOps {
|
||||||
|
color: clear_color,
|
||||||
|
..ClearOps::default()
|
||||||
|
},
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
core.stats.drawcall_count += 1;
|
core.stats.drawcall_count += 1;
|
||||||
core.finish_timing_draw_call(&timer_query);
|
core.finish_timing_draw_call(&timer_query);
|
||||||
core.current_timer.as_mut().unwrap().push_query(TimeCategory::Fill, timer_query);
|
core.current_timer
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.push_query(TimeCategory::Fill, timer_query);
|
||||||
|
|
||||||
core.framebuffer_flags.insert(FramebufferFlags::MASK_FRAMEBUFFER_IS_DIRTY);
|
core.framebuffer_flags
|
||||||
|
.insert(FramebufferFlags::MASK_FRAMEBUFFER_IS_DIRTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clip_tiles(&mut self, core: &mut RendererCore<D>, clip_buffer_info: &ClipBufferInfo) {
|
fn clip_tiles(&mut self, core: &mut RendererCore<D>, clip_buffer_info: &ClipBufferInfo) {
|
||||||
// Allocate temp mask framebuffer.
|
// Allocate temp mask framebuffer.
|
||||||
let mask_temp_framebuffer_id =
|
let mask_temp_framebuffer_id = core.allocator.allocate_framebuffer(
|
||||||
core.allocator.allocate_framebuffer(&core.device,
|
&core.device,
|
||||||
self.mask_viewport(core).size(),
|
self.mask_viewport(core).size(),
|
||||||
core.mask_texture_format(),
|
core.mask_texture_format(),
|
||||||
FramebufferTag("TempClipMaskD3D9"));
|
FramebufferTag("TempClipMaskD3D9"),
|
||||||
|
);
|
||||||
let mask_temp_framebuffer = core.allocator.get_framebuffer(mask_temp_framebuffer_id);
|
let mask_temp_framebuffer = core.allocator.get_framebuffer(mask_temp_framebuffer_id);
|
||||||
|
|
||||||
let mask_storage = core.mask_storage.as_ref().expect("Where's the mask storage?");
|
let mask_storage = core
|
||||||
|
.mask_storage
|
||||||
|
.as_ref()
|
||||||
|
.expect("Where's the mask storage?");
|
||||||
let mask_framebuffer_id = mask_storage.framebuffer_id;
|
let mask_framebuffer_id = mask_storage.framebuffer_id;
|
||||||
let mask_framebuffer = core.allocator.get_framebuffer(mask_framebuffer_id);
|
let mask_framebuffer = core.allocator.get_framebuffer(mask_framebuffer_id);
|
||||||
let mask_texture = core.device.framebuffer_texture(mask_framebuffer);
|
let mask_texture = core.device.framebuffer_texture(mask_framebuffer);
|
||||||
let mask_texture_size = core.device.texture_size(&mask_texture);
|
let mask_texture_size = core.device.texture_size(&mask_texture);
|
||||||
|
|
||||||
let clip_vertex_buffer = core.allocator
|
let clip_vertex_buffer = core
|
||||||
|
.allocator
|
||||||
.get_general_buffer(clip_buffer_info.clip_buffer_id);
|
.get_general_buffer(clip_buffer_info.clip_buffer_id);
|
||||||
let quad_vertex_positions_buffer =
|
let quad_vertex_positions_buffer = core
|
||||||
core.allocator.get_general_buffer(core.quad_vertex_positions_buffer_id);
|
.allocator
|
||||||
let quad_vertex_indices_buffer = core.allocator
|
.get_general_buffer(core.quad_vertex_positions_buffer_id);
|
||||||
|
let quad_vertex_indices_buffer = core
|
||||||
|
.allocator
|
||||||
.get_index_buffer(core.quad_vertex_indices_buffer_id);
|
.get_index_buffer(core.quad_vertex_indices_buffer_id);
|
||||||
|
|
||||||
let tile_clip_copy_vertex_array =
|
let tile_clip_copy_vertex_array = ClipTileCopyVertexArrayD3D9::new(
|
||||||
ClipTileCopyVertexArrayD3D9::new(&core.device,
|
&core.device,
|
||||||
&self.programs.tile_clip_copy_program,
|
&self.programs.tile_clip_copy_program,
|
||||||
clip_vertex_buffer,
|
clip_vertex_buffer,
|
||||||
quad_vertex_positions_buffer,
|
quad_vertex_positions_buffer,
|
||||||
quad_vertex_indices_buffer);
|
quad_vertex_indices_buffer,
|
||||||
let tile_clip_combine_vertex_array =
|
);
|
||||||
ClipTileCombineVertexArrayD3D9::new(&core.device,
|
let tile_clip_combine_vertex_array = ClipTileCombineVertexArrayD3D9::new(
|
||||||
|
&core.device,
|
||||||
&self.programs.tile_clip_combine_program,
|
&self.programs.tile_clip_combine_program,
|
||||||
clip_vertex_buffer,
|
clip_vertex_buffer,
|
||||||
quad_vertex_positions_buffer,
|
quad_vertex_positions_buffer,
|
||||||
quad_vertex_indices_buffer);
|
quad_vertex_indices_buffer,
|
||||||
|
);
|
||||||
|
|
||||||
let timer_query = core.timer_query_cache.start_timing_draw_call(&core.device,
|
let timer_query = core
|
||||||
&core.options);
|
.timer_query_cache
|
||||||
|
.start_timing_draw_call(&core.device, &core.options);
|
||||||
|
|
||||||
// Copy out tiles.
|
// Copy out tiles.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): Don't do this on GL4.
|
// TODO(pcwalton): Don't do this on GL4.
|
||||||
core.device.draw_elements_instanced(6, clip_buffer_info.clip_count * 2, &RenderState {
|
core.device.draw_elements_instanced(
|
||||||
|
6,
|
||||||
|
clip_buffer_info.clip_count * 2,
|
||||||
|
&RenderState {
|
||||||
target: &RenderTarget::Framebuffer(mask_temp_framebuffer),
|
target: &RenderTarget::Framebuffer(mask_temp_framebuffer),
|
||||||
program: &self.programs.tile_clip_copy_program.program,
|
program: &self.programs.tile_clip_copy_program.program,
|
||||||
vertex_array: &tile_clip_copy_vertex_array.vertex_array,
|
vertex_array: &tile_clip_copy_vertex_array.vertex_array,
|
||||||
primitive: Primitive::Triangles,
|
primitive: Primitive::Triangles,
|
||||||
textures: &[
|
textures: &[(
|
||||||
(&self.programs.tile_clip_copy_program.src_texture,
|
&self.programs.tile_clip_copy_program.src_texture,
|
||||||
core.device.framebuffer_texture(mask_framebuffer)),
|
core.device.framebuffer_texture(mask_framebuffer),
|
||||||
],
|
)],
|
||||||
images: &[],
|
images: &[],
|
||||||
uniforms: &[
|
uniforms: &[(
|
||||||
(&self.programs.tile_clip_copy_program.framebuffer_size_uniform,
|
&self
|
||||||
UniformData::Vec2(mask_texture_size.to_f32().0)),
|
.programs
|
||||||
],
|
.tile_clip_copy_program
|
||||||
|
.framebuffer_size_uniform,
|
||||||
|
UniformData::Vec2(mask_texture_size.to_f32().0),
|
||||||
|
)],
|
||||||
storage_buffers: &[],
|
storage_buffers: &[],
|
||||||
viewport: RectI::new(Vector2I::zero(), mask_texture_size),
|
viewport: RectI::new(Vector2I::zero(), mask_texture_size),
|
||||||
options: RenderOptions::default(),
|
options: RenderOptions::default(),
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
core.stats.drawcall_count += 1;
|
core.stats.drawcall_count += 1;
|
||||||
core.finish_timing_draw_call(&timer_query);
|
core.finish_timing_draw_call(&timer_query);
|
||||||
core.current_timer.as_mut().unwrap().push_query(TimeCategory::Other, timer_query);
|
core.current_timer
|
||||||
let timer_query = core.timer_query_cache.start_timing_draw_call(&core.device,
|
.as_mut()
|
||||||
&core.options);
|
.unwrap()
|
||||||
|
.push_query(TimeCategory::Other, timer_query);
|
||||||
|
let timer_query = core
|
||||||
|
.timer_query_cache
|
||||||
|
.start_timing_draw_call(&core.device, &core.options);
|
||||||
|
|
||||||
// Combine clip tiles.
|
// Combine clip tiles.
|
||||||
core.device.draw_elements_instanced(6, clip_buffer_info.clip_count, &RenderState {
|
core.device.draw_elements_instanced(
|
||||||
|
6,
|
||||||
|
clip_buffer_info.clip_count,
|
||||||
|
&RenderState {
|
||||||
target: &RenderTarget::Framebuffer(mask_framebuffer),
|
target: &RenderTarget::Framebuffer(mask_framebuffer),
|
||||||
program: &self.programs.tile_clip_combine_program.program,
|
program: &self.programs.tile_clip_combine_program.program,
|
||||||
vertex_array: &tile_clip_combine_vertex_array.vertex_array,
|
vertex_array: &tile_clip_combine_vertex_array.vertex_array,
|
||||||
primitive: Primitive::Triangles,
|
primitive: Primitive::Triangles,
|
||||||
textures: &[
|
textures: &[(
|
||||||
(&self.programs.tile_clip_combine_program.src_texture,
|
&self.programs.tile_clip_combine_program.src_texture,
|
||||||
core.device.framebuffer_texture(&mask_temp_framebuffer)),
|
core.device.framebuffer_texture(&mask_temp_framebuffer),
|
||||||
],
|
)],
|
||||||
images: &[],
|
images: &[],
|
||||||
uniforms: &[
|
uniforms: &[(
|
||||||
(&self.programs.tile_clip_combine_program.framebuffer_size_uniform,
|
&self
|
||||||
UniformData::Vec2(mask_texture_size.to_f32().0)),
|
.programs
|
||||||
],
|
.tile_clip_combine_program
|
||||||
|
.framebuffer_size_uniform,
|
||||||
|
UniformData::Vec2(mask_texture_size.to_f32().0),
|
||||||
|
)],
|
||||||
storage_buffers: &[],
|
storage_buffers: &[],
|
||||||
viewport: RectI::new(Vector2I::zero(), mask_texture_size),
|
viewport: RectI::new(Vector2I::zero(), mask_texture_size),
|
||||||
options: RenderOptions::default(),
|
options: RenderOptions::default(),
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
core.stats.drawcall_count += 1;
|
core.stats.drawcall_count += 1;
|
||||||
core.finish_timing_draw_call(&timer_query);
|
core.finish_timing_draw_call(&timer_query);
|
||||||
core.current_timer.as_mut().unwrap().push_query(TimeCategory::Other, timer_query);
|
core.current_timer
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.push_query(TimeCategory::Other, timer_query);
|
||||||
|
|
||||||
core.allocator.free_framebuffer(mask_temp_framebuffer_id);
|
core.allocator.free_framebuffer(mask_temp_framebuffer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_z_buffer(&mut self, core: &mut RendererCore<D>, z_buffer_map: &DenseTileMap<i32>)
|
fn upload_z_buffer(
|
||||||
-> TextureID {
|
&mut self,
|
||||||
let z_buffer_texture_id = core.allocator.allocate_texture(&core.device,
|
core: &mut RendererCore<D>,
|
||||||
|
z_buffer_map: &DenseTileMap<i32>,
|
||||||
|
) -> TextureID {
|
||||||
|
let z_buffer_texture_id = core.allocator.allocate_texture(
|
||||||
|
&core.device,
|
||||||
z_buffer_map.rect.size(),
|
z_buffer_map.rect.size(),
|
||||||
TextureFormat::RGBA8,
|
TextureFormat::RGBA8,
|
||||||
TextureTag("ZBufferD3D9"));
|
TextureTag("ZBufferD3D9"),
|
||||||
|
);
|
||||||
let z_buffer_texture = core.allocator.get_texture(z_buffer_texture_id);
|
let z_buffer_texture = core.allocator.get_texture(z_buffer_texture_id);
|
||||||
debug_assert_eq!(z_buffer_map.rect.origin(), Vector2I::default());
|
debug_assert_eq!(z_buffer_map.rect.origin(), Vector2I::default());
|
||||||
let z_data: &[u8] = z_buffer_map.data.as_byte_slice();
|
let z_data: &[u8] = z_buffer_map.data.as_byte_slice();
|
||||||
core.device.upload_to_texture(z_buffer_texture,
|
core.device.upload_to_texture(
|
||||||
|
z_buffer_texture,
|
||||||
z_buffer_map.rect,
|
z_buffer_map.rect,
|
||||||
TextureDataRef::U8(&z_data));
|
TextureDataRef::U8(&z_data),
|
||||||
|
);
|
||||||
z_buffer_texture_id
|
z_buffer_texture_id
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uploads clip tiles from CPU to GPU.
|
// Uploads clip tiles from CPU to GPU.
|
||||||
fn upload_clip_tiles(&mut self, core: &mut RendererCore<D>, clips: &[Clip]) -> ClipBufferInfo {
|
fn upload_clip_tiles(&mut self, core: &mut RendererCore<D>, clips: &[Clip]) -> ClipBufferInfo {
|
||||||
let clip_buffer_id = core.allocator.allocate_general_buffer::<Clip>(&core.device,
|
let clip_buffer_id = core.allocator.allocate_general_buffer::<Clip>(
|
||||||
|
&core.device,
|
||||||
clips.len() as u64,
|
clips.len() as u64,
|
||||||
BufferTag("ClipD3D9"));
|
BufferTag("ClipD3D9"),
|
||||||
|
);
|
||||||
let clip_buffer = core.allocator.get_general_buffer(clip_buffer_id);
|
let clip_buffer = core.allocator.get_general_buffer(clip_buffer_id);
|
||||||
core.device.upload_to_buffer(clip_buffer, 0, clips, BufferTarget::Vertex);
|
core.device
|
||||||
ClipBufferInfo { clip_buffer_id, clip_count: clips.len() as u32 }
|
.upload_to_buffer(clip_buffer, 0, clips, BufferTarget::Vertex);
|
||||||
|
ClipBufferInfo {
|
||||||
|
clip_buffer_id,
|
||||||
|
clip_count: clips.len() as u32,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_tiles(&mut self,
|
fn draw_tiles(
|
||||||
|
&mut self,
|
||||||
core: &mut RendererCore<D>,
|
core: &mut RendererCore<D>,
|
||||||
tile_count: u32,
|
tile_count: u32,
|
||||||
tile_vertex_buffer_id: GeneralBufferID,
|
tile_vertex_buffer_id: GeneralBufferID,
|
||||||
color_texture_0: Option<TileBatchTexture>,
|
color_texture_0: Option<TileBatchTexture>,
|
||||||
blend_mode: BlendMode,
|
blend_mode: BlendMode,
|
||||||
z_buffer_texture_id: TextureID) {
|
z_buffer_texture_id: TextureID,
|
||||||
|
) {
|
||||||
// TODO(pcwalton): Disable blend for solid tiles.
|
// TODO(pcwalton): Disable blend for solid tiles.
|
||||||
|
|
||||||
if tile_count == 0 {
|
if tile_count == 0 {
|
||||||
|
@ -410,43 +526,63 @@ impl<D> RendererD3D9<D> where D: Device {
|
||||||
let clear_color = core.clear_color_for_draw_operation();
|
let clear_color = core.clear_color_for_draw_operation();
|
||||||
let draw_viewport = core.draw_viewport();
|
let draw_viewport = core.draw_viewport();
|
||||||
|
|
||||||
let timer_query = core.timer_query_cache.start_timing_draw_call(&core.device,
|
let timer_query = core
|
||||||
&core.options);
|
.timer_query_cache
|
||||||
|
.start_timing_draw_call(&core.device, &core.options);
|
||||||
|
|
||||||
let tile_raster_program = &self.programs.tile_program;
|
let tile_raster_program = &self.programs.tile_program;
|
||||||
|
|
||||||
let tile_vertex_buffer = core.allocator.get_general_buffer(tile_vertex_buffer_id);
|
let tile_vertex_buffer = core.allocator.get_general_buffer(tile_vertex_buffer_id);
|
||||||
let quad_vertex_positions_buffer =
|
let quad_vertex_positions_buffer = core
|
||||||
core.allocator.get_general_buffer(core.quad_vertex_positions_buffer_id);
|
.allocator
|
||||||
let quad_vertex_indices_buffer = core.allocator
|
.get_general_buffer(core.quad_vertex_positions_buffer_id);
|
||||||
|
let quad_vertex_indices_buffer = core
|
||||||
|
.allocator
|
||||||
.get_index_buffer(core.quad_vertex_indices_buffer_id);
|
.get_index_buffer(core.quad_vertex_indices_buffer_id);
|
||||||
let dest_blend_framebuffer = core.allocator
|
let dest_blend_framebuffer = core
|
||||||
|
.allocator
|
||||||
.get_framebuffer(self.dest_blend_framebuffer_id);
|
.get_framebuffer(self.dest_blend_framebuffer_id);
|
||||||
|
|
||||||
let (mut textures, mut uniforms) = (vec![], vec![]);
|
let (mut textures, mut uniforms) = (vec![], vec![]);
|
||||||
|
|
||||||
core.set_uniforms_for_drawing_tiles(&tile_raster_program.common,
|
core.set_uniforms_for_drawing_tiles(
|
||||||
|
&tile_raster_program.common,
|
||||||
&mut textures,
|
&mut textures,
|
||||||
&mut uniforms,
|
&mut uniforms,
|
||||||
color_texture_0);
|
color_texture_0,
|
||||||
|
);
|
||||||
|
|
||||||
uniforms.push((&tile_raster_program.transform_uniform,
|
uniforms.push((
|
||||||
UniformData::Mat4(self.tile_transform(core).to_columns())));
|
&tile_raster_program.transform_uniform,
|
||||||
textures.push((&tile_raster_program.dest_texture,
|
UniformData::Mat4(self.tile_transform(core).to_columns()),
|
||||||
core.device.framebuffer_texture(dest_blend_framebuffer)));
|
));
|
||||||
|
textures.push((
|
||||||
|
&tile_raster_program.dest_texture,
|
||||||
|
core.device.framebuffer_texture(dest_blend_framebuffer),
|
||||||
|
));
|
||||||
|
|
||||||
let z_buffer_texture = core.allocator.get_texture(z_buffer_texture_id);
|
let z_buffer_texture = core.allocator.get_texture(z_buffer_texture_id);
|
||||||
textures.push((&tile_raster_program.common.z_buffer_texture, z_buffer_texture));
|
textures.push((
|
||||||
uniforms.push((&tile_raster_program.common.z_buffer_texture_size_uniform,
|
&tile_raster_program.common.z_buffer_texture,
|
||||||
UniformData::IVec2(core.device.texture_size(z_buffer_texture).0)));
|
z_buffer_texture,
|
||||||
|
));
|
||||||
|
uniforms.push((
|
||||||
|
&tile_raster_program.common.z_buffer_texture_size_uniform,
|
||||||
|
UniformData::IVec2(core.device.texture_size(z_buffer_texture).0),
|
||||||
|
));
|
||||||
|
|
||||||
let tile_vertex_array = TileVertexArrayD3D9::new(&core.device,
|
let tile_vertex_array = TileVertexArrayD3D9::new(
|
||||||
|
&core.device,
|
||||||
&self.programs.tile_program,
|
&self.programs.tile_program,
|
||||||
tile_vertex_buffer,
|
tile_vertex_buffer,
|
||||||
quad_vertex_positions_buffer,
|
quad_vertex_positions_buffer,
|
||||||
quad_vertex_indices_buffer);
|
quad_vertex_indices_buffer,
|
||||||
|
);
|
||||||
|
|
||||||
core.device.draw_elements_instanced(6, tile_count, &RenderState {
|
core.device.draw_elements_instanced(
|
||||||
|
6,
|
||||||
|
tile_count,
|
||||||
|
&RenderState {
|
||||||
target: &core.draw_render_target(),
|
target: &core.draw_render_target(),
|
||||||
program: &tile_raster_program.common.program,
|
program: &tile_raster_program.common.program,
|
||||||
vertex_array: &tile_vertex_array.vertex_array,
|
vertex_array: &tile_vertex_array.vertex_array,
|
||||||
|
@ -459,30 +595,43 @@ impl<D> RendererD3D9<D> where D: Device {
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
blend: blend_mode.to_blend_state(),
|
blend: blend_mode.to_blend_state(),
|
||||||
stencil: self.stencil_state(core),
|
stencil: self.stencil_state(core),
|
||||||
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
clear_ops: ClearOps {
|
||||||
|
color: clear_color,
|
||||||
|
..ClearOps::default()
|
||||||
|
},
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
core.stats.drawcall_count += 1;
|
core.stats.drawcall_count += 1;
|
||||||
core.finish_timing_draw_call(&timer_query);
|
core.finish_timing_draw_call(&timer_query);
|
||||||
core.current_timer.as_mut().unwrap().push_query(TimeCategory::Composite, timer_query);
|
core.current_timer
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.push_query(TimeCategory::Composite, timer_query);
|
||||||
|
|
||||||
core.preserve_draw_framebuffer();
|
core.preserve_draw_framebuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_alpha_tiles_to_dest_blend_texture(&mut self,
|
fn copy_alpha_tiles_to_dest_blend_texture(
|
||||||
|
&mut self,
|
||||||
core: &mut RendererCore<D>,
|
core: &mut RendererCore<D>,
|
||||||
tile_count: u32,
|
tile_count: u32,
|
||||||
vertex_buffer_id: GeneralBufferID) {
|
vertex_buffer_id: GeneralBufferID,
|
||||||
|
) {
|
||||||
let draw_viewport = core.draw_viewport();
|
let draw_viewport = core.draw_viewport();
|
||||||
|
|
||||||
let mut textures = vec![];
|
let mut textures = vec![];
|
||||||
let mut uniforms = vec![
|
let mut uniforms = vec![
|
||||||
(&self.programs.tile_copy_program.transform_uniform,
|
(
|
||||||
UniformData::Mat4(self.tile_transform(core).to_columns())),
|
&self.programs.tile_copy_program.transform_uniform,
|
||||||
(&self.programs.tile_copy_program.tile_size_uniform,
|
UniformData::Mat4(self.tile_transform(core).to_columns()),
|
||||||
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
),
|
||||||
|
(
|
||||||
|
&self.programs.tile_copy_program.tile_size_uniform,
|
||||||
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32)),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
let draw_framebuffer = match core.draw_render_target() {
|
let draw_framebuffer = match core.draw_render_target() {
|
||||||
|
@ -492,24 +641,33 @@ impl<D> RendererD3D9<D> where D: Device {
|
||||||
let draw_texture = core.device.framebuffer_texture(&draw_framebuffer);
|
let draw_texture = core.device.framebuffer_texture(&draw_framebuffer);
|
||||||
|
|
||||||
textures.push((&self.programs.tile_copy_program.src_texture, draw_texture));
|
textures.push((&self.programs.tile_copy_program.src_texture, draw_texture));
|
||||||
uniforms.push((&self.programs.tile_copy_program.framebuffer_size_uniform,
|
uniforms.push((
|
||||||
UniformData::Vec2(draw_viewport.size().to_f32().0)));
|
&self.programs.tile_copy_program.framebuffer_size_uniform,
|
||||||
|
UniformData::Vec2(draw_viewport.size().to_f32().0),
|
||||||
|
));
|
||||||
|
|
||||||
let quads_vertex_indices_buffer_id = self.quads_vertex_indices_buffer_id
|
let quads_vertex_indices_buffer_id = self
|
||||||
|
.quads_vertex_indices_buffer_id
|
||||||
.expect("Where's the quads vertex buffer?");
|
.expect("Where's the quads vertex buffer?");
|
||||||
let quads_vertex_indices_buffer = core.allocator
|
let quads_vertex_indices_buffer = core
|
||||||
|
.allocator
|
||||||
.get_index_buffer(quads_vertex_indices_buffer_id);
|
.get_index_buffer(quads_vertex_indices_buffer_id);
|
||||||
let vertex_buffer = core.allocator.get_general_buffer(vertex_buffer_id);
|
let vertex_buffer = core.allocator.get_general_buffer(vertex_buffer_id);
|
||||||
|
|
||||||
let tile_copy_vertex_array = CopyTileVertexArray::new(&core.device,
|
let tile_copy_vertex_array = CopyTileVertexArray::new(
|
||||||
|
&core.device,
|
||||||
&self.programs.tile_copy_program,
|
&self.programs.tile_copy_program,
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
quads_vertex_indices_buffer);
|
quads_vertex_indices_buffer,
|
||||||
|
);
|
||||||
|
|
||||||
let dest_blend_framebuffer = core.allocator
|
let dest_blend_framebuffer = core
|
||||||
|
.allocator
|
||||||
.get_framebuffer(self.dest_blend_framebuffer_id);
|
.get_framebuffer(self.dest_blend_framebuffer_id);
|
||||||
|
|
||||||
core.device.draw_elements(tile_count * 6, &RenderState {
|
core.device.draw_elements(
|
||||||
|
tile_count * 6,
|
||||||
|
&RenderState {
|
||||||
target: &RenderTarget::Framebuffer(dest_blend_framebuffer),
|
target: &RenderTarget::Framebuffer(dest_blend_framebuffer),
|
||||||
program: &self.programs.tile_copy_program.program,
|
program: &self.programs.tile_copy_program.program,
|
||||||
vertex_array: &tile_copy_vertex_array.vertex_array,
|
vertex_array: &tile_copy_vertex_array.vertex_array,
|
||||||
|
@ -526,7 +684,8 @@ impl<D> RendererD3D9<D> where D: Device {
|
||||||
},
|
},
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
core.stats.drawcall_count += 1;
|
core.stats.drawcall_count += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,33 +10,52 @@
|
||||||
|
|
||||||
//! Shaders and vertex specifications for the Direct3D 9-level renderer.
|
//! Shaders and vertex specifications for the Direct3D 9-level renderer.
|
||||||
|
|
||||||
use crate::gpu::shaders::{TILE_INSTANCE_SIZE, TileProgramCommon};
|
use crate::gpu::shaders::{TileProgramCommon, TILE_INSTANCE_SIZE};
|
||||||
use pathfinder_gpu::{BufferTarget, Device, VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
use pathfinder_gpu::{BufferTarget, Device, VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
|
|
||||||
const FILL_INSTANCE_SIZE: usize = 12;
|
const FILL_INSTANCE_SIZE: usize = 12;
|
||||||
const CLIP_TILE_INSTANCE_SIZE: usize = 16;
|
const CLIP_TILE_INSTANCE_SIZE: usize = 16;
|
||||||
|
|
||||||
pub(crate) struct FillVertexArrayD3D9<D> where D: Device {
|
pub(crate) struct FillVertexArrayD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> FillVertexArrayD3D9<D> where D: Device {
|
impl<D> FillVertexArrayD3D9<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
fill_program: &FillProgramD3D9<D>,
|
fill_program: &FillProgramD3D9<D>,
|
||||||
vertex_buffer: &D::Buffer,
|
vertex_buffer: &D::Buffer,
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
quad_vertex_indices_buffer: &D::Buffer,
|
||||||
-> FillVertexArrayD3D9<D> {
|
) -> FillVertexArrayD3D9<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap();
|
let tess_coord_attr = device
|
||||||
let line_segment_attr = device.get_vertex_attr(&fill_program.program, "LineSegment")
|
.get_vertex_attr(&fill_program.program, "TessCoord")
|
||||||
|
.unwrap();
|
||||||
|
let line_segment_attr = device
|
||||||
|
.get_vertex_attr(&fill_program.program, "LineSegment")
|
||||||
|
.unwrap();
|
||||||
|
let tile_index_attr = device
|
||||||
|
.get_vertex_attr(&fill_program.program, "TileIndex")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap();
|
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
device.bind_buffer(
|
||||||
device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor {
|
&vertex_array,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&tess_coord_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::U16,
|
attr_type: VertexAttrType::U16,
|
||||||
|
@ -44,9 +63,13 @@ impl<D> FillVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
||||||
device.configure_vertex_attr(&vertex_array, &line_segment_attr, &VertexAttrDescriptor {
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&line_segment_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 4,
|
size: 4,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::U16,
|
attr_type: VertexAttrType::U16,
|
||||||
|
@ -54,8 +77,12 @@ impl<D> FillVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor {
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&tile_index_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 1,
|
size: 1,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I32,
|
attr_type: VertexAttrType::I32,
|
||||||
|
@ -63,40 +90,66 @@ impl<D> FillVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 8,
|
offset: 8,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quad_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
FillVertexArrayD3D9 { vertex_array }
|
FillVertexArrayD3D9 { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct TileVertexArrayD3D9<D> where D: Device {
|
pub(crate) struct TileVertexArrayD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> TileVertexArrayD3D9<D> where D: Device {
|
impl<D> TileVertexArrayD3D9<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
tile_program: &TileProgramD3D9<D>,
|
tile_program: &TileProgramD3D9<D>,
|
||||||
tile_vertex_buffer: &D::Buffer,
|
tile_vertex_buffer: &D::Buffer,
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
quad_vertex_indices_buffer: &D::Buffer,
|
||||||
-> TileVertexArrayD3D9<D> {
|
) -> TileVertexArrayD3D9<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let tile_offset_attr =
|
let tile_offset_attr = device
|
||||||
device.get_vertex_attr(&tile_program.common.program, "TileOffset").unwrap();
|
.get_vertex_attr(&tile_program.common.program, "TileOffset")
|
||||||
let tile_origin_attr =
|
.unwrap();
|
||||||
device.get_vertex_attr(&tile_program.common.program, "TileOrigin").unwrap();
|
let tile_origin_attr = device
|
||||||
let mask_0_tex_coord_attr =
|
.get_vertex_attr(&tile_program.common.program, "TileOrigin")
|
||||||
device.get_vertex_attr(&tile_program.common.program, "MaskTexCoord0").unwrap();
|
.unwrap();
|
||||||
let ctrl_backdrop_attr =
|
let mask_0_tex_coord_attr = device
|
||||||
device.get_vertex_attr(&tile_program.common.program, "CtrlBackdrop").unwrap();
|
.get_vertex_attr(&tile_program.common.program, "MaskTexCoord0")
|
||||||
let color_attr = device.get_vertex_attr(&tile_program.common.program, "Color").unwrap();
|
.unwrap();
|
||||||
let path_index_attr = device.get_vertex_attr(&tile_program.common.program, "PathIndex")
|
let ctrl_backdrop_attr = device
|
||||||
|
.get_vertex_attr(&tile_program.common.program, "CtrlBackdrop")
|
||||||
|
.unwrap();
|
||||||
|
let color_attr = device
|
||||||
|
.get_vertex_attr(&tile_program.common.program, "Color")
|
||||||
|
.unwrap();
|
||||||
|
let path_index_attr = device
|
||||||
|
.get_vertex_attr(&tile_program.common.program, "PathIndex")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
device.bind_buffer(
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
|
&vertex_array,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&tile_offset_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -104,9 +157,13 @@ impl<D> TileVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex);
|
device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex);
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor {
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&tile_origin_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -114,8 +171,12 @@ impl<D> TileVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.configure_vertex_attr(&vertex_array, &mask_0_tex_coord_attr, &VertexAttrDescriptor {
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&mask_0_tex_coord_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 4,
|
size: 4,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::U8,
|
attr_type: VertexAttrType::U8,
|
||||||
|
@ -123,8 +184,12 @@ impl<D> TileVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 4,
|
offset: 4,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.configure_vertex_attr(&vertex_array, &path_index_attr, &VertexAttrDescriptor {
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&path_index_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 1,
|
size: 1,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I32,
|
attr_type: VertexAttrType::I32,
|
||||||
|
@ -132,8 +197,12 @@ impl<D> TileVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 8,
|
offset: 8,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.configure_vertex_attr(&vertex_array, &color_attr, &VertexAttrDescriptor {
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&color_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 1,
|
size: 1,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -141,8 +210,12 @@ impl<D> TileVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 12,
|
offset: 12,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.configure_vertex_attr(&vertex_array, &ctrl_backdrop_attr, &VertexAttrDescriptor {
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&ctrl_backdrop_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I8,
|
attr_type: VertexAttrType::I8,
|
||||||
|
@ -150,33 +223,54 @@ impl<D> TileVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 14,
|
offset: 14,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quad_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
TileVertexArrayD3D9 { vertex_array }
|
TileVertexArrayD3D9 { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ClipTileCopyVertexArrayD3D9<D> where D: Device {
|
pub(crate) struct ClipTileCopyVertexArrayD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ClipTileCopyVertexArrayD3D9<D> where D: Device {
|
impl<D> ClipTileCopyVertexArrayD3D9<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
clip_tile_copy_program: &ClipTileCopyProgramD3D9<D>,
|
clip_tile_copy_program: &ClipTileCopyProgramD3D9<D>,
|
||||||
vertex_buffer: &D::Buffer,
|
vertex_buffer: &D::Buffer,
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
quad_vertex_indices_buffer: &D::Buffer,
|
||||||
-> ClipTileCopyVertexArrayD3D9<D> {
|
) -> ClipTileCopyVertexArrayD3D9<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let tile_offset_attr =
|
let tile_offset_attr = device
|
||||||
device.get_vertex_attr(&clip_tile_copy_program.program, "TileOffset").unwrap();
|
.get_vertex_attr(&clip_tile_copy_program.program, "TileOffset")
|
||||||
let tile_index_attr =
|
.unwrap();
|
||||||
device.get_vertex_attr(&clip_tile_copy_program.program, "TileIndex").unwrap();
|
let tile_index_attr = device
|
||||||
|
.get_vertex_attr(&clip_tile_copy_program.program, "TileIndex")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
device.bind_buffer(
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
|
&vertex_array,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&tile_offset_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -184,9 +278,13 @@ impl<D> ClipTileCopyVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor {
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&tile_index_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 1,
|
size: 1,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I32,
|
attr_type: VertexAttrType::I32,
|
||||||
|
@ -194,39 +292,63 @@ impl<D> ClipTileCopyVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quad_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
ClipTileCopyVertexArrayD3D9 { vertex_array }
|
ClipTileCopyVertexArrayD3D9 { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
pub(crate) struct ClipTileCombineVertexArrayD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
impl<D> ClipTileCombineVertexArrayD3D9<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
clip_tile_combine_program: &ClipTileCombineProgramD3D9<D>,
|
clip_tile_combine_program: &ClipTileCombineProgramD3D9<D>,
|
||||||
vertex_buffer: &D::Buffer,
|
vertex_buffer: &D::Buffer,
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
quad_vertex_indices_buffer: &D::Buffer,
|
||||||
-> ClipTileCombineVertexArrayD3D9<D> {
|
) -> ClipTileCombineVertexArrayD3D9<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let tile_offset_attr =
|
let tile_offset_attr = device
|
||||||
device.get_vertex_attr(&clip_tile_combine_program.program, "TileOffset").unwrap();
|
.get_vertex_attr(&clip_tile_combine_program.program, "TileOffset")
|
||||||
let dest_tile_index_attr =
|
.unwrap();
|
||||||
device.get_vertex_attr(&clip_tile_combine_program.program, "DestTileIndex").unwrap();
|
let dest_tile_index_attr = device
|
||||||
let dest_backdrop_attr =
|
.get_vertex_attr(&clip_tile_combine_program.program, "DestTileIndex")
|
||||||
device.get_vertex_attr(&clip_tile_combine_program.program, "DestBackdrop").unwrap();
|
.unwrap();
|
||||||
let src_tile_index_attr =
|
let dest_backdrop_attr = device
|
||||||
device.get_vertex_attr(&clip_tile_combine_program.program, "SrcTileIndex").unwrap();
|
.get_vertex_attr(&clip_tile_combine_program.program, "DestBackdrop")
|
||||||
let src_backdrop_attr =
|
.unwrap();
|
||||||
device.get_vertex_attr(&clip_tile_combine_program.program, "SrcBackdrop").unwrap();
|
let src_tile_index_attr = device
|
||||||
|
.get_vertex_attr(&clip_tile_combine_program.program, "SrcTileIndex")
|
||||||
|
.unwrap();
|
||||||
|
let src_backdrop_attr = device
|
||||||
|
.get_vertex_attr(&clip_tile_combine_program.program, "SrcBackdrop")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
device.bind_buffer(
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
|
&vertex_array,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&tile_offset_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -234,9 +356,13 @@ impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
||||||
device.configure_vertex_attr(&vertex_array, &dest_tile_index_attr, &VertexAttrDescriptor {
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&dest_tile_index_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 1,
|
size: 1,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I32,
|
attr_type: VertexAttrType::I32,
|
||||||
|
@ -244,8 +370,12 @@ impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.configure_vertex_attr(&vertex_array, &dest_backdrop_attr, &VertexAttrDescriptor {
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&dest_backdrop_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 1,
|
size: 1,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I32,
|
attr_type: VertexAttrType::I32,
|
||||||
|
@ -253,8 +383,12 @@ impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 4,
|
offset: 4,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.configure_vertex_attr(&vertex_array, &src_tile_index_attr, &VertexAttrDescriptor {
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&src_tile_index_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 1,
|
size: 1,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I32,
|
attr_type: VertexAttrType::I32,
|
||||||
|
@ -262,8 +396,12 @@ impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 8,
|
offset: 8,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.configure_vertex_attr(&vertex_array, &src_backdrop_attr, &VertexAttrDescriptor {
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&src_backdrop_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 1,
|
size: 1,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I32,
|
attr_type: VertexAttrType::I32,
|
||||||
|
@ -271,30 +409,46 @@ impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
||||||
offset: 12,
|
offset: 12,
|
||||||
divisor: 1,
|
divisor: 1,
|
||||||
buffer_index: 1,
|
buffer_index: 1,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quad_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
ClipTileCombineVertexArrayD3D9 { vertex_array }
|
ClipTileCombineVertexArrayD3D9 { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CopyTileVertexArray<D> where D: Device {
|
pub(crate) struct CopyTileVertexArray<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> CopyTileVertexArray<D> where D: Device {
|
impl<D> CopyTileVertexArray<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
copy_tile_program: &CopyTileProgram<D>,
|
copy_tile_program: &CopyTileProgram<D>,
|
||||||
copy_tile_vertex_buffer: &D::Buffer,
|
copy_tile_vertex_buffer: &D::Buffer,
|
||||||
quads_vertex_indices_buffer: &D::Buffer)
|
quads_vertex_indices_buffer: &D::Buffer,
|
||||||
-> CopyTileVertexArray<D> {
|
) -> CopyTileVertexArray<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let tile_position_attr =
|
let tile_position_attr = device
|
||||||
device.get_vertex_attr(©_tile_program.program, "TilePosition").unwrap();
|
.get_vertex_attr(©_tile_program.program, "TilePosition")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, copy_tile_vertex_buffer, BufferTarget::Vertex);
|
device.bind_buffer(&vertex_array, copy_tile_vertex_buffer, BufferTarget::Vertex);
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&tile_position_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -302,21 +456,32 @@ impl<D> CopyTileVertexArray<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quads_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
CopyTileVertexArray { vertex_array }
|
CopyTileVertexArray { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FillProgramD3D9<D> where D: Device {
|
pub(crate) struct FillProgramD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) framebuffer_size_uniform: D::Uniform,
|
pub(crate) framebuffer_size_uniform: D::Uniform,
|
||||||
pub(crate) tile_size_uniform: D::Uniform,
|
pub(crate) tile_size_uniform: D::Uniform,
|
||||||
pub(crate) area_lut_texture: D::TextureParameter,
|
pub(crate) area_lut_texture: D::TextureParameter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> FillProgramD3D9<D> where D: Device {
|
impl<D> FillProgramD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgramD3D9<D> {
|
fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgramD3D9<D> {
|
||||||
let program = device.create_raster_program(resources, "d3d9/fill");
|
let program = device.create_raster_program(resources, "d3d9/fill");
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
|
@ -331,54 +496,86 @@ impl<D> FillProgramD3D9<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct TileProgramD3D9<D> where D: Device {
|
pub(crate) struct TileProgramD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) common: TileProgramCommon<D>,
|
pub(crate) common: TileProgramCommon<D>,
|
||||||
pub(crate) dest_texture: D::TextureParameter,
|
pub(crate) dest_texture: D::TextureParameter,
|
||||||
pub(crate) transform_uniform: D::Uniform,
|
pub(crate) transform_uniform: D::Uniform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> TileProgramD3D9<D> where D: Device {
|
impl<D> TileProgramD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgramD3D9<D> {
|
fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgramD3D9<D> {
|
||||||
let program = device.create_raster_program(resources, "d3d9/tile");
|
let program = device.create_raster_program(resources, "d3d9/tile");
|
||||||
let dest_texture = device.get_texture_parameter(&program, "DestTexture");
|
let dest_texture = device.get_texture_parameter(&program, "DestTexture");
|
||||||
let transform_uniform = device.get_uniform(&program, "Transform");
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
let common = TileProgramCommon::new(device, program);
|
let common = TileProgramCommon::new(device, program);
|
||||||
TileProgramD3D9 { common, dest_texture, transform_uniform }
|
TileProgramD3D9 {
|
||||||
|
common,
|
||||||
|
dest_texture,
|
||||||
|
transform_uniform,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ClipTileCombineProgramD3D9<D> where D: Device {
|
pub(crate) struct ClipTileCombineProgramD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) src_texture: D::TextureParameter,
|
pub(crate) src_texture: D::TextureParameter,
|
||||||
pub(crate) framebuffer_size_uniform: D::Uniform,
|
pub(crate) framebuffer_size_uniform: D::Uniform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ClipTileCombineProgramD3D9<D> where D: Device {
|
impl<D> ClipTileCombineProgramD3D9<D>
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader)
|
where
|
||||||
-> ClipTileCombineProgramD3D9<D> {
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileCombineProgramD3D9<D> {
|
||||||
let program = device.create_raster_program(resources, "d3d9/tile_clip_combine");
|
let program = device.create_raster_program(resources, "d3d9/tile_clip_combine");
|
||||||
let src_texture = device.get_texture_parameter(&program, "Src");
|
let src_texture = device.get_texture_parameter(&program, "Src");
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
ClipTileCombineProgramD3D9 { program, src_texture, framebuffer_size_uniform }
|
ClipTileCombineProgramD3D9 {
|
||||||
|
program,
|
||||||
|
src_texture,
|
||||||
|
framebuffer_size_uniform,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ClipTileCopyProgramD3D9<D> where D: Device {
|
pub(crate) struct ClipTileCopyProgramD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) src_texture: D::TextureParameter,
|
pub(crate) src_texture: D::TextureParameter,
|
||||||
pub(crate) framebuffer_size_uniform: D::Uniform,
|
pub(crate) framebuffer_size_uniform: D::Uniform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ClipTileCopyProgramD3D9<D> where D: Device {
|
impl<D> ClipTileCopyProgramD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileCopyProgramD3D9<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileCopyProgramD3D9<D> {
|
||||||
let program = device.create_raster_program(resources, "d3d9/tile_clip_copy");
|
let program = device.create_raster_program(resources, "d3d9/tile_clip_copy");
|
||||||
let src_texture = device.get_texture_parameter(&program, "Src");
|
let src_texture = device.get_texture_parameter(&program, "Src");
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
ClipTileCopyProgramD3D9 { program, src_texture, framebuffer_size_uniform }
|
ClipTileCopyProgramD3D9 {
|
||||||
|
program,
|
||||||
|
src_texture,
|
||||||
|
framebuffer_size_uniform,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CopyTileProgram<D> where D: Device {
|
pub(crate) struct CopyTileProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) transform_uniform: D::Uniform,
|
pub(crate) transform_uniform: D::Uniform,
|
||||||
pub(crate) tile_size_uniform: D::Uniform,
|
pub(crate) tile_size_uniform: D::Uniform,
|
||||||
|
@ -386,7 +583,10 @@ pub(crate) struct CopyTileProgram<D> where D: Device {
|
||||||
pub(crate) src_texture: D::TextureParameter,
|
pub(crate) src_texture: D::TextureParameter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> CopyTileProgram<D> where D: Device {
|
impl<D> CopyTileProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> CopyTileProgram<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> CopyTileProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "d3d9/tile_copy");
|
let program = device.create_raster_program(resources, "d3d9/tile_copy");
|
||||||
let transform_uniform = device.get_uniform(&program, "Transform");
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
|
@ -403,7 +603,10 @@ impl<D> CopyTileProgram<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ProgramsD3D9<D> where D: Device {
|
pub(crate) struct ProgramsD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fill_program: FillProgramD3D9<D>,
|
pub(crate) fill_program: FillProgramD3D9<D>,
|
||||||
pub(crate) tile_program: TileProgramD3D9<D>,
|
pub(crate) tile_program: TileProgramD3D9<D>,
|
||||||
pub(crate) tile_clip_copy_program: ClipTileCopyProgramD3D9<D>,
|
pub(crate) tile_clip_copy_program: ClipTileCopyProgramD3D9<D>,
|
||||||
|
@ -411,7 +614,10 @@ pub(crate) struct ProgramsD3D9<D> where D: Device {
|
||||||
pub(crate) tile_copy_program: CopyTileProgram<D>,
|
pub(crate) tile_copy_program: CopyTileProgram<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ProgramsD3D9<D> where D: Device {
|
impl<D> ProgramsD3D9<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D9<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D9<D> {
|
||||||
ProgramsD3D9 {
|
ProgramsD3D9 {
|
||||||
fill_program: FillProgramD3D9::new(device, resources),
|
fill_program: FillProgramD3D9::new(device, resources),
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
use crate::gpu::options::RendererLevel;
|
use crate::gpu::options::RendererLevel;
|
||||||
use crate::gpu::perf::{RenderStats, RenderTime};
|
use crate::gpu::perf::{RenderStats, RenderTime};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{vec2i, Vector2I};
|
||||||
use pathfinder_gpu::Device;
|
|
||||||
use pathfinder_gpu::allocator::GPUMemoryAllocator;
|
use pathfinder_gpu::allocator::GPUMemoryAllocator;
|
||||||
|
use pathfinder_gpu::Device;
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UIPresenter, WINDOW_COLOR};
|
use pathfinder_ui::{UIPresenter, FONT_ASCENT, LINE_HEIGHT, PADDING, WINDOW_COLOR};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::ops::{Add, Div};
|
use std::ops::{Add, Div};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -40,7 +40,10 @@ const INFO_WINDOW_WIDTH: i32 = 425;
|
||||||
const INFO_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2;
|
const INFO_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2;
|
||||||
|
|
||||||
/// Manages the debug UI.
|
/// Manages the debug UI.
|
||||||
pub struct DebugUIPresenter<D> where D: Device {
|
pub struct DebugUIPresenter<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
/// The general UI presenter object.
|
/// The general UI presenter object.
|
||||||
///
|
///
|
||||||
/// You can use this to draw your own application-specific debug widgets.
|
/// You can use this to draw your own application-specific debug widgets.
|
||||||
|
@ -53,12 +56,16 @@ pub struct DebugUIPresenter<D> where D: Device {
|
||||||
renderer_level: RendererLevel,
|
renderer_level: RendererLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> DebugUIPresenter<D> where D: Device {
|
impl<D> DebugUIPresenter<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
resources: &dyn ResourceLoader,
|
resources: &dyn ResourceLoader,
|
||||||
framebuffer_size: Vector2I,
|
framebuffer_size: Vector2I,
|
||||||
renderer_level: RendererLevel)
|
renderer_level: RendererLevel,
|
||||||
-> DebugUIPresenter<D> {
|
) -> DebugUIPresenter<D> {
|
||||||
let ui_presenter = UIPresenter::new(device, resources, framebuffer_size);
|
let ui_presenter = UIPresenter::new(device, resources, framebuffer_size);
|
||||||
DebugUIPresenter {
|
DebugUIPresenter {
|
||||||
ui_presenter,
|
ui_presenter,
|
||||||
|
@ -90,29 +97,35 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
||||||
let bottom = framebuffer_size.y() - PADDING;
|
let bottom = framebuffer_size.y() - PADDING;
|
||||||
let window_rect = RectI::new(
|
let window_rect = RectI::new(
|
||||||
vec2i(framebuffer_size.x() - PADDING - INFO_WINDOW_WIDTH,
|
vec2i(
|
||||||
bottom - INFO_WINDOW_HEIGHT),
|
framebuffer_size.x() - PADDING - INFO_WINDOW_WIDTH,
|
||||||
|
bottom - INFO_WINDOW_HEIGHT,
|
||||||
|
),
|
||||||
vec2i(INFO_WINDOW_WIDTH, INFO_WINDOW_HEIGHT),
|
vec2i(INFO_WINDOW_WIDTH, INFO_WINDOW_HEIGHT),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
self.ui_presenter
|
||||||
|
.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
||||||
|
|
||||||
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
||||||
let level = match self.renderer_level {
|
let level = match self.renderer_level {
|
||||||
RendererLevel::D3D9 => "D3D9",
|
RendererLevel::D3D9 => "D3D9",
|
||||||
RendererLevel::D3D11 => "D3D11",
|
RendererLevel::D3D11 => "D3D11",
|
||||||
};
|
};
|
||||||
self.ui_presenter.draw_text(device,
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("{} ({} level)", self.backend_name, level),
|
&format!("{} ({} level)", self.backend_name, level),
|
||||||
origin + vec2i(0, LINE_HEIGHT * 0),
|
origin + vec2i(0, LINE_HEIGHT * 0),
|
||||||
false);
|
false,
|
||||||
self.ui_presenter.draw_text(device,
|
);
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&self.device_name,
|
&self.device_name,
|
||||||
origin + vec2i(0, LINE_HEIGHT * 1),
|
origin + vec2i(0, LINE_HEIGHT * 1),
|
||||||
false);
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn performance_window_size(&self) -> Vector2I {
|
fn performance_window_size(&self) -> Vector2I {
|
||||||
|
@ -130,16 +143,20 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
||||||
let bottom = framebuffer_size.y() - PADDING;
|
let bottom = framebuffer_size.y() - PADDING;
|
||||||
let window_rect = RectI::new(
|
let window_rect = RectI::new(
|
||||||
vec2i(framebuffer_size.x() - PADDING - STATS_WINDOW_WIDTH,
|
vec2i(
|
||||||
bottom -
|
framebuffer_size.x() - PADDING - STATS_WINDOW_WIDTH,
|
||||||
PADDING -
|
bottom
|
||||||
INFO_WINDOW_HEIGHT -
|
- PADDING
|
||||||
performance_window_height -
|
- INFO_WINDOW_HEIGHT
|
||||||
PADDING -
|
- performance_window_height
|
||||||
STATS_WINDOW_HEIGHT),
|
- PADDING
|
||||||
vec2i(STATS_WINDOW_WIDTH, STATS_WINDOW_HEIGHT));
|
- STATS_WINDOW_HEIGHT,
|
||||||
|
),
|
||||||
|
vec2i(STATS_WINDOW_WIDTH, STATS_WINDOW_HEIGHT),
|
||||||
|
);
|
||||||
|
|
||||||
self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
self.ui_presenter
|
||||||
|
.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
||||||
|
|
||||||
let mean_cpu_sample = self.cpu_samples.mean();
|
let mean_cpu_sample = self.cpu_samples.mean();
|
||||||
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
||||||
|
@ -179,11 +196,15 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
||||||
let bottom = framebuffer_size.y() - PADDING;
|
let bottom = framebuffer_size.y() - PADDING;
|
||||||
let window_rect = RectI::new(
|
let window_rect = RectI::new(
|
||||||
vec2i(framebuffer_size.x() - PADDING - performance_window_size.x(),
|
vec2i(
|
||||||
bottom - INFO_WINDOW_HEIGHT - PADDING - performance_window_size.y()),
|
framebuffer_size.x() - PADDING - performance_window_size.x(),
|
||||||
performance_window_size);
|
bottom - INFO_WINDOW_HEIGHT - PADDING - performance_window_size.y(),
|
||||||
|
),
|
||||||
|
performance_window_size,
|
||||||
|
);
|
||||||
|
|
||||||
self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
self.ui_presenter
|
||||||
|
.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
||||||
|
|
||||||
let mean_cpu_sample = self.cpu_samples.mean();
|
let mean_cpu_sample = self.cpu_samples.mean();
|
||||||
let mean_gpu_sample = self.gpu_samples.mean();
|
let mean_gpu_sample = self.gpu_samples.mean();
|
||||||
|
@ -201,8 +222,10 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("VRAM Alloc.: {:.1} MB",
|
&format!(
|
||||||
mean_cpu_sample.gpu_bytes_allocated as f64 / (1024.0 * 1024.0)),
|
"VRAM Alloc.: {:.1} MB",
|
||||||
|
mean_cpu_sample.gpu_bytes_allocated as f64 / (1024.0 * 1024.0)
|
||||||
|
),
|
||||||
origin + vec2i(0, current_y),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -210,8 +233,10 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("VRAM Commit: {:.1} MB",
|
&format!(
|
||||||
mean_cpu_sample.gpu_bytes_committed as f64 / (1024.0 * 1024.0)),
|
"VRAM Commit: {:.1} MB",
|
||||||
|
mean_cpu_sample.gpu_bytes_committed as f64 / (1024.0 * 1024.0)
|
||||||
|
),
|
||||||
origin + vec2i(0, current_y),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -220,7 +245,10 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("CPU: {:.3} ms", duration_to_ms(mean_cpu_sample.cpu_build_time)),
|
&format!(
|
||||||
|
"CPU: {:.3} ms",
|
||||||
|
duration_to_ms(mean_cpu_sample.cpu_build_time)
|
||||||
|
),
|
||||||
origin + vec2i(0, current_y),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -231,7 +259,10 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("GPU Dice: {:.3} ms", duration_to_ms(mean_gpu_sample.dice_time)),
|
&format!(
|
||||||
|
"GPU Dice: {:.3} ms",
|
||||||
|
duration_to_ms(mean_gpu_sample.dice_time)
|
||||||
|
),
|
||||||
origin + vec2i(0, current_y),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -239,7 +270,10 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("GPU Bin: {:.3} ms", duration_to_ms(mean_gpu_sample.bin_time)),
|
&format!(
|
||||||
|
"GPU Bin: {:.3} ms",
|
||||||
|
duration_to_ms(mean_gpu_sample.bin_time)
|
||||||
|
),
|
||||||
origin + vec2i(0, current_y),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -250,7 +284,10 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("GPU Fill: {:.3} ms", duration_to_ms(mean_gpu_sample.fill_time)),
|
&format!(
|
||||||
|
"GPU Fill: {:.3} ms",
|
||||||
|
duration_to_ms(mean_gpu_sample.fill_time)
|
||||||
|
),
|
||||||
origin + vec2i(0, current_y),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -258,7 +295,10 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("GPU Comp.: {:.3} ms", duration_to_ms(mean_gpu_sample.composite_time)),
|
&format!(
|
||||||
|
"GPU Comp.: {:.3} ms",
|
||||||
|
duration_to_ms(mean_gpu_sample.composite_time)
|
||||||
|
),
|
||||||
origin + vec2i(0, current_y),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -266,7 +306,10 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
&format!("GPU Other: {:.3} ms", duration_to_ms(mean_gpu_sample.other_time)),
|
&format!(
|
||||||
|
"GPU Other: {:.3} ms",
|
||||||
|
duration_to_ms(mean_gpu_sample.other_time)
|
||||||
|
),
|
||||||
origin + vec2i(0, current_y),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -274,18 +317,18 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
|
|
||||||
let mut wallclock_time = match self.renderer_level {
|
let mut wallclock_time = match self.renderer_level {
|
||||||
RendererLevel::D3D11 => {
|
RendererLevel::D3D11 => {
|
||||||
duration_to_ms(mean_cpu_sample.cpu_build_time) +
|
duration_to_ms(mean_cpu_sample.cpu_build_time)
|
||||||
duration_to_ms(mean_gpu_sample.fill_time)
|
+ duration_to_ms(mean_gpu_sample.fill_time)
|
||||||
}
|
|
||||||
RendererLevel::D3D9 => {
|
|
||||||
f64::max(duration_to_ms(mean_cpu_sample.cpu_build_time),
|
|
||||||
duration_to_ms(mean_gpu_sample.fill_time))
|
|
||||||
}
|
}
|
||||||
|
RendererLevel::D3D9 => f64::max(
|
||||||
|
duration_to_ms(mean_cpu_sample.cpu_build_time),
|
||||||
|
duration_to_ms(mean_gpu_sample.fill_time),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
wallclock_time += duration_to_ms(mean_gpu_sample.composite_time) +
|
wallclock_time += duration_to_ms(mean_gpu_sample.composite_time)
|
||||||
duration_to_ms(mean_gpu_sample.dice_time) +
|
+ duration_to_ms(mean_gpu_sample.dice_time)
|
||||||
duration_to_ms(mean_gpu_sample.bin_time) +
|
+ duration_to_ms(mean_gpu_sample.bin_time)
|
||||||
duration_to_ms(mean_gpu_sample.other_time);
|
+ duration_to_ms(mean_gpu_sample.other_time);
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
allocator,
|
allocator,
|
||||||
|
@ -294,7 +337,6 @@ impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SampleBuffer<S>
|
struct SampleBuffer<S>
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
//! The GPU renderer for Pathfinder 3.
|
//! The GPU renderer for Pathfinder 3.
|
||||||
|
|
||||||
pub mod d3d9;
|
|
||||||
pub mod d3d11;
|
pub mod d3d11;
|
||||||
|
pub mod d3d9;
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod options;
|
pub mod options;
|
||||||
pub mod perf;
|
pub mod perf;
|
||||||
|
|
|
@ -22,7 +22,10 @@ pub struct RendererMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options that influence rendering that can be changed at runtime.
|
/// Options that influence rendering that can be changed at runtime.
|
||||||
pub struct RendererOptions<D> where D: Device {
|
pub struct RendererOptions<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
/// Where the rendering should go: either to the default framebuffer (i.e. screen) or to a
|
/// Where the rendering should go: either to the default framebuffer (i.e. screen) or to a
|
||||||
/// custom framebuffer.
|
/// custom framebuffer.
|
||||||
pub dest: DestFramebuffer<D>,
|
pub dest: DestFramebuffer<D>,
|
||||||
|
@ -48,12 +51,20 @@ pub enum RendererLevel {
|
||||||
impl RendererMode {
|
impl RendererMode {
|
||||||
/// Creates a new `RendererMode` with a suitable API level for the given GPU device.
|
/// Creates a new `RendererMode` with a suitable API level for the given GPU device.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn default_for_device<D>(device: &D) -> RendererMode where D: Device {
|
pub fn default_for_device<D>(device: &D) -> RendererMode
|
||||||
RendererMode { level: RendererLevel::default_for_device(device) }
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
RendererMode {
|
||||||
|
level: RendererLevel::default_for_device(device),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> Default for RendererOptions<D> where D: Device {
|
impl<D> Default for RendererOptions<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> RendererOptions<D> {
|
fn default() -> RendererOptions<D> {
|
||||||
RendererOptions {
|
RendererOptions {
|
||||||
|
@ -66,7 +77,10 @@ impl<D> Default for RendererOptions<D> where D: Device {
|
||||||
|
|
||||||
impl RendererLevel {
|
impl RendererLevel {
|
||||||
/// Returns a suitable renderer level for the given device.
|
/// Returns a suitable renderer level for the given device.
|
||||||
pub fn default_for_device<D>(device: &D) -> RendererLevel where D: Device {
|
pub fn default_for_device<D>(device: &D) -> RendererLevel
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
match device.feature_level() {
|
match device.feature_level() {
|
||||||
FeatureLevel::D3D10 => RendererLevel::D3D9,
|
FeatureLevel::D3D10 => RendererLevel::D3D9,
|
||||||
FeatureLevel::D3D11 => RendererLevel::D3D11,
|
FeatureLevel::D3D11 => RendererLevel::D3D11,
|
||||||
|
@ -76,7 +90,10 @@ impl RendererLevel {
|
||||||
|
|
||||||
/// Where the rendered content should go.
|
/// Where the rendered content should go.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum DestFramebuffer<D> where D: Device {
|
pub enum DestFramebuffer<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
/// The rendered content should go to the default framebuffer (e.g. the window in OpenGL).
|
/// The rendered content should go to the default framebuffer (e.g. the window in OpenGL).
|
||||||
Default {
|
Default {
|
||||||
/// The rectangle within the window to draw in, in device pixels.
|
/// The rectangle within the window to draw in, in device pixels.
|
||||||
|
@ -88,14 +105,23 @@ pub enum DestFramebuffer<D> where D: Device {
|
||||||
Other(D::Framebuffer),
|
Other(D::Framebuffer),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> Default for DestFramebuffer<D> where D: Device {
|
impl<D> Default for DestFramebuffer<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> DestFramebuffer<D> {
|
fn default() -> DestFramebuffer<D> {
|
||||||
DestFramebuffer::Default { viewport: RectI::default(), window_size: Vector2I::default() }
|
DestFramebuffer::Default {
|
||||||
|
viewport: RectI::default(),
|
||||||
|
window_size: Vector2I::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> DestFramebuffer<D> where D: Device {
|
impl<D> DestFramebuffer<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
/// Returns a `DestFramebuffer` object that renders to the entire contents of the default
|
/// Returns a `DestFramebuffer` object that renders to the entire contents of the default
|
||||||
/// framebuffer.
|
/// framebuffer.
|
||||||
///
|
///
|
||||||
|
@ -103,7 +129,10 @@ impl<D> DestFramebuffer<D> where D: Device {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn full_window(window_size: Vector2I) -> DestFramebuffer<D> {
|
pub fn full_window(window_size: Vector2I) -> DestFramebuffer<D> {
|
||||||
let viewport = RectI::new(Vector2I::default(), window_size);
|
let viewport = RectI::new(Vector2I::default(), window_size);
|
||||||
DestFramebuffer::Default { viewport, window_size }
|
DestFramebuffer::Default {
|
||||||
|
viewport,
|
||||||
|
window_size,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the size of the destination buffer, in device pixels.
|
/// Returns the size of the destination buffer, in device pixels.
|
||||||
|
|
|
@ -75,11 +75,17 @@ impl Div<usize> for RenderStats {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct TimerQueryCache<D> where D: Device {
|
pub(crate) struct TimerQueryCache<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
free_queries: Vec<D::TimerQuery>,
|
free_queries: Vec<D::TimerQuery>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PendingTimer<D> where D: Device {
|
pub(crate) struct PendingTimer<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) dice_times: Vec<TimerFuture<D>>,
|
pub(crate) dice_times: Vec<TimerFuture<D>>,
|
||||||
pub(crate) bin_times: Vec<TimerFuture<D>>,
|
pub(crate) bin_times: Vec<TimerFuture<D>>,
|
||||||
pub(crate) fill_times: Vec<TimerFuture<D>>,
|
pub(crate) fill_times: Vec<TimerFuture<D>>,
|
||||||
|
@ -87,7 +93,10 @@ pub(crate) struct PendingTimer<D> where D: Device {
|
||||||
pub(crate) other_times: Vec<TimerFuture<D>>,
|
pub(crate) other_times: Vec<TimerFuture<D>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum TimerFuture<D> where D: Device {
|
pub(crate) enum TimerFuture<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
Pending(D::TimerQuery),
|
Pending(D::TimerQuery),
|
||||||
Resolved(Duration),
|
Resolved(Duration),
|
||||||
}
|
}
|
||||||
|
@ -101,21 +110,31 @@ pub(crate) enum TimeCategory {
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> TimerQueryCache<D> where D: Device {
|
impl<D> TimerQueryCache<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new() -> TimerQueryCache<D> {
|
pub(crate) fn new() -> TimerQueryCache<D> {
|
||||||
TimerQueryCache { free_queries: vec![] }
|
TimerQueryCache {
|
||||||
|
free_queries: vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn alloc(&mut self, device: &D) -> D::TimerQuery {
|
pub(crate) fn alloc(&mut self, device: &D) -> D::TimerQuery {
|
||||||
self.free_queries.pop().unwrap_or_else(|| device.create_timer_query())
|
self.free_queries
|
||||||
|
.pop()
|
||||||
|
.unwrap_or_else(|| device.create_timer_query())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn free(&mut self, old_query: D::TimerQuery) {
|
pub(crate) fn free(&mut self, old_query: D::TimerQuery) {
|
||||||
self.free_queries.push(old_query);
|
self.free_queries.push(old_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn start_timing_draw_call(&mut self, device: &D, options: &RendererOptions<D>)
|
pub(crate) fn start_timing_draw_call(
|
||||||
-> Option<D::TimerQuery> {
|
&mut self,
|
||||||
|
device: &D,
|
||||||
|
options: &RendererOptions<D>,
|
||||||
|
) -> Option<D::TimerQuery> {
|
||||||
if !options.show_debug_ui {
|
if !options.show_debug_ui {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +145,10 @@ impl<D> TimerQueryCache<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> PendingTimer<D> where D: Device {
|
impl<D> PendingTimer<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new() -> PendingTimer<D> {
|
pub(crate) fn new() -> PendingTimer<D> {
|
||||||
PendingTimer {
|
PendingTimer {
|
||||||
dice_times: vec![],
|
dice_times: vec![],
|
||||||
|
@ -139,10 +161,14 @@ impl<D> PendingTimer<D> where D: Device {
|
||||||
|
|
||||||
pub(crate) fn poll(&mut self, device: &D) -> Vec<D::TimerQuery> {
|
pub(crate) fn poll(&mut self, device: &D) -> Vec<D::TimerQuery> {
|
||||||
let mut old_queries = vec![];
|
let mut old_queries = vec![];
|
||||||
for future in self.dice_times.iter_mut().chain(self.bin_times.iter_mut())
|
for future in self
|
||||||
|
.dice_times
|
||||||
|
.iter_mut()
|
||||||
|
.chain(self.bin_times.iter_mut())
|
||||||
.chain(self.fill_times.iter_mut())
|
.chain(self.fill_times.iter_mut())
|
||||||
.chain(self.composite_times.iter_mut())
|
.chain(self.composite_times.iter_mut())
|
||||||
.chain(self.other_times.iter_mut()) {
|
.chain(self.other_times.iter_mut())
|
||||||
|
{
|
||||||
if let Some(old_query) = future.poll(device) {
|
if let Some(old_query) = future.poll(device) {
|
||||||
old_queries.push(old_query)
|
old_queries.push(old_query)
|
||||||
}
|
}
|
||||||
|
@ -157,20 +183,28 @@ impl<D> PendingTimer<D> where D: Device {
|
||||||
let composite_time = total_time_of_timer_futures(&self.composite_times);
|
let composite_time = total_time_of_timer_futures(&self.composite_times);
|
||||||
let other_time = total_time_of_timer_futures(&self.other_times);
|
let other_time = total_time_of_timer_futures(&self.other_times);
|
||||||
match (dice_time, bin_time, fill_time, composite_time, other_time) {
|
match (dice_time, bin_time, fill_time, composite_time, other_time) {
|
||||||
(Some(dice_time),
|
(
|
||||||
|
Some(dice_time),
|
||||||
Some(bin_time),
|
Some(bin_time),
|
||||||
Some(fill_time),
|
Some(fill_time),
|
||||||
Some(composite_time),
|
Some(composite_time),
|
||||||
Some(other_time)) => {
|
Some(other_time),
|
||||||
Some(RenderTime { dice_time, bin_time, fill_time, composite_time, other_time })
|
) => Some(RenderTime {
|
||||||
}
|
dice_time,
|
||||||
|
bin_time,
|
||||||
|
fill_time,
|
||||||
|
composite_time,
|
||||||
|
other_time,
|
||||||
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push_query(&mut self,
|
pub(crate) fn push_query(
|
||||||
|
&mut self,
|
||||||
time_category: TimeCategory,
|
time_category: TimeCategory,
|
||||||
timer_query: Option<D::TimerQuery>) {
|
timer_query: Option<D::TimerQuery>,
|
||||||
|
) {
|
||||||
let timer_future = match timer_query {
|
let timer_future = match timer_query {
|
||||||
None => return,
|
None => return,
|
||||||
Some(timer_query) => TimerFuture::new(timer_query),
|
Some(timer_query) => TimerFuture::new(timer_query),
|
||||||
|
@ -185,7 +219,10 @@ impl<D> PendingTimer<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> TimerFuture<D> where D: Device {
|
impl<D> TimerFuture<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(query: D::TimerQuery) -> TimerFuture<D> {
|
pub(crate) fn new(query: D::TimerQuery) -> TimerFuture<D> {
|
||||||
TimerFuture::Pending(query)
|
TimerFuture::Pending(query)
|
||||||
}
|
}
|
||||||
|
@ -197,17 +234,18 @@ impl<D> TimerFuture<D> where D: Device {
|
||||||
};
|
};
|
||||||
match duration {
|
match duration {
|
||||||
None => None,
|
None => None,
|
||||||
Some(duration) => {
|
Some(duration) => match mem::replace(self, TimerFuture::Resolved(duration)) {
|
||||||
match mem::replace(self, TimerFuture::Resolved(duration)) {
|
|
||||||
TimerFuture::Resolved(_) => unreachable!(),
|
TimerFuture::Resolved(_) => unreachable!(),
|
||||||
TimerFuture::Pending(old_query) => Some(old_query),
|
TimerFuture::Pending(old_query) => Some(old_query),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn total_time_of_timer_futures<D>(futures: &[TimerFuture<D>]) -> Option<Duration> where D: Device {
|
fn total_time_of_timer_futures<D>(futures: &[TimerFuture<D>]) -> Option<Duration>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
let mut total = Duration::default();
|
let mut total = Duration::default();
|
||||||
for future in futures {
|
for future in futures {
|
||||||
match *future {
|
match *future {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,21 +15,37 @@ use pathfinder_resources::ResourceLoader;
|
||||||
// TODO(pcwalton): Replace with `mem::size_of` calls?
|
// TODO(pcwalton): Replace with `mem::size_of` calls?
|
||||||
pub(crate) const TILE_INSTANCE_SIZE: usize = 16;
|
pub(crate) const TILE_INSTANCE_SIZE: usize = 16;
|
||||||
|
|
||||||
pub(crate) struct BlitVertexArray<D> where D: Device {
|
pub(crate) struct BlitVertexArray<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> BlitVertexArray<D> where D: Device {
|
impl<D> BlitVertexArray<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
blit_program: &BlitProgram<D>,
|
blit_program: &BlitProgram<D>,
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
quad_vertex_indices_buffer: &D::Buffer,
|
||||||
-> BlitVertexArray<D> {
|
) -> BlitVertexArray<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
let position_attr = device.get_vertex_attr(&blit_program.program, "Position").unwrap();
|
let position_attr = device
|
||||||
|
.get_vertex_attr(&blit_program.program, "Position")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
device.bind_buffer(
|
||||||
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
|
&vertex_array,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&position_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -37,47 +53,77 @@ impl<D> BlitVertexArray<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quad_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
BlitVertexArray { vertex_array }
|
BlitVertexArray { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct VertexArraysCore<D> where D: Device {
|
pub(crate) struct VertexArraysCore<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) blit_vertex_array: BlitVertexArray<D>,
|
pub(crate) blit_vertex_array: BlitVertexArray<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> VertexArraysCore<D> where D: Device {
|
impl<D> VertexArraysCore<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
programs: &ProgramsCore<D>,
|
programs: &ProgramsCore<D>,
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
quad_vertex_indices_buffer: &D::Buffer,
|
||||||
-> VertexArraysCore<D> {
|
) -> VertexArraysCore<D> {
|
||||||
VertexArraysCore {
|
VertexArraysCore {
|
||||||
blit_vertex_array: BlitVertexArray::new(device,
|
blit_vertex_array: BlitVertexArray::new(
|
||||||
|
device,
|
||||||
&programs.blit_program,
|
&programs.blit_program,
|
||||||
quad_vertex_positions_buffer,
|
quad_vertex_positions_buffer,
|
||||||
quad_vertex_indices_buffer),
|
quad_vertex_indices_buffer,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ClearVertexArray<D> where D: Device {
|
pub(crate) struct ClearVertexArray<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ClearVertexArray<D> where D: Device {
|
impl<D> ClearVertexArray<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
clear_program: &ClearProgram<D>,
|
clear_program: &ClearProgram<D>,
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
quad_vertex_indices_buffer: &D::Buffer,
|
||||||
-> ClearVertexArray<D> {
|
) -> ClearVertexArray<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
let position_attr = device.get_vertex_attr(&clear_program.program, "Position").unwrap();
|
let position_attr = device
|
||||||
|
.get_vertex_attr(&clear_program.program, "Position")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
device.bind_buffer(
|
||||||
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
|
&vertex_array,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&position_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -85,35 +131,57 @@ impl<D> ClearVertexArray<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quad_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
ClearVertexArray { vertex_array }
|
ClearVertexArray { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct BlitProgram<D> where D: Device {
|
pub(crate) struct BlitProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) dest_rect_uniform: D::Uniform,
|
pub(crate) dest_rect_uniform: D::Uniform,
|
||||||
pub(crate) framebuffer_size_uniform: D::Uniform,
|
pub(crate) framebuffer_size_uniform: D::Uniform,
|
||||||
pub(crate) src_texture: D::TextureParameter,
|
pub(crate) src_texture: D::TextureParameter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> BlitProgram<D> where D: Device {
|
impl<D> BlitProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BlitProgram<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BlitProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "blit");
|
let program = device.create_raster_program(resources, "blit");
|
||||||
let dest_rect_uniform = device.get_uniform(&program, "DestRect");
|
let dest_rect_uniform = device.get_uniform(&program, "DestRect");
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
let src_texture = device.get_texture_parameter(&program, "Src");
|
let src_texture = device.get_texture_parameter(&program, "Src");
|
||||||
BlitProgram { program, dest_rect_uniform, framebuffer_size_uniform, src_texture }
|
BlitProgram {
|
||||||
|
program,
|
||||||
|
dest_rect_uniform,
|
||||||
|
framebuffer_size_uniform,
|
||||||
|
src_texture,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ProgramsCore<D> where D: Device {
|
pub(crate) struct ProgramsCore<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) blit_program: BlitProgram<D>,
|
pub(crate) blit_program: BlitProgram<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ProgramsCore<D> where D: Device {
|
impl<D> ProgramsCore<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsCore<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsCore<D> {
|
||||||
ProgramsCore {
|
ProgramsCore {
|
||||||
blit_program: BlitProgram::new(device, resources),
|
blit_program: BlitProgram::new(device, resources),
|
||||||
|
@ -121,24 +189,38 @@ impl<D> ProgramsCore<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ClearProgram<D> where D: Device {
|
pub(crate) struct ClearProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) rect_uniform: D::Uniform,
|
pub(crate) rect_uniform: D::Uniform,
|
||||||
pub(crate) framebuffer_size_uniform: D::Uniform,
|
pub(crate) framebuffer_size_uniform: D::Uniform,
|
||||||
pub(crate) color_uniform: D::Uniform,
|
pub(crate) color_uniform: D::Uniform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ClearProgram<D> where D: Device {
|
impl<D> ClearProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ClearProgram<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ClearProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "clear");
|
let program = device.create_raster_program(resources, "clear");
|
||||||
let rect_uniform = device.get_uniform(&program, "Rect");
|
let rect_uniform = device.get_uniform(&program, "Rect");
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
let color_uniform = device.get_uniform(&program, "Color");
|
let color_uniform = device.get_uniform(&program, "Color");
|
||||||
ClearProgram { program, rect_uniform, framebuffer_size_uniform, color_uniform }
|
ClearProgram {
|
||||||
|
program,
|
||||||
|
rect_uniform,
|
||||||
|
framebuffer_size_uniform,
|
||||||
|
color_uniform,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct TileProgramCommon<D> where D: Device {
|
pub(crate) struct TileProgramCommon<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) tile_size_uniform: D::Uniform,
|
pub(crate) tile_size_uniform: D::Uniform,
|
||||||
pub(crate) texture_metadata_texture: D::TextureParameter,
|
pub(crate) texture_metadata_texture: D::TextureParameter,
|
||||||
|
@ -153,7 +235,10 @@ pub(crate) struct TileProgramCommon<D> where D: Device {
|
||||||
pub(crate) framebuffer_size_uniform: D::Uniform,
|
pub(crate) framebuffer_size_uniform: D::Uniform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> TileProgramCommon<D> where D: Device {
|
impl<D> TileProgramCommon<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, program: D::Program) -> TileProgramCommon<D> {
|
pub(crate) fn new(device: &D, program: D::Program) -> TileProgramCommon<D> {
|
||||||
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
let texture_metadata_texture = device.get_texture_parameter(&program, "TextureMetadata");
|
let texture_metadata_texture = device.get_texture_parameter(&program, "TextureMetadata");
|
||||||
|
@ -184,33 +269,50 @@ impl<D> TileProgramCommon<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct StencilProgram<D> where D: Device {
|
pub(crate) struct StencilProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> StencilProgram<D> where D: Device {
|
impl<D> StencilProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> StencilProgram<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> StencilProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "stencil");
|
let program = device.create_raster_program(resources, "stencil");
|
||||||
StencilProgram { program }
|
StencilProgram { program }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct StencilVertexArray<D> where D: Device {
|
pub(crate) struct StencilVertexArray<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
pub(crate) vertex_buffer: D::Buffer,
|
pub(crate) vertex_buffer: D::Buffer,
|
||||||
pub(crate) index_buffer: D::Buffer,
|
pub(crate) index_buffer: D::Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> StencilVertexArray<D> where D: Device {
|
impl<D> StencilVertexArray<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, stencil_program: &StencilProgram<D>) -> StencilVertexArray<D> {
|
pub(crate) fn new(device: &D, stencil_program: &StencilProgram<D>) -> StencilVertexArray<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
let vertex_buffer = device.create_buffer(BufferUploadMode::Static);
|
let vertex_buffer = device.create_buffer(BufferUploadMode::Static);
|
||||||
let index_buffer = device.create_buffer(BufferUploadMode::Static);
|
let index_buffer = device.create_buffer(BufferUploadMode::Static);
|
||||||
|
|
||||||
let position_attr = device.get_vertex_attr(&stencil_program.program, "Position").unwrap();
|
let position_attr = device
|
||||||
|
.get_vertex_attr(&stencil_program.program, "Position")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
||||||
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&position_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 3,
|
size: 3,
|
||||||
class: VertexAttrClass::Float,
|
class: VertexAttrClass::Float,
|
||||||
attr_type: VertexAttrType::F32,
|
attr_type: VertexAttrType::F32,
|
||||||
|
@ -218,46 +320,77 @@ impl<D> StencilVertexArray<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index);
|
device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index);
|
||||||
|
|
||||||
StencilVertexArray { vertex_array, vertex_buffer, index_buffer }
|
StencilVertexArray {
|
||||||
|
vertex_array,
|
||||||
|
vertex_buffer,
|
||||||
|
index_buffer,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ReprojectionProgram<D> where D: Device {
|
pub(crate) struct ReprojectionProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) program: D::Program,
|
pub(crate) program: D::Program,
|
||||||
pub(crate) old_transform_uniform: D::Uniform,
|
pub(crate) old_transform_uniform: D::Uniform,
|
||||||
pub(crate) new_transform_uniform: D::Uniform,
|
pub(crate) new_transform_uniform: D::Uniform,
|
||||||
pub(crate) texture: D::TextureParameter,
|
pub(crate) texture: D::TextureParameter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ReprojectionProgram<D> where D: Device {
|
impl<D> ReprojectionProgram<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram<D> {
|
pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "reproject");
|
let program = device.create_raster_program(resources, "reproject");
|
||||||
let old_transform_uniform = device.get_uniform(&program, "OldTransform");
|
let old_transform_uniform = device.get_uniform(&program, "OldTransform");
|
||||||
let new_transform_uniform = device.get_uniform(&program, "NewTransform");
|
let new_transform_uniform = device.get_uniform(&program, "NewTransform");
|
||||||
let texture = device.get_texture_parameter(&program, "Texture");
|
let texture = device.get_texture_parameter(&program, "Texture");
|
||||||
ReprojectionProgram { program, old_transform_uniform, new_transform_uniform, texture }
|
ReprojectionProgram {
|
||||||
|
program,
|
||||||
|
old_transform_uniform,
|
||||||
|
new_transform_uniform,
|
||||||
|
texture,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ReprojectionVertexArray<D> where D: Device {
|
pub(crate) struct ReprojectionVertexArray<D>
|
||||||
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
pub(crate) vertex_array: D::VertexArray,
|
pub(crate) vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ReprojectionVertexArray<D> where D: Device {
|
impl<D> ReprojectionVertexArray<D>
|
||||||
pub(crate) fn new(device: &D,
|
where
|
||||||
|
D: Device,
|
||||||
|
{
|
||||||
|
pub(crate) fn new(
|
||||||
|
device: &D,
|
||||||
reprojection_program: &ReprojectionProgram<D>,
|
reprojection_program: &ReprojectionProgram<D>,
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
quad_vertex_indices_buffer: &D::Buffer,
|
||||||
-> ReprojectionVertexArray<D> {
|
) -> ReprojectionVertexArray<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position")
|
let position_attr = device
|
||||||
|
.get_vertex_attr(&reprojection_program.program, "Position")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
device.bind_buffer(
|
||||||
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
|
&vertex_array,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
BufferTarget::Vertex,
|
||||||
|
);
|
||||||
|
device.configure_vertex_attr(
|
||||||
|
&vertex_array,
|
||||||
|
&position_attr,
|
||||||
|
&VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
attr_type: VertexAttrType::I16,
|
attr_type: VertexAttrType::I16,
|
||||||
|
@ -265,8 +398,13 @@ impl<D> ReprojectionVertexArray<D> where D: Device {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
divisor: 0,
|
divisor: 0,
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
},
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
);
|
||||||
|
device.bind_buffer(
|
||||||
|
&vertex_array,
|
||||||
|
quad_vertex_indices_buffer,
|
||||||
|
BufferTarget::Index,
|
||||||
|
);
|
||||||
|
|
||||||
ReprojectionVertexArray { vertex_array }
|
ReprojectionVertexArray { vertex_array }
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,8 @@ use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
use pathfinder_gpu::TextureSamplingFlags;
|
use pathfinder_gpu::TextureSamplingFlags;
|
||||||
use std::fmt::{Debug, Formatter, Result as DebugResult};
|
use std::fmt::{Debug, Formatter, Result as DebugResult};
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
|
||||||
|
@ -51,15 +51,24 @@ pub enum RenderCommand {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Allocates a texture page.
|
// Allocates a texture page.
|
||||||
AllocateTexturePage { page_id: TexturePageId, descriptor: TexturePageDescriptor },
|
AllocateTexturePage {
|
||||||
|
page_id: TexturePageId,
|
||||||
|
descriptor: TexturePageDescriptor,
|
||||||
|
},
|
||||||
|
|
||||||
// Uploads data to a texture page.
|
// Uploads data to a texture page.
|
||||||
UploadTexelData { texels: Arc<Vec<ColorU>>, location: TextureLocation },
|
UploadTexelData {
|
||||||
|
texels: Arc<Vec<ColorU>>,
|
||||||
|
location: TextureLocation,
|
||||||
|
},
|
||||||
|
|
||||||
// Associates a render target with a texture page.
|
// Associates a render target with a texture page.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): Add a rect to this so we can render to subrects of a page.
|
// TODO(pcwalton): Add a rect to this so we can render to subrects of a page.
|
||||||
DeclareRenderTarget { id: RenderTargetId, location: TextureLocation },
|
DeclareRenderTarget {
|
||||||
|
id: RenderTargetId,
|
||||||
|
location: TextureLocation,
|
||||||
|
},
|
||||||
|
|
||||||
// Upload texture metadata.
|
// Upload texture metadata.
|
||||||
UploadTextureMetadata(Vec<TextureMetadataEntry>),
|
UploadTextureMetadata(Vec<TextureMetadataEntry>),
|
||||||
|
@ -95,7 +104,9 @@ pub enum RenderCommand {
|
||||||
DrawTilesD3D11(DrawTileBatchD3D11),
|
DrawTilesD3D11(DrawTileBatchD3D11),
|
||||||
|
|
||||||
// Presents a rendered frame.
|
// Presents a rendered frame.
|
||||||
Finish { cpu_build_time: Duration },
|
Finish {
|
||||||
|
cpu_build_time: Duration,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug, Default)]
|
#[derive(Clone, Copy, PartialEq, Debug, Default)]
|
||||||
|
@ -438,8 +449,10 @@ impl PathBatchIndex {
|
||||||
|
|
||||||
impl AlphaTileId {
|
impl AlphaTileId {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(next_alpha_tile_index: &[AtomicUsize; ALPHA_TILE_LEVEL_COUNT], level: usize)
|
pub fn new(
|
||||||
-> AlphaTileId {
|
next_alpha_tile_index: &[AtomicUsize; ALPHA_TILE_LEVEL_COUNT],
|
||||||
|
level: usize,
|
||||||
|
) -> AlphaTileId {
|
||||||
let alpha_tile_index = next_alpha_tile_index[level].fetch_add(1, Ordering::Relaxed);
|
let alpha_tile_index = next_alpha_tile_index[level].fetch_add(1, Ordering::Relaxed);
|
||||||
debug_assert!(alpha_tile_index < ALPHA_TILES_PER_LEVEL);
|
debug_assert!(alpha_tile_index < ALPHA_TILES_PER_LEVEL);
|
||||||
AlphaTileId((level * ALPHA_TILES_PER_LEVEL + alpha_tile_index) as u32)
|
AlphaTileId((level * ALPHA_TILES_PER_LEVEL + alpha_tile_index) as u32)
|
||||||
|
@ -470,11 +483,22 @@ impl Debug for RenderCommand {
|
||||||
fn fmt(&self, formatter: &mut Formatter) -> DebugResult {
|
fn fmt(&self, formatter: &mut Formatter) -> DebugResult {
|
||||||
match *self {
|
match *self {
|
||||||
RenderCommand::Start { .. } => write!(formatter, "Start"),
|
RenderCommand::Start { .. } => write!(formatter, "Start"),
|
||||||
RenderCommand::AllocateTexturePage { page_id, descriptor: _ } => {
|
RenderCommand::AllocateTexturePage {
|
||||||
|
page_id,
|
||||||
|
descriptor: _,
|
||||||
|
} => {
|
||||||
write!(formatter, "AllocateTexturePage({})", page_id.0)
|
write!(formatter, "AllocateTexturePage({})", page_id.0)
|
||||||
}
|
}
|
||||||
RenderCommand::UploadTexelData { ref texels, location } => {
|
RenderCommand::UploadTexelData {
|
||||||
write!(formatter, "UploadTexelData(x{:?}, {:?})", texels.len(), location)
|
ref texels,
|
||||||
|
location,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
formatter,
|
||||||
|
"UploadTexelData(x{:?}, {:?})",
|
||||||
|
texels.len(),
|
||||||
|
location
|
||||||
|
)
|
||||||
}
|
}
|
||||||
RenderCommand::DeclareRenderTarget { id, location } => {
|
RenderCommand::DeclareRenderTarget { id, location } => {
|
||||||
write!(formatter, "DeclareRenderTarget({:?}, {:?})", id, location)
|
write!(formatter, "DeclareRenderTarget({:?}, {:?})", id, location)
|
||||||
|
@ -486,23 +510,29 @@ impl Debug for RenderCommand {
|
||||||
write!(formatter, "AddFillsD3D9(x{})", fills.len())
|
write!(formatter, "AddFillsD3D9(x{})", fills.len())
|
||||||
}
|
}
|
||||||
RenderCommand::FlushFillsD3D9 => write!(formatter, "FlushFills"),
|
RenderCommand::FlushFillsD3D9 => write!(formatter, "FlushFills"),
|
||||||
RenderCommand::UploadSceneD3D11 { ref draw_segments, ref clip_segments } => {
|
RenderCommand::UploadSceneD3D11 {
|
||||||
write!(formatter,
|
ref draw_segments,
|
||||||
|
ref clip_segments,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
formatter,
|
||||||
"UploadSceneD3D11(DP x{}, DI x{}, CP x{}, CI x{})",
|
"UploadSceneD3D11(DP x{}, DI x{}, CP x{}, CI x{})",
|
||||||
draw_segments.points.len(),
|
draw_segments.points.len(),
|
||||||
draw_segments.indices.len(),
|
draw_segments.indices.len(),
|
||||||
clip_segments.points.len(),
|
clip_segments.points.len(),
|
||||||
clip_segments.indices.len())
|
clip_segments.indices.len()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
RenderCommand::PrepareClipTilesD3D11(ref batch) => {
|
RenderCommand::PrepareClipTilesD3D11(ref batch) => {
|
||||||
let clipped_path_count = match batch.clipped_path_info {
|
let clipped_path_count = match batch.clipped_path_info {
|
||||||
None => 0,
|
None => 0,
|
||||||
Some(ref clipped_path_info) => clipped_path_info.clipped_path_count,
|
Some(ref clipped_path_info) => clipped_path_info.clipped_path_count,
|
||||||
};
|
};
|
||||||
write!(formatter,
|
write!(
|
||||||
|
formatter,
|
||||||
"PrepareClipTilesD3D11({:?}, C {})",
|
"PrepareClipTilesD3D11({:?}, C {})",
|
||||||
batch.batch_id,
|
batch.batch_id, clipped_path_count
|
||||||
clipped_path_count)
|
)
|
||||||
}
|
}
|
||||||
RenderCommand::PushRenderTarget(render_target_id) => {
|
RenderCommand::PushRenderTarget(render_target_id) => {
|
||||||
write!(formatter, "PushRenderTarget({:?})", render_target_id)
|
write!(formatter, "PushRenderTarget({:?})", render_target_id)
|
||||||
|
@ -512,13 +542,18 @@ impl Debug for RenderCommand {
|
||||||
write!(formatter, "DrawTilesD3D9(x{:?})", batch.tiles.len())
|
write!(formatter, "DrawTilesD3D9(x{:?})", batch.tiles.len())
|
||||||
}
|
}
|
||||||
RenderCommand::DrawTilesD3D11(ref batch) => {
|
RenderCommand::DrawTilesD3D11(ref batch) => {
|
||||||
write!(formatter,
|
write!(
|
||||||
|
formatter,
|
||||||
"DrawTilesD3D11({:?}, C0 {:?})",
|
"DrawTilesD3D11({:?}, C0 {:?})",
|
||||||
batch.tile_batch_data.batch_id,
|
batch.tile_batch_data.batch_id, batch.color_texture
|
||||||
batch.color_texture)
|
)
|
||||||
}
|
}
|
||||||
RenderCommand::Finish { cpu_build_time } => {
|
RenderCommand::Finish { cpu_build_time } => {
|
||||||
write!(formatter, "Finish({} ms)", cpu_build_time.as_secs_f64() * 1000.0)
|
write!(
|
||||||
|
formatter,
|
||||||
|
"Finish({} ms)",
|
||||||
|
cpu_build_time.as_secs_f64() * 1000.0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,8 @@ impl RenderTransform {
|
||||||
}
|
}
|
||||||
|
|
||||||
let inverse_transform = perspective.transform.inverse();
|
let inverse_transform = perspective.transform.inverse();
|
||||||
let clip_polygon = points.into_iter()
|
let clip_polygon = points
|
||||||
|
.into_iter()
|
||||||
.map(|point| (inverse_transform * point).to_2d())
|
.map(|point| (inverse_transform * point).to_2d())
|
||||||
.collect();
|
.collect();
|
||||||
return PreparedRenderTransform::Perspective {
|
return PreparedRenderTransform::Perspective {
|
||||||
|
@ -166,17 +167,13 @@ impl PreparedBuildOptions {
|
||||||
pub(crate) fn to_prepare_mode(&self, renderer_level: RendererLevel) -> PrepareMode {
|
pub(crate) fn to_prepare_mode(&self, renderer_level: RendererLevel) -> PrepareMode {
|
||||||
match renderer_level {
|
match renderer_level {
|
||||||
RendererLevel::D3D9 => PrepareMode::CPU,
|
RendererLevel::D3D9 => PrepareMode::CPU,
|
||||||
RendererLevel::D3D11 => {
|
RendererLevel::D3D11 => match self.transform {
|
||||||
match self.transform {
|
|
||||||
PreparedRenderTransform::Perspective { .. } => PrepareMode::TransformCPUBinGPU,
|
PreparedRenderTransform::Perspective { .. } => PrepareMode::TransformCPUBinGPU,
|
||||||
PreparedRenderTransform::None => {
|
PreparedRenderTransform::None => PrepareMode::GPU {
|
||||||
PrepareMode::GPU { transform: Transform2F::default() }
|
transform: Transform2F::default(),
|
||||||
}
|
},
|
||||||
PreparedRenderTransform::Transform2D(transform) => {
|
PreparedRenderTransform::Transform2D(transform) => PrepareMode::GPU { transform },
|
||||||
PrepareMode::GPU { transform }
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use pathfinder_content::render_target::RenderTargetId;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::{RectF, RectI};
|
use pathfinder_geometry::rect::{RectF, RectI};
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
|
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F, Vector2I};
|
||||||
use pathfinder_gpu::TextureSamplingFlags;
|
use pathfinder_gpu::TextureSamplingFlags;
|
||||||
use pathfinder_simd::default::{F32x2, F32x4};
|
use pathfinder_simd::default::{F32x2, F32x4};
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
@ -118,7 +118,10 @@ impl Paint {
|
||||||
/// Creates a simple paint from a single base color.
|
/// Creates a simple paint from a single base color.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_color(color: ColorU) -> Paint {
|
pub fn from_color(color: ColorU) -> Paint {
|
||||||
Paint { base_color: color, overlay: None }
|
Paint {
|
||||||
|
base_color: color,
|
||||||
|
overlay: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a paint from a gradient.
|
/// Creates a paint from a gradient.
|
||||||
|
@ -167,12 +170,10 @@ impl Paint {
|
||||||
|
|
||||||
match self.overlay {
|
match self.overlay {
|
||||||
None => true,
|
None => true,
|
||||||
Some(ref overlay) => {
|
Some(ref overlay) => match overlay.contents {
|
||||||
match overlay.contents {
|
|
||||||
PaintContents::Gradient(ref gradient) => gradient.is_opaque(),
|
PaintContents::Gradient(ref gradient) => gradient.is_opaque(),
|
||||||
PaintContents::Pattern(ref pattern) => pattern.is_opaque(),
|
PaintContents::Pattern(ref pattern) => pattern.is_opaque(),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,12 +187,10 @@ impl Paint {
|
||||||
|
|
||||||
match self.overlay {
|
match self.overlay {
|
||||||
None => true,
|
None => true,
|
||||||
Some(ref overlay) => {
|
Some(ref overlay) => match overlay.contents {
|
||||||
match overlay.contents {
|
|
||||||
PaintContents::Gradient(ref gradient) => gradient.is_fully_transparent(),
|
PaintContents::Gradient(ref gradient) => gradient.is_fully_transparent(),
|
||||||
PaintContents::Pattern(_) => false,
|
PaintContents::Pattern(_) => false,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,12 +250,10 @@ impl Paint {
|
||||||
pub fn pattern(&self) -> Option<&Pattern> {
|
pub fn pattern(&self) -> Option<&Pattern> {
|
||||||
match self.overlay {
|
match self.overlay {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref overlay) => {
|
Some(ref overlay) => match overlay.contents {
|
||||||
match overlay.contents {
|
|
||||||
PaintContents::Pattern(ref pattern) => Some(pattern),
|
PaintContents::Pattern(ref pattern) => Some(pattern),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,12 +262,10 @@ impl Paint {
|
||||||
pub fn pattern_mut(&mut self) -> Option<&mut Pattern> {
|
pub fn pattern_mut(&mut self) -> Option<&mut Pattern> {
|
||||||
match self.overlay {
|
match self.overlay {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref mut overlay) => {
|
Some(ref mut overlay) => match overlay.contents {
|
||||||
match overlay.contents {
|
|
||||||
PaintContents::Pattern(ref mut pattern) => Some(pattern),
|
PaintContents::Pattern(ref mut pattern) => Some(pattern),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,12 +274,10 @@ impl Paint {
|
||||||
pub fn gradient(&self) -> Option<&Gradient> {
|
pub fn gradient(&self) -> Option<&Gradient> {
|
||||||
match self.overlay {
|
match self.overlay {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref overlay) => {
|
Some(ref overlay) => match overlay.contents {
|
||||||
match overlay.contents {
|
|
||||||
PaintContents::Gradient(ref gradient) => Some(gradient),
|
PaintContents::Gradient(ref gradient) => Some(gradient),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,13 +385,17 @@ impl Palette {
|
||||||
pub(crate) fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId {
|
pub(crate) fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId {
|
||||||
let id = self.render_targets.len() as u32;
|
let id = self.render_targets.len() as u32;
|
||||||
self.render_targets.push(render_target);
|
self.render_targets.push(render_target);
|
||||||
RenderTargetId { scene: self.scene_id.0, render_target: id }
|
RenderTargetId {
|
||||||
|
scene: self.scene_id.0,
|
||||||
|
render_target: id,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn build_paint_info(&mut self,
|
pub(crate) fn build_paint_info(
|
||||||
|
&mut self,
|
||||||
texture_manager: &mut PaintTextureManager,
|
texture_manager: &mut PaintTextureManager,
|
||||||
render_transform: Transform2F)
|
render_transform: Transform2F,
|
||||||
-> PaintInfo {
|
) -> PaintInfo {
|
||||||
// Assign render target locations.
|
// Assign render target locations.
|
||||||
let mut transient_paint_locations = vec![];
|
let mut transient_paint_locations = vec![];
|
||||||
let render_target_metadata =
|
let render_target_metadata =
|
||||||
|
@ -410,9 +407,11 @@ impl Palette {
|
||||||
gradient_tile_builder,
|
gradient_tile_builder,
|
||||||
image_texel_info,
|
image_texel_info,
|
||||||
used_image_hashes,
|
used_image_hashes,
|
||||||
} = self.assign_paint_locations(&render_target_metadata,
|
} = self.assign_paint_locations(
|
||||||
|
&render_target_metadata,
|
||||||
texture_manager,
|
texture_manager,
|
||||||
&mut transient_paint_locations);
|
&mut transient_paint_locations,
|
||||||
|
);
|
||||||
|
|
||||||
// Calculate texture transforms.
|
// Calculate texture transforms.
|
||||||
self.calculate_texture_transforms(&mut paint_metadata, texture_manager, render_transform);
|
self.calculate_texture_transforms(&mut paint_metadata, texture_manager, render_transform);
|
||||||
|
@ -425,36 +424,45 @@ impl Palette {
|
||||||
self.allocate_textures(&mut render_commands, texture_manager);
|
self.allocate_textures(&mut render_commands, texture_manager);
|
||||||
|
|
||||||
// Create render commands.
|
// Create render commands.
|
||||||
self.create_render_commands(&mut render_commands,
|
self.create_render_commands(
|
||||||
|
&mut render_commands,
|
||||||
render_target_metadata,
|
render_target_metadata,
|
||||||
gradient_tile_builder,
|
gradient_tile_builder,
|
||||||
image_texel_info);
|
image_texel_info,
|
||||||
|
);
|
||||||
|
|
||||||
// Free transient locations and unused images, now that they're no longer needed.
|
// Free transient locations and unused images, now that they're no longer needed.
|
||||||
self.free_transient_locations(texture_manager, transient_paint_locations);
|
self.free_transient_locations(texture_manager, transient_paint_locations);
|
||||||
self.free_unused_images(texture_manager, used_image_hashes);
|
self.free_unused_images(texture_manager, used_image_hashes);
|
||||||
|
|
||||||
PaintInfo { render_commands, paint_metadata }
|
PaintInfo {
|
||||||
|
render_commands,
|
||||||
|
paint_metadata,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_render_target_locations(&self,
|
fn assign_render_target_locations(
|
||||||
|
&self,
|
||||||
texture_manager: &mut PaintTextureManager,
|
texture_manager: &mut PaintTextureManager,
|
||||||
transient_paint_locations: &mut Vec<TextureLocation>)
|
transient_paint_locations: &mut Vec<TextureLocation>,
|
||||||
-> Vec<RenderTargetMetadata> {
|
) -> Vec<RenderTargetMetadata> {
|
||||||
let mut render_target_metadata = vec![];
|
let mut render_target_metadata = vec![];
|
||||||
for render_target in &self.render_targets {
|
for render_target in &self.render_targets {
|
||||||
let location = texture_manager.allocator.allocate_image(render_target.size());
|
let location = texture_manager
|
||||||
|
.allocator
|
||||||
|
.allocate_image(render_target.size());
|
||||||
render_target_metadata.push(RenderTargetMetadata { location });
|
render_target_metadata.push(RenderTargetMetadata { location });
|
||||||
transient_paint_locations.push(location);
|
transient_paint_locations.push(location);
|
||||||
}
|
}
|
||||||
render_target_metadata
|
render_target_metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_paint_locations(&self,
|
fn assign_paint_locations(
|
||||||
|
&self,
|
||||||
render_target_metadata: &[RenderTargetMetadata],
|
render_target_metadata: &[RenderTargetMetadata],
|
||||||
texture_manager: &mut PaintTextureManager,
|
texture_manager: &mut PaintTextureManager,
|
||||||
transient_paint_locations: &mut Vec<TextureLocation>)
|
transient_paint_locations: &mut Vec<TextureLocation>,
|
||||||
-> PaintLocationsInfo {
|
) -> PaintLocationsInfo {
|
||||||
let mut paint_metadata = vec![];
|
let mut paint_metadata = vec![];
|
||||||
let mut gradient_tile_builder = GradientTileBuilder::new();
|
let mut gradient_tile_builder = GradientTileBuilder::new();
|
||||||
let mut image_texel_info = vec![];
|
let mut image_texel_info = vec![];
|
||||||
|
@ -476,10 +484,11 @@ impl Palette {
|
||||||
|
|
||||||
// FIXME(pcwalton): The gradient size might not be big enough. Detect
|
// FIXME(pcwalton): The gradient size might not be big enough. Detect
|
||||||
// this.
|
// this.
|
||||||
let location =
|
let location = gradient_tile_builder.allocate(
|
||||||
gradient_tile_builder.allocate(allocator,
|
allocator,
|
||||||
transient_paint_locations,
|
transient_paint_locations,
|
||||||
gradient);
|
gradient,
|
||||||
|
);
|
||||||
Some(PaintColorTextureMetadata {
|
Some(PaintColorTextureMetadata {
|
||||||
location,
|
location,
|
||||||
page_scale: allocator.page_scale(location.page),
|
page_scale: allocator.page_scale(location.page),
|
||||||
|
@ -496,12 +505,17 @@ impl Palette {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
PaintContents::Pattern(ref pattern) => {
|
PaintContents::Pattern(ref pattern) => {
|
||||||
let border = vec2i(if pattern.repeat_x() { 0 } else { 1 },
|
let border = vec2i(
|
||||||
if pattern.repeat_y() { 0 } else { 1 });
|
if pattern.repeat_x() { 0 } else { 1 },
|
||||||
|
if pattern.repeat_y() { 0 } else { 1 },
|
||||||
|
);
|
||||||
|
|
||||||
let location;
|
let location;
|
||||||
match *pattern.source() {
|
match *pattern.source() {
|
||||||
PatternSource::RenderTarget { id: render_target_id, .. } => {
|
PatternSource::RenderTarget {
|
||||||
|
id: render_target_id,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let index = render_target_id.render_target as usize;
|
let index = render_target_id.render_target as usize;
|
||||||
location = render_target_metadata[index].location;
|
location = render_target_metadata[index].location;
|
||||||
}
|
}
|
||||||
|
@ -519,9 +533,11 @@ impl Palette {
|
||||||
let allocation_mode = AllocationMode::OwnPage;
|
let allocation_mode = AllocationMode::OwnPage;
|
||||||
location = allocator.allocate(
|
location = allocator.allocate(
|
||||||
image.size() + border * 2,
|
image.size() + border * 2,
|
||||||
allocation_mode);
|
allocation_mode,
|
||||||
texture_manager.cached_images.insert(image_hash,
|
);
|
||||||
location);
|
texture_manager
|
||||||
|
.cached_images
|
||||||
|
.insert(image_hash, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
image_texel_info.push(ImageTexelInfo {
|
image_texel_info.push(ImageTexelInfo {
|
||||||
|
@ -542,8 +558,10 @@ impl Palette {
|
||||||
sampling_flags.insert(TextureSamplingFlags::REPEAT_V);
|
sampling_flags.insert(TextureSamplingFlags::REPEAT_V);
|
||||||
}
|
}
|
||||||
if !pattern.smoothing_enabled() {
|
if !pattern.smoothing_enabled() {
|
||||||
sampling_flags.insert(TextureSamplingFlags::NEAREST_MIN |
|
sampling_flags.insert(
|
||||||
TextureSamplingFlags::NEAREST_MAG);
|
TextureSamplingFlags::NEAREST_MIN
|
||||||
|
| TextureSamplingFlags::NEAREST_MAG,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let filter = match pattern.filter() {
|
let filter = match pattern.filter() {
|
||||||
|
@ -582,24 +600,28 @@ impl Palette {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_texture_transforms(&self,
|
fn calculate_texture_transforms(
|
||||||
|
&self,
|
||||||
paint_metadata: &mut [PaintMetadata],
|
paint_metadata: &mut [PaintMetadata],
|
||||||
texture_manager: &mut PaintTextureManager,
|
texture_manager: &mut PaintTextureManager,
|
||||||
render_transform: Transform2F) {
|
render_transform: Transform2F,
|
||||||
|
) {
|
||||||
for (paint, metadata) in self.paints.iter().zip(paint_metadata.iter_mut()) {
|
for (paint, metadata) in self.paints.iter().zip(paint_metadata.iter_mut()) {
|
||||||
let color_texture_metadata = match metadata.color_texture_metadata {
|
let color_texture_metadata = match metadata.color_texture_metadata {
|
||||||
None => continue,
|
None => continue,
|
||||||
Some(ref mut color_texture_metadata) => color_texture_metadata,
|
Some(ref mut color_texture_metadata) => color_texture_metadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
let texture_scale = texture_manager.allocator
|
let texture_scale = texture_manager
|
||||||
|
.allocator
|
||||||
.page_scale(color_texture_metadata.location.page);
|
.page_scale(color_texture_metadata.location.page);
|
||||||
let texture_rect = color_texture_metadata.location.rect;
|
let texture_rect = color_texture_metadata.location.rect;
|
||||||
color_texture_metadata.transform = match paint.overlay
|
color_texture_metadata.transform = match paint
|
||||||
|
.overlay
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("Why do we have color texture \
|
.expect("Why do we have color texture metadata but no overlay?")
|
||||||
metadata but no overlay?")
|
.contents
|
||||||
.contents {
|
{
|
||||||
PaintContents::Gradient(Gradient {
|
PaintContents::Gradient(Gradient {
|
||||||
geometry: GradientGeometry::Linear(gradient_line),
|
geometry: GradientGeometry::Linear(gradient_line),
|
||||||
..
|
..
|
||||||
|
@ -620,16 +642,16 @@ impl Palette {
|
||||||
PatternSource::Image(_) => {
|
PatternSource::Image(_) => {
|
||||||
let texture_origin_uv =
|
let texture_origin_uv =
|
||||||
rect_to_uv(texture_rect, texture_scale).origin();
|
rect_to_uv(texture_rect, texture_scale).origin();
|
||||||
Transform2F::from_scale(texture_scale).translate(texture_origin_uv) *
|
Transform2F::from_scale(texture_scale).translate(texture_origin_uv)
|
||||||
pattern.transform().inverse()
|
* pattern.transform().inverse()
|
||||||
}
|
}
|
||||||
PatternSource::RenderTarget { .. } => {
|
PatternSource::RenderTarget { .. } => {
|
||||||
// FIXME(pcwalton): Only do this in GL, not Metal!
|
// FIXME(pcwalton): Only do this in GL, not Metal!
|
||||||
let texture_origin_uv =
|
let texture_origin_uv =
|
||||||
rect_to_uv(texture_rect, texture_scale).lower_left();
|
rect_to_uv(texture_rect, texture_scale).lower_left();
|
||||||
Transform2F::from_translation(texture_origin_uv) *
|
Transform2F::from_translation(texture_origin_uv)
|
||||||
Transform2F::from_scale(texture_scale * vec2f(1.0, -1.0)) *
|
* Transform2F::from_scale(texture_scale * vec2f(1.0, -1.0))
|
||||||
pattern.transform().inverse()
|
* pattern.transform().inverse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -638,10 +660,13 @@ impl Palette {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_texture_metadata(&self, paint_metadata: &[PaintMetadata])
|
fn create_texture_metadata(
|
||||||
-> Vec<TextureMetadataEntry> {
|
&self,
|
||||||
paint_metadata.iter().map(|paint_metadata| {
|
paint_metadata: &[PaintMetadata],
|
||||||
TextureMetadataEntry {
|
) -> Vec<TextureMetadataEntry> {
|
||||||
|
paint_metadata
|
||||||
|
.iter()
|
||||||
|
.map(|paint_metadata| TextureMetadataEntry {
|
||||||
color_0_transform: match paint_metadata.color_texture_metadata {
|
color_0_transform: match paint_metadata.color_texture_metadata {
|
||||||
None => Transform2F::default(),
|
None => Transform2F::default(),
|
||||||
Some(ref color_texture_metadata) => color_texture_metadata.transform,
|
Some(ref color_texture_metadata) => color_texture_metadata.transform,
|
||||||
|
@ -654,31 +679,41 @@ impl Palette {
|
||||||
base_color: paint_metadata.base_color,
|
base_color: paint_metadata.base_color,
|
||||||
filter: paint_metadata.filter(),
|
filter: paint_metadata.filter(),
|
||||||
blend_mode: paint_metadata.blend_mode,
|
blend_mode: paint_metadata.blend_mode,
|
||||||
}
|
})
|
||||||
}).collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_textures(&self,
|
fn allocate_textures(
|
||||||
|
&self,
|
||||||
render_commands: &mut Vec<RenderCommand>,
|
render_commands: &mut Vec<RenderCommand>,
|
||||||
texture_manager: &mut PaintTextureManager) {
|
texture_manager: &mut PaintTextureManager,
|
||||||
|
) {
|
||||||
for page_id in texture_manager.allocator.page_ids() {
|
for page_id in texture_manager.allocator.page_ids() {
|
||||||
let page_size = texture_manager.allocator.page_size(page_id);
|
let page_size = texture_manager.allocator.page_size(page_id);
|
||||||
let descriptor = TexturePageDescriptor { size: page_size };
|
let descriptor = TexturePageDescriptor { size: page_size };
|
||||||
|
|
||||||
if texture_manager.allocator.page_is_new(page_id) {
|
if texture_manager.allocator.page_is_new(page_id) {
|
||||||
render_commands.push(RenderCommand::AllocateTexturePage { page_id, descriptor });
|
render_commands.push(RenderCommand::AllocateTexturePage {
|
||||||
|
page_id,
|
||||||
|
descriptor,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
texture_manager.allocator.mark_all_pages_as_allocated();
|
texture_manager.allocator.mark_all_pages_as_allocated();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_render_commands(&self,
|
fn create_render_commands(
|
||||||
|
&self,
|
||||||
render_commands: &mut Vec<RenderCommand>,
|
render_commands: &mut Vec<RenderCommand>,
|
||||||
render_target_metadata: Vec<RenderTargetMetadata>,
|
render_target_metadata: Vec<RenderTargetMetadata>,
|
||||||
gradient_tile_builder: GradientTileBuilder,
|
gradient_tile_builder: GradientTileBuilder,
|
||||||
image_texel_info: Vec<ImageTexelInfo>) {
|
image_texel_info: Vec<ImageTexelInfo>,
|
||||||
|
) {
|
||||||
for (index, metadata) in render_target_metadata.iter().enumerate() {
|
for (index, metadata) in render_target_metadata.iter().enumerate() {
|
||||||
let id = RenderTargetId { scene: self.scene_id.0, render_target: index as u32 };
|
let id = RenderTargetId {
|
||||||
|
scene: self.scene_id.0,
|
||||||
|
render_target: index as u32,
|
||||||
|
};
|
||||||
render_commands.push(RenderCommand::DeclareRenderTarget {
|
render_commands.push(RenderCommand::DeclareRenderTarget {
|
||||||
id,
|
id,
|
||||||
location: metadata.location,
|
location: metadata.location,
|
||||||
|
@ -693,18 +728,22 @@ impl Palette {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn free_transient_locations(&self,
|
fn free_transient_locations(
|
||||||
|
&self,
|
||||||
texture_manager: &mut PaintTextureManager,
|
texture_manager: &mut PaintTextureManager,
|
||||||
transient_paint_locations: Vec<TextureLocation>) {
|
transient_paint_locations: Vec<TextureLocation>,
|
||||||
|
) {
|
||||||
for location in transient_paint_locations {
|
for location in transient_paint_locations {
|
||||||
texture_manager.allocator.free(location);
|
texture_manager.allocator.free(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frees images that are cached but not used this frame.
|
// Frees images that are cached but not used this frame.
|
||||||
fn free_unused_images(&self,
|
fn free_unused_images(
|
||||||
|
&self,
|
||||||
texture_manager: &mut PaintTextureManager,
|
texture_manager: &mut PaintTextureManager,
|
||||||
used_image_hashes: HashSet<ImageHash>) {
|
used_image_hashes: HashSet<ImageHash>,
|
||||||
|
) {
|
||||||
let cached_images = &mut texture_manager.cached_images;
|
let cached_images = &mut texture_manager.cached_images;
|
||||||
let allocator = &mut texture_manager.allocator;
|
let allocator = &mut texture_manager.allocator;
|
||||||
cached_images.retain(|image_hash, location| {
|
cached_images.retain(|image_hash, location| {
|
||||||
|
@ -719,9 +758,9 @@ impl Palette {
|
||||||
pub(crate) fn append_palette(&mut self, palette: Palette) -> MergedPaletteInfo {
|
pub(crate) fn append_palette(&mut self, palette: Palette) -> MergedPaletteInfo {
|
||||||
// Merge render targets.
|
// Merge render targets.
|
||||||
let mut render_target_mapping = HashMap::new();
|
let mut render_target_mapping = HashMap::new();
|
||||||
for (old_render_target_index, render_target) in palette.render_targets
|
for (old_render_target_index, render_target) in
|
||||||
.into_iter()
|
palette.render_targets.into_iter().enumerate()
|
||||||
.enumerate() {
|
{
|
||||||
let old_render_target_id = RenderTargetId {
|
let old_render_target_id = RenderTargetId {
|
||||||
scene: palette.scene_id.0,
|
scene: palette.scene_id.0,
|
||||||
render_target: old_render_target_index as u32,
|
render_target: old_render_target_index as u32,
|
||||||
|
@ -736,11 +775,12 @@ impl Palette {
|
||||||
let old_paint_id = PaintId(old_paint_index as u16);
|
let old_paint_id = PaintId(old_paint_index as u16);
|
||||||
let new_paint_id = match *old_paint.overlay() {
|
let new_paint_id = match *old_paint.overlay() {
|
||||||
None => self.push_paint(old_paint),
|
None => self.push_paint(old_paint),
|
||||||
Some(ref overlay) => {
|
Some(ref overlay) => match *overlay.contents() {
|
||||||
match *overlay.contents() {
|
PaintContents::Pattern(ref pattern) => match pattern.source() {
|
||||||
PaintContents::Pattern(ref pattern) => {
|
PatternSource::RenderTarget {
|
||||||
match pattern.source() {
|
id: old_render_target_id,
|
||||||
PatternSource::RenderTarget { id: old_render_target_id, size } => {
|
size,
|
||||||
|
} => {
|
||||||
let mut new_pattern =
|
let mut new_pattern =
|
||||||
Pattern::from_render_target(*old_render_target_id, *size);
|
Pattern::from_render_target(*old_render_target_id, *size);
|
||||||
new_pattern.set_filter(pattern.filter());
|
new_pattern.set_filter(pattern.filter());
|
||||||
|
@ -751,16 +791,17 @@ impl Palette {
|
||||||
self.push_paint(&Paint::from_pattern(new_pattern))
|
self.push_paint(&Paint::from_pattern(new_pattern))
|
||||||
}
|
}
|
||||||
_ => self.push_paint(old_paint),
|
_ => self.push_paint(old_paint),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
_ => self.push_paint(old_paint),
|
_ => self.push_paint(old_paint),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
paint_mapping.insert(old_paint_id, new_paint_id);
|
paint_mapping.insert(old_paint_id, new_paint_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MergedPaletteInfo { render_target_mapping, paint_mapping }
|
MergedPaletteInfo {
|
||||||
|
render_target_mapping,
|
||||||
|
paint_mapping,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,25 +823,27 @@ impl PaintMetadata {
|
||||||
pub(crate) fn filter(&self) -> Filter {
|
pub(crate) fn filter(&self) -> Filter {
|
||||||
match self.color_texture_metadata {
|
match self.color_texture_metadata {
|
||||||
None => Filter::None,
|
None => Filter::None,
|
||||||
Some(ref color_metadata) => {
|
Some(ref color_metadata) => match color_metadata.filter {
|
||||||
match color_metadata.filter {
|
|
||||||
PaintFilter::None => Filter::None,
|
PaintFilter::None => Filter::None,
|
||||||
PaintFilter::RadialGradient { line, radii } => {
|
PaintFilter::RadialGradient { line, radii } => {
|
||||||
let uv_rect = rect_to_uv(color_metadata.location.rect,
|
let uv_rect =
|
||||||
color_metadata.page_scale).contract(
|
rect_to_uv(color_metadata.location.rect, color_metadata.page_scale)
|
||||||
vec2f(0.0, color_metadata.page_scale.y() * 0.5));
|
.contract(vec2f(0.0, color_metadata.page_scale.y() * 0.5));
|
||||||
Filter::RadialGradient { line, radii, uv_origin: uv_rect.origin() }
|
Filter::RadialGradient {
|
||||||
}
|
line,
|
||||||
PaintFilter::PatternFilter(pattern_filter) => {
|
radii,
|
||||||
Filter::PatternFilter(pattern_filter)
|
uv_origin: uv_rect.origin(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PaintFilter::PatternFilter(pattern_filter) => Filter::PatternFilter(pattern_filter),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tile_batch_texture(&self) -> Option<TileBatchTexture> {
|
pub(crate) fn tile_batch_texture(&self) -> Option<TileBatchTexture> {
|
||||||
self.color_texture_metadata.as_ref().map(PaintColorTextureMetadata::as_tile_batch_texture)
|
self.color_texture_metadata
|
||||||
|
.as_ref()
|
||||||
|
.map(PaintColorTextureMetadata::as_tile_batch_texture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,13 +868,13 @@ impl GradientTileBuilder {
|
||||||
GradientTileBuilder { tiles: vec![] }
|
GradientTileBuilder { tiles: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate(&mut self,
|
fn allocate(
|
||||||
|
&mut self,
|
||||||
allocator: &mut TextureAllocator,
|
allocator: &mut TextureAllocator,
|
||||||
transient_paint_locations: &mut Vec<TextureLocation>,
|
transient_paint_locations: &mut Vec<TextureLocation>,
|
||||||
gradient: &Gradient)
|
gradient: &Gradient,
|
||||||
-> TextureLocation {
|
) -> TextureLocation {
|
||||||
if self.tiles.is_empty() ||
|
if self.tiles.is_empty() || self.tiles.last().unwrap().next_index == GRADIENT_TILE_LENGTH {
|
||||||
self.tiles.last().unwrap().next_index == GRADIENT_TILE_LENGTH {
|
|
||||||
let size = Vector2I::splat(GRADIENT_TILE_LENGTH as i32);
|
let size = Vector2I::splat(GRADIENT_TILE_LENGTH as i32);
|
||||||
let area = size.x() as usize * size.y() as usize;
|
let area = size.x() as usize * size.y() as usize;
|
||||||
let page_location = allocator.allocate(size, AllocationMode::OwnPage);
|
let page_location = allocator.allocate(size, AllocationMode::OwnPage);
|
||||||
|
@ -846,8 +889,10 @@ impl GradientTileBuilder {
|
||||||
let data = self.tiles.last_mut().unwrap();
|
let data = self.tiles.last_mut().unwrap();
|
||||||
let location = TextureLocation {
|
let location = TextureLocation {
|
||||||
page: data.page,
|
page: data.page,
|
||||||
rect: RectI::new(vec2i(0, data.next_index as i32),
|
rect: RectI::new(
|
||||||
vec2i(GRADIENT_TILE_LENGTH as i32, 1)),
|
vec2i(0, data.next_index as i32),
|
||||||
|
vec2i(GRADIENT_TILE_LENGTH as i32, 1),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
data.next_index += 1;
|
data.next_index += 1;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use pathfinder_content::outline::Outline;
|
||||||
use pathfinder_content::render_target::RenderTargetId;
|
use pathfinder_content::render_target::RenderTargetId;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2I};
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::Device;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -90,7 +90,9 @@ impl Scene {
|
||||||
let end_path_id = DrawPathId(draw_path_id.0 + 1);
|
let end_path_id = DrawPathId(draw_path_id.0 + 1);
|
||||||
match self.display_list.last_mut() {
|
match self.display_list.last_mut() {
|
||||||
Some(DisplayItem::DrawPaths(ref mut range)) => range.end = end_path_id,
|
Some(DisplayItem::DrawPaths(ref mut range)) => range.end = end_path_id,
|
||||||
_ => self.display_list.push(DisplayItem::DrawPaths(draw_path_id..end_path_id)),
|
_ => self
|
||||||
|
.display_list
|
||||||
|
.push(DisplayItem::DrawPaths(draw_path_id..end_path_id)),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.epoch.next();
|
self.epoch.next();
|
||||||
|
@ -111,7 +113,8 @@ impl Scene {
|
||||||
/// top of the stack.
|
/// top of the stack.
|
||||||
pub fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId {
|
pub fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId {
|
||||||
let render_target_id = self.palette.push_render_target(render_target);
|
let render_target_id = self.palette.push_render_target(render_target);
|
||||||
self.display_list.push(DisplayItem::PushRenderTarget(render_target_id));
|
self.display_list
|
||||||
|
.push(DisplayItem::PushRenderTarget(render_target_id));
|
||||||
self.epoch.next();
|
self.epoch.next();
|
||||||
render_target_id
|
render_target_id
|
||||||
}
|
}
|
||||||
|
@ -161,7 +164,8 @@ impl Scene {
|
||||||
match display_item {
|
match display_item {
|
||||||
DisplayItem::PushRenderTarget(old_render_target_id) => {
|
DisplayItem::PushRenderTarget(old_render_target_id) => {
|
||||||
let new_render_target_id = render_target_mapping[&old_render_target_id];
|
let new_render_target_id = render_target_mapping[&old_render_target_id];
|
||||||
self.display_list.push(DisplayItem::PushRenderTarget(new_render_target_id));
|
self.display_list
|
||||||
|
.push(DisplayItem::PushRenderTarget(new_render_target_id));
|
||||||
}
|
}
|
||||||
DisplayItem::PopRenderTarget => {
|
DisplayItem::PopRenderTarget => {
|
||||||
self.display_list.push(DisplayItem::PopRenderTarget);
|
self.display_list.push(DisplayItem::PopRenderTarget);
|
||||||
|
@ -180,11 +184,13 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn build_paint_info(&mut self,
|
pub(crate) fn build_paint_info(
|
||||||
|
&mut self,
|
||||||
texture_manager: &mut PaintTextureManager,
|
texture_manager: &mut PaintTextureManager,
|
||||||
render_transform: Transform2F)
|
render_transform: Transform2F,
|
||||||
-> PaintInfo {
|
) -> PaintInfo {
|
||||||
self.palette.build_paint_info(texture_manager, render_transform)
|
self.palette
|
||||||
|
.build_paint_info(texture_manager, render_transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a new paint, which specifies how paths are to be filled or stroked. Returns a paint
|
/// Defines a new paint, which specifies how paths are to be filled or stroked. Returns a paint
|
||||||
|
@ -227,10 +233,11 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub(crate) fn apply_render_options(&self,
|
pub(crate) fn apply_render_options(
|
||||||
|
&self,
|
||||||
original_outline: &Outline,
|
original_outline: &Outline,
|
||||||
options: &PreparedBuildOptions)
|
options: &PreparedBuildOptions,
|
||||||
-> Outline {
|
) -> Outline {
|
||||||
let mut outline;
|
let mut outline;
|
||||||
match options.transform {
|
match options.transform {
|
||||||
PreparedRenderTransform::Perspective {
|
PreparedRenderTransform::Perspective {
|
||||||
|
@ -289,11 +296,14 @@ impl Scene {
|
||||||
/// `SequentialExecutor` to prepare commands on a single thread or `RayonExecutor` to prepare
|
/// `SequentialExecutor` to prepare commands on a single thread or `RayonExecutor` to prepare
|
||||||
/// commands in parallel across multiple threads.
|
/// commands in parallel across multiple threads.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build<'a, 'b, E>(&mut self,
|
pub fn build<'a, 'b, E>(
|
||||||
|
&mut self,
|
||||||
options: BuildOptions,
|
options: BuildOptions,
|
||||||
sink: &'b mut SceneSink<'a>,
|
sink: &'b mut SceneSink<'a>,
|
||||||
executor: &E)
|
executor: &E,
|
||||||
where E: Executor {
|
) where
|
||||||
|
E: Executor,
|
||||||
|
{
|
||||||
let prepared_options = options.prepare(self.bounds);
|
let prepared_options = options.prepare(self.bounds);
|
||||||
SceneBuilder::new(self, &prepared_options, sink).build(executor)
|
SceneBuilder::new(self, &prepared_options, sink).build(executor)
|
||||||
}
|
}
|
||||||
|
@ -334,7 +344,10 @@ impl Scene {
|
||||||
/// Returns the paint with the given ID.
|
/// Returns the paint with the given ID.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_paint(&self, paint_id: PaintId) -> &Paint {
|
pub fn get_paint(&self, paint_id: PaintId) -> &Paint {
|
||||||
self.palette.paints.get(paint_id.0 as usize).expect("No paint with that ID!")
|
self.palette
|
||||||
|
.paints
|
||||||
|
.get(paint_id.0 as usize)
|
||||||
|
.expect("No paint with that ID!")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the globally-unique ID of the scene.
|
/// Returns the globally-unique ID of the scene.
|
||||||
|
@ -349,12 +362,16 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience method to build a scene and accumulate commands into a vector.
|
/// A convenience method to build a scene and accumulate commands into a vector.
|
||||||
pub fn build_into_vector<D, E>(&mut self,
|
pub fn build_into_vector<D, E>(
|
||||||
|
&mut self,
|
||||||
renderer: &mut Renderer<D>,
|
renderer: &mut Renderer<D>,
|
||||||
build_options: BuildOptions,
|
build_options: BuildOptions,
|
||||||
executor: E)
|
executor: E,
|
||||||
-> Vec<RenderCommand>
|
) -> Vec<RenderCommand>
|
||||||
where D: Device, E: Executor {
|
where
|
||||||
|
D: Device,
|
||||||
|
E: Executor,
|
||||||
|
{
|
||||||
let commands = Arc::new(Mutex::new(vec![]));
|
let commands = Arc::new(Mutex::new(vec![]));
|
||||||
let commands_for_listener = commands.clone();
|
let commands_for_listener = commands.clone();
|
||||||
let listener = RenderCommandListener::new(Box::new(move |command| {
|
let listener = RenderCommandListener::new(Box::new(move |command| {
|
||||||
|
@ -368,11 +385,15 @@ impl Scene {
|
||||||
|
|
||||||
/// A convenience method to build a scene and send the resulting commands to the given
|
/// A convenience method to build a scene and send the resulting commands to the given
|
||||||
/// renderer.
|
/// renderer.
|
||||||
pub fn build_and_render<D, E>(&mut self,
|
pub fn build_and_render<D, E>(
|
||||||
|
&mut self,
|
||||||
renderer: &mut Renderer<D>,
|
renderer: &mut Renderer<D>,
|
||||||
build_options: BuildOptions,
|
build_options: BuildOptions,
|
||||||
executor: E)
|
executor: E,
|
||||||
where D: Device, E: Executor + Send {
|
) where
|
||||||
|
D: Device,
|
||||||
|
E: Executor + Send,
|
||||||
|
{
|
||||||
std::thread::scope(move |scope| {
|
std::thread::scope(move |scope| {
|
||||||
let (tx, rx) = flume::bounded(MAX_MESSAGES_IN_FLIGHT);
|
let (tx, rx) = flume::bounded(MAX_MESSAGES_IN_FLIGHT);
|
||||||
|
|
||||||
|
@ -380,9 +401,8 @@ impl Scene {
|
||||||
|
|
||||||
// TODO: avoid this auxiliary thread
|
// TODO: avoid this auxiliary thread
|
||||||
scope.spawn(move || {
|
scope.spawn(move || {
|
||||||
let listener = RenderCommandListener::new(Box::new(move |command| {
|
let listener =
|
||||||
tx.send(command).unwrap()
|
RenderCommandListener::new(Box::new(move |command| tx.send(command).unwrap()));
|
||||||
}));
|
|
||||||
let mut sink = SceneSink::new(listener, level);
|
let mut sink = SceneSink::new(listener, level);
|
||||||
self.build(build_options, &mut sink, &executor);
|
self.build(build_options, &mut sink, &executor);
|
||||||
});
|
});
|
||||||
|
@ -430,9 +450,15 @@ impl SceneEpoch {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn successor(&self) -> SceneEpoch {
|
fn successor(&self) -> SceneEpoch {
|
||||||
if self.lo == u64::MAX {
|
if self.lo == u64::MAX {
|
||||||
SceneEpoch { hi: self.hi + 1, lo: 0 }
|
SceneEpoch {
|
||||||
|
hi: self.hi + 1,
|
||||||
|
lo: 0,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
SceneEpoch { hi: self.hi, lo: self.lo + 1 }
|
SceneEpoch {
|
||||||
|
hi: self.hi,
|
||||||
|
lo: self.lo + 1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,8 +471,10 @@ impl SceneEpoch {
|
||||||
impl<'a> SceneSink<'a> {
|
impl<'a> SceneSink<'a> {
|
||||||
/// Creates a new scene sink from the given render command listener and level.
|
/// Creates a new scene sink from the given render command listener and level.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(listener: RenderCommandListener<'a>, renderer_level: RendererLevel)
|
pub fn new(
|
||||||
-> SceneSink<'a> {
|
listener: RenderCommandListener<'a>,
|
||||||
|
renderer_level: RendererLevel,
|
||||||
|
) -> SceneSink<'a> {
|
||||||
SceneSink {
|
SceneSink {
|
||||||
listener,
|
listener,
|
||||||
renderer_level,
|
renderer_level,
|
||||||
|
@ -607,7 +635,12 @@ impl ClipPath {
|
||||||
/// has no name.
|
/// has no name.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(outline: Outline) -> ClipPath {
|
pub fn new(outline: Outline) -> ClipPath {
|
||||||
ClipPath { outline, clip_path: None, fill_rule: FillRule::Winding, name: String::new() }
|
ClipPath {
|
||||||
|
outline,
|
||||||
|
clip_path: None,
|
||||||
|
fill_rule: FillRule::Winding,
|
||||||
|
name: String::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the outline of this clip path, which defines its vector commands.
|
/// Returns the outline of this clip path, which defines its vector commands.
|
||||||
|
|
|
@ -9,18 +9,26 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{vec2i, Vector2I};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DenseTileMap<T> where T: Clone + Copy {
|
pub struct DenseTileMap<T>
|
||||||
|
where
|
||||||
|
T: Clone + Copy,
|
||||||
|
{
|
||||||
pub data: Vec<T>,
|
pub data: Vec<T>,
|
||||||
pub rect: RectI,
|
pub rect: RectI,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DenseTileMap<T> where T: Clone + Copy {
|
impl<T> DenseTileMap<T>
|
||||||
|
where
|
||||||
|
T: Clone + Copy,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_builder<F>(mut build: F, rect: RectI) -> DenseTileMap<T>
|
pub fn from_builder<F>(mut build: F, rect: RectI) -> DenseTileMap<T>
|
||||||
where F: FnMut(Vector2I) -> T {
|
where
|
||||||
|
F: FnMut(Vector2I) -> T,
|
||||||
|
{
|
||||||
let mut data = Vec::with_capacity(rect.size().x() as usize * rect.size().y() as usize);
|
let mut data = Vec::with_capacity(rect.size().x() as usize * rect.size().y() as usize);
|
||||||
for y in rect.min_y()..rect.max_y() {
|
for y in rect.min_y()..rect.max_y() {
|
||||||
for x in rect.min_x()..rect.max_x() {
|
for x in rect.min_x()..rect.max_x() {
|
||||||
|
@ -32,7 +40,8 @@ impl<T> DenseTileMap<T> where T: Clone + Copy {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, coords: Vector2I) -> Option<&T> {
|
pub fn get(&self, coords: Vector2I) -> Option<&T> {
|
||||||
self.coords_to_index(coords).and_then(|index| self.data.get(index))
|
self.coords_to_index(coords)
|
||||||
|
.and_then(|index| self.data.get(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -16,14 +16,14 @@ use crate::gpu::options::RendererLevel;
|
||||||
use crate::gpu_data::AlphaTileId;
|
use crate::gpu_data::AlphaTileId;
|
||||||
use crate::options::PrepareMode;
|
use crate::options::PrepareMode;
|
||||||
use crate::scene::{ClipPathId, PathId};
|
use crate::scene::{ClipPathId, PathId};
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH, TilingPathInfo};
|
use crate::tiles::{TilingPathInfo, TILE_HEIGHT, TILE_WIDTH};
|
||||||
use pathfinder_content::clip;
|
use pathfinder_content::clip;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::{ContourIterFlags, Outline};
|
use pathfinder_content::outline::{ContourIterFlags, Outline};
|
||||||
use pathfinder_content::segment::Segment;
|
use pathfinder_content::segment::Segment;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
|
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F, Vector2I};
|
||||||
use pathfinder_simd::default::{F32x2, U32x2};
|
use pathfinder_simd::default::{F32x2, U32x2};
|
||||||
use std::f32::NEG_INFINITY;
|
use std::f32::NEG_INFINITY;
|
||||||
|
|
||||||
|
@ -37,7 +37,8 @@ pub(crate) struct Tiler<'a, 'b, 'c, 'd> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
||||||
pub(crate) fn new(scene_builder: &'a SceneBuilder<'b, 'a, 'c, 'd>,
|
pub(crate) fn new(
|
||||||
|
scene_builder: &'a SceneBuilder<'b, 'a, 'c, 'd>,
|
||||||
path_id: PathId,
|
path_id: PathId,
|
||||||
outline: &'a Outline,
|
outline: &'a Outline,
|
||||||
fill_rule: FillRule,
|
fill_rule: FillRule,
|
||||||
|
@ -45,24 +46,34 @@ impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
||||||
prepare_mode: &PrepareMode,
|
prepare_mode: &PrepareMode,
|
||||||
clip_path_id: Option<ClipPathId>,
|
clip_path_id: Option<ClipPathId>,
|
||||||
built_clip_paths: &'a [BuiltPath],
|
built_clip_paths: &'a [BuiltPath],
|
||||||
path_info: TilingPathInfo)
|
path_info: TilingPathInfo,
|
||||||
-> Tiler<'a, 'b, 'c, 'd> {
|
) -> Tiler<'a, 'b, 'c, 'd> {
|
||||||
let bounds = outline.bounds().intersection(view_box).unwrap_or(RectF::default());
|
let bounds = outline
|
||||||
|
.bounds()
|
||||||
|
.intersection(view_box)
|
||||||
|
.unwrap_or(RectF::default());
|
||||||
|
|
||||||
let clip_path = match clip_path_id {
|
let clip_path = match clip_path_id {
|
||||||
Some(clip_path_id) => Some(&built_clip_paths[clip_path_id.0 as usize]),
|
Some(clip_path_id) => Some(&built_clip_paths[clip_path_id.0 as usize]),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let object_builder = ObjectBuilder::new(path_id,
|
let object_builder = ObjectBuilder::new(
|
||||||
|
path_id,
|
||||||
bounds,
|
bounds,
|
||||||
view_box,
|
view_box,
|
||||||
fill_rule,
|
fill_rule,
|
||||||
prepare_mode,
|
prepare_mode,
|
||||||
clip_path_id,
|
clip_path_id,
|
||||||
&path_info);
|
&path_info,
|
||||||
|
);
|
||||||
|
|
||||||
Tiler { scene_builder, object_builder, outline, clip_path }
|
Tiler {
|
||||||
|
scene_builder,
|
||||||
|
object_builder,
|
||||||
|
outline,
|
||||||
|
clip_path,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generate_tiles(&mut self) {
|
pub(crate) fn generate_tiles(&mut self) {
|
||||||
|
@ -93,9 +104,11 @@ impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
||||||
fn prepare_tiles(&mut self) {
|
fn prepare_tiles(&mut self) {
|
||||||
// Don't do this here if the GPU will do it.
|
// Don't do this here if the GPU will do it.
|
||||||
let (backdrops, tiles, clips) = match self.object_builder.built_path.data {
|
let (backdrops, tiles, clips) = match self.object_builder.built_path.data {
|
||||||
BuiltPathData::CPU(ref mut tiled_data) => {
|
BuiltPathData::CPU(ref mut tiled_data) => (
|
||||||
(&mut tiled_data.backdrops, &mut tiled_data.tiles, &mut tiled_data.clip_tiles)
|
&mut tiled_data.backdrops,
|
||||||
}
|
&mut tiled_data.tiles,
|
||||||
|
&mut tiled_data.clip_tiles,
|
||||||
|
),
|
||||||
BuiltPathData::TransformCPUBinGPU(_) | BuiltPathData::GPU => {
|
BuiltPathData::TransformCPUBinGPU(_) | BuiltPathData::GPU => {
|
||||||
panic!("We shouldn't be preparing tiles on CPU!")
|
panic!("We shouldn't be preparing tiles on CPU!")
|
||||||
}
|
}
|
||||||
|
@ -118,13 +131,15 @@ impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
||||||
};
|
};
|
||||||
match clip_tiles.get(tile_coords) {
|
match clip_tiles.get(tile_coords) {
|
||||||
Some(clip_tile) => {
|
Some(clip_tile) => {
|
||||||
if clip_tile.alpha_tile_id != AlphaTileId(!0) &&
|
if clip_tile.alpha_tile_id != AlphaTileId(!0)
|
||||||
draw_alpha_tile_id != AlphaTileId(!0) {
|
&& draw_alpha_tile_id != AlphaTileId(!0)
|
||||||
|
{
|
||||||
// Hard case: We have an alpha tile and a clip tile with masks. Add a
|
// Hard case: We have an alpha tile and a clip tile with masks. Add a
|
||||||
// job to combine the two masks. Because the mask combining step
|
// job to combine the two masks. Because the mask combining step
|
||||||
// applies the backdrops, zero out the backdrop in the draw tile itself
|
// applies the backdrops, zero out the backdrop in the draw tile itself
|
||||||
// so that we don't double-count it.
|
// so that we don't double-count it.
|
||||||
let clip = clips.as_mut()
|
let clip = clips
|
||||||
|
.as_mut()
|
||||||
.expect("Where are the clips?")
|
.expect("Where are the clips?")
|
||||||
.get_mut(tile_coords)
|
.get_mut(tile_coords)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -133,15 +148,17 @@ impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
||||||
clip.src_tile_id = clip_tile.alpha_tile_id;
|
clip.src_tile_id = clip_tile.alpha_tile_id;
|
||||||
clip.src_backdrop = clip_tile.backdrop as i32;
|
clip.src_backdrop = clip_tile.backdrop as i32;
|
||||||
draw_tile_backdrop = 0;
|
draw_tile_backdrop = 0;
|
||||||
} else if clip_tile.alpha_tile_id != AlphaTileId(!0) &&
|
} else if clip_tile.alpha_tile_id != AlphaTileId(!0)
|
||||||
draw_alpha_tile_id == AlphaTileId(!0) &&
|
&& draw_alpha_tile_id == AlphaTileId(!0)
|
||||||
draw_tile_backdrop != 0 {
|
&& draw_tile_backdrop != 0
|
||||||
|
{
|
||||||
// This is a solid draw tile, but there's a clip applied. Replace it
|
// This is a solid draw tile, but there's a clip applied. Replace it
|
||||||
// with an alpha tile pointing directly to the clip mask.
|
// with an alpha tile pointing directly to the clip mask.
|
||||||
draw_alpha_tile_id = clip_tile.alpha_tile_id;
|
draw_alpha_tile_id = clip_tile.alpha_tile_id;
|
||||||
draw_tile_backdrop = clip_tile.backdrop;
|
draw_tile_backdrop = clip_tile.backdrop;
|
||||||
} else if clip_tile.alpha_tile_id == AlphaTileId(!0) &&
|
} else if clip_tile.alpha_tile_id == AlphaTileId(!0)
|
||||||
clip_tile.backdrop == 0 {
|
&& clip_tile.backdrop == 0
|
||||||
|
{
|
||||||
// This is a blank clip tile. Cull the draw tile entirely.
|
// This is a blank clip tile. Cull the draw tile entirely.
|
||||||
draw_alpha_tile_id = AlphaTileId(!0);
|
draw_alpha_tile_id = AlphaTileId(!0);
|
||||||
draw_tile_backdrop = 0;
|
draw_tile_backdrop = 0;
|
||||||
|
@ -163,17 +180,20 @@ impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_segment(segment: &Segment,
|
fn process_segment(
|
||||||
|
segment: &Segment,
|
||||||
scene_builder: &SceneBuilder,
|
scene_builder: &SceneBuilder,
|
||||||
object_builder: &mut ObjectBuilder) {
|
object_builder: &mut ObjectBuilder,
|
||||||
|
) {
|
||||||
// TODO(pcwalton): Stop degree elevating.
|
// TODO(pcwalton): Stop degree elevating.
|
||||||
if segment.is_quadratic() {
|
if segment.is_quadratic() {
|
||||||
let cubic = segment.to_cubic();
|
let cubic = segment.to_cubic();
|
||||||
return process_segment(&cubic, scene_builder, object_builder);
|
return process_segment(&cubic, scene_builder, object_builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if segment.is_line() ||
|
if segment.is_line()
|
||||||
(segment.is_cubic() && segment.as_cubic_segment().is_flat(FLATTENING_TOLERANCE)) {
|
|| (segment.is_cubic() && segment.as_cubic_segment().is_flat(FLATTENING_TOLERANCE))
|
||||||
|
{
|
||||||
return process_line_segment(segment.baseline, scene_builder, object_builder);
|
return process_line_segment(segment.baseline, scene_builder, object_builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,12 +208,16 @@ fn process_segment(segment: &Segment,
|
||||||
//
|
//
|
||||||
// The algorithm to step through tiles is Amanatides and Woo, "A Fast Voxel Traversal Algorithm for
|
// The algorithm to step through tiles is Amanatides and Woo, "A Fast Voxel Traversal Algorithm for
|
||||||
// Ray Tracing" 1987: http://www.cse.yorku.ca/~amana/research/grid.pdf
|
// Ray Tracing" 1987: http://www.cse.yorku.ca/~amana/research/grid.pdf
|
||||||
fn process_line_segment(line_segment: LineSegment2F,
|
fn process_line_segment(
|
||||||
|
line_segment: LineSegment2F,
|
||||||
scene_builder: &SceneBuilder,
|
scene_builder: &SceneBuilder,
|
||||||
object_builder: &mut ObjectBuilder) {
|
object_builder: &mut ObjectBuilder,
|
||||||
|
) {
|
||||||
let view_box = scene_builder.scene.view_box();
|
let view_box = scene_builder.scene.view_box();
|
||||||
let clip_box = RectF::from_points(vec2f(view_box.min_x(), NEG_INFINITY),
|
let clip_box = RectF::from_points(
|
||||||
view_box.lower_right());
|
vec2f(view_box.min_x(), NEG_INFINITY),
|
||||||
|
view_box.lower_right(),
|
||||||
|
);
|
||||||
let line_segment = match clip::clip_line_segment_to_rect(line_segment, clip_box) {
|
let line_segment = match clip::clip_line_segment_to_rect(line_segment, clip_box) {
|
||||||
None => return,
|
None => return,
|
||||||
Some(line_segment) => line_segment,
|
Some(line_segment) => line_segment,
|
||||||
|
@ -202,8 +226,9 @@ fn process_line_segment(line_segment: LineSegment2F,
|
||||||
let tile_size = vec2f(TILE_WIDTH as f32, TILE_HEIGHT as f32);
|
let tile_size = vec2f(TILE_WIDTH as f32, TILE_HEIGHT as f32);
|
||||||
let tile_size_recip = Vector2F::splat(1.0) / tile_size;
|
let tile_size_recip = Vector2F::splat(1.0) / tile_size;
|
||||||
|
|
||||||
let tile_line_segment =
|
let tile_line_segment = (line_segment.0 * tile_size_recip.0.concat_xy_xy(tile_size_recip.0))
|
||||||
(line_segment.0 * tile_size_recip.0.concat_xy_xy(tile_size_recip.0)).floor().to_i32x4();
|
.floor()
|
||||||
|
.to_i32x4();
|
||||||
let from_tile_coords = Vector2I(tile_line_segment.xy());
|
let from_tile_coords = Vector2I(tile_line_segment.xy());
|
||||||
let to_tile_coords = Vector2I(tile_line_segment.zw());
|
let to_tile_coords = Vector2I(tile_line_segment.zw());
|
||||||
|
|
||||||
|
@ -216,8 +241,9 @@ fn process_line_segment(line_segment: LineSegment2F,
|
||||||
|
|
||||||
// Compute `first_tile_crossing = (from_tile_coords + vec2i(vector.x >= 0 ? 1 : 0,
|
// Compute `first_tile_crossing = (from_tile_coords + vec2i(vector.x >= 0 ? 1 : 0,
|
||||||
// vector.y >= 0 ? 1 : 0)) * tile_size`.
|
// vector.y >= 0 ? 1 : 0)) * tile_size`.
|
||||||
let first_tile_crossing = (from_tile_coords +
|
let first_tile_crossing =
|
||||||
Vector2I((!vector_is_negative & U32x2::splat(1)).to_i32x2())).to_f32() * tile_size;
|
(from_tile_coords + Vector2I((!vector_is_negative & U32x2::splat(1)).to_i32x2())).to_f32()
|
||||||
|
* tile_size;
|
||||||
|
|
||||||
let mut t_max = (first_tile_crossing - line_segment.from()) / vector;
|
let mut t_max = (first_tile_crossing - line_segment.from()) / vector;
|
||||||
let t_delta = (tile_size / vector).abs();
|
let t_delta = (tile_size / vector).abs();
|
||||||
|
@ -244,11 +270,19 @@ fn process_line_segment(line_segment: LineSegment2F,
|
||||||
//
|
//
|
||||||
// In that case we just need to step in the positive direction to move to the lower
|
// In that case we just need to step in the positive direction to move to the lower
|
||||||
// right tile.
|
// right tile.
|
||||||
if step.x() > 0 { StepDirection::X } else { StepDirection::Y }
|
if step.x() > 0 {
|
||||||
|
StepDirection::X
|
||||||
|
} else {
|
||||||
|
StepDirection::Y
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let next_t =
|
let next_t = (if next_step_direction == StepDirection::X {
|
||||||
(if next_step_direction == StepDirection::X { t_max.x() } else { t_max.y() }).min(1.0);
|
t_max.x()
|
||||||
|
} else {
|
||||||
|
t_max.y()
|
||||||
|
})
|
||||||
|
.min(1.0);
|
||||||
|
|
||||||
// If we've reached the end tile, don't step at all.
|
// If we've reached the end tile, don't step at all.
|
||||||
let next_step_direction = if tile_coords == to_tile_coords {
|
let next_step_direction = if tile_coords == to_tile_coords {
|
||||||
|
@ -264,13 +298,15 @@ fn process_line_segment(line_segment: LineSegment2F,
|
||||||
// Add extra fills if necessary.
|
// Add extra fills if necessary.
|
||||||
if step.y() < 0 && next_step_direction == Some(StepDirection::Y) {
|
if step.y() < 0 && next_step_direction == Some(StepDirection::Y) {
|
||||||
// Leaves through top boundary.
|
// Leaves through top boundary.
|
||||||
let auxiliary_segment = LineSegment2F::new(clipped_line_segment.to(),
|
let auxiliary_segment =
|
||||||
tile_coords.to_f32() * tile_size);
|
LineSegment2F::new(clipped_line_segment.to(), tile_coords.to_f32() * tile_size);
|
||||||
object_builder.add_fill(scene_builder, auxiliary_segment, tile_coords);
|
object_builder.add_fill(scene_builder, auxiliary_segment, tile_coords);
|
||||||
} else if step.y() > 0 && last_step_direction == Some(StepDirection::Y) {
|
} else if step.y() > 0 && last_step_direction == Some(StepDirection::Y) {
|
||||||
// Enters through top boundary.
|
// Enters through top boundary.
|
||||||
let auxiliary_segment = LineSegment2F::new(tile_coords.to_f32() * tile_size,
|
let auxiliary_segment = LineSegment2F::new(
|
||||||
clipped_line_segment.from());
|
tile_coords.to_f32() * tile_size,
|
||||||
|
clipped_line_segment.from(),
|
||||||
|
);
|
||||||
object_builder.add_fill(scene_builder, auxiliary_segment, tile_coords);
|
object_builder.add_fill(scene_builder, auxiliary_segment, tile_coords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use crate::gpu_data::{TileObjectPrimitive, TILE_CTRL_MASK_WINDING};
|
||||||
use crate::gpu_data::{TILE_CTRL_MASK_0_SHIFT, TILE_CTRL_MASK_EVEN_ODD};
|
use crate::gpu_data::{TILE_CTRL_MASK_0_SHIFT, TILE_CTRL_MASK_EVEN_ODD};
|
||||||
use crate::gpu_data::{TILE_CTRL_MASK_WINDING, TileObjectPrimitive};
|
|
||||||
use crate::paint::PaintId;
|
use crate::paint::PaintId;
|
||||||
use pathfinder_content::effects::BlendMode;
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
|
@ -62,10 +62,14 @@ impl TilingPathInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn round_rect_out_to_tile_bounds(rect: RectF) -> RectI {
|
pub fn round_rect_out_to_tile_bounds(rect: RectF) -> RectI {
|
||||||
(rect * vec2f(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32)).round_out().to_i32()
|
(rect * vec2f(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32))
|
||||||
|
.round_out()
|
||||||
|
.to_i32()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileObjectPrimitive {
|
impl TileObjectPrimitive {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_solid(&self) -> bool { !self.alpha_tile_id.is_valid() }
|
pub fn is_solid(&self) -> bool {
|
||||||
|
!self.alpha_tile_id.is_valid()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,16 @@ fn main() {
|
||||||
let mut dest = File::create(dest_path).unwrap();
|
let mut dest = File::create(dest_path).unwrap();
|
||||||
let cwd = env::current_dir().unwrap();
|
let cwd = env::current_dir().unwrap();
|
||||||
|
|
||||||
writeln!(&mut dest, "// Generated by `pathfinder/resources/build.rs`. Do not edit!\n").unwrap();
|
writeln!(
|
||||||
writeln!(&mut dest,
|
&mut dest,
|
||||||
"pub static RESOURCES: &'static [(&'static str, &'static [u8])] = &[").unwrap();
|
"// Generated by `pathfinder/resources/build.rs`. Do not edit!\n"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
writeln!(
|
||||||
|
&mut dest,
|
||||||
|
"pub static RESOURCES: &'static [(&'static str, &'static [u8])] = &["
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let src = BufReader::new(File::open("MANIFEST").unwrap());
|
let src = BufReader::new(File::open("MANIFEST").unwrap());
|
||||||
for line in src.lines() {
|
for line in src.lines() {
|
||||||
|
@ -36,10 +43,12 @@ fn main() {
|
||||||
full_path.push(line);
|
full_path.push(line);
|
||||||
let escaped_full_path = full_path.to_str().unwrap().escape_default().to_string();
|
let escaped_full_path = full_path.to_str().unwrap().escape_default().to_string();
|
||||||
|
|
||||||
writeln!(&mut dest,
|
writeln!(
|
||||||
|
&mut dest,
|
||||||
" (\"{}\", include_bytes!(\"{}\")),",
|
" (\"{}\", include_bytes!(\"{}\")),",
|
||||||
escaped_path,
|
escaped_path, escaped_full_path
|
||||||
escaped_full_path).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed={}", line);
|
println!("cargo:rerun-if-changed={}", line);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,11 @@ impl EmbeddedResourceLoader {
|
||||||
|
|
||||||
impl ResourceLoader for EmbeddedResourceLoader {
|
impl ResourceLoader for EmbeddedResourceLoader {
|
||||||
fn slurp(&self, virtual_path: &str) -> Result<Vec<u8>, IOError> {
|
fn slurp(&self, virtual_path: &str) -> Result<Vec<u8>, IOError> {
|
||||||
match RESOURCES.iter().filter(|&(path, _)| *path == virtual_path).next() {
|
match RESOURCES
|
||||||
|
.iter()
|
||||||
|
.filter(|&(path, _)| *path == virtual_path)
|
||||||
|
.next()
|
||||||
|
{
|
||||||
Some((_, data)) => Ok(data.to_vec()),
|
Some((_, data)) => Ok(data.to_vec()),
|
||||||
None => Err(IOError::from(ErrorKind::NotFound)),
|
None => Err(IOError::from(ErrorKind::NotFound)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
|
|
||||||
use std::arch::aarch64::{self, float32x2_t, float32x4_t, int32x2_t, int32x4_t};
|
use std::arch::aarch64::{self, float32x2_t, float32x4_t, int32x2_t, int32x4_t};
|
||||||
use std::arch::aarch64::{uint32x2_t, uint32x4_t};
|
use std::arch::aarch64::{uint32x2_t, uint32x4_t};
|
||||||
use std::intrinsics::simd::*;
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
use std::intrinsics::simd::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Add, BitAnd, BitOr, Div, Index, IndexMut, Mul, Not, Shr, Sub};
|
use std::ops::{Add, BitAnd, BitOr, Div, Index, IndexMut, Mul, Not, Shr, Sub};
|
||||||
|
|
||||||
|
@ -201,7 +201,6 @@ impl IndexMut<usize> for F32x2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Add<F32x2> for F32x2 {
|
impl Add<F32x2> for F32x2 {
|
||||||
type Output = F32x2;
|
type Output = F32x2;
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -832,7 +831,6 @@ impl BitOr<U32x2> for U32x2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Four 32-bit unsigned integers
|
// Four 32-bit unsigned integers
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
|
@ -49,7 +49,10 @@ impl F32x2 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn approx_eq(self, other: F32x2, epsilon: f32) -> bool {
|
pub fn approx_eq(self, other: F32x2, epsilon: f32) -> bool {
|
||||||
(self - other).abs().packed_gt(F32x2::splat(epsilon)).all_false()
|
(self - other)
|
||||||
|
.abs()
|
||||||
|
.packed_gt(F32x2::splat(epsilon))
|
||||||
|
.all_false()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +143,10 @@ impl F32x4 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn approx_eq(self, other: F32x4, epsilon: f32) -> bool {
|
pub fn approx_eq(self, other: F32x4, epsilon: f32) -> bool {
|
||||||
(self - other).abs().packed_gt(F32x4::splat(epsilon)).all_false()
|
(self - other)
|
||||||
|
.abs()
|
||||||
|
.packed_gt(F32x4::splat(epsilon))
|
||||||
|
.all_false()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::ops::{Add, BitAnd, BitOr, Div, Index, IndexMut, Mul, Shr, Sub, Not};
|
use std::ops::{Add, BitAnd, BitOr, Div, Index, IndexMut, Mul, Not, Shr, Sub};
|
||||||
|
|
||||||
mod swizzle_f32x4;
|
mod swizzle_f32x4;
|
||||||
mod swizzle_i32x4;
|
mod swizzle_i32x4;
|
||||||
|
@ -485,18 +485,12 @@ impl I32x2 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min(self, other: I32x2) -> I32x2 {
|
pub fn min(self, other: I32x2) -> I32x2 {
|
||||||
I32x2([
|
I32x2([self[0].min(other[0]), self[1].min(other[1])])
|
||||||
self[0].min(other[0]),
|
|
||||||
self[1].min(other[1]),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn max(self, other: I32x2) -> I32x2 {
|
pub fn max(self, other: I32x2) -> I32x2 {
|
||||||
I32x2([
|
I32x2([self[0].max(other[0]), self[1].max(other[1])])
|
||||||
self[0].max(other[0]),
|
|
||||||
self[1].max(other[1]),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packed comparisons
|
// Packed comparisons
|
||||||
|
@ -715,7 +709,12 @@ impl I32x4 {
|
||||||
/// FIXME(pcwalton): Should they? This will assert on overflow in debug.
|
/// FIXME(pcwalton): Should they? This will assert on overflow in debug.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_u32x4(self) -> U32x4 {
|
pub fn to_u32x4(self) -> U32x4 {
|
||||||
U32x4([self[0] as u32, self[1] as u32, self[2] as u32, self[3] as u32])
|
U32x4([
|
||||||
|
self[0] as u32,
|
||||||
|
self[1] as u32,
|
||||||
|
self[2] as u32,
|
||||||
|
self[3] as u32,
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,7 +776,12 @@ impl BitAnd<I32x4> for I32x4 {
|
||||||
type Output = I32x4;
|
type Output = I32x4;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bitand(self, other: I32x4) -> I32x4 {
|
fn bitand(self, other: I32x4) -> I32x4 {
|
||||||
I32x4([self[0] & other[0], self[1] & other[1], self[2] & other[2], self[3] & other[3]])
|
I32x4([
|
||||||
|
self[0] & other[0],
|
||||||
|
self[1] & other[1],
|
||||||
|
self[2] & other[2],
|
||||||
|
self[3] & other[3],
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,7 +789,12 @@ impl BitOr<I32x4> for I32x4 {
|
||||||
type Output = I32x4;
|
type Output = I32x4;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bitor(self, other: I32x4) -> I32x4 {
|
fn bitor(self, other: I32x4) -> I32x4 {
|
||||||
I32x4([self[0] | other[0], self[1] | other[1], self[2] | other[2], self[3] | other[3]])
|
I32x4([
|
||||||
|
self[0] | other[0],
|
||||||
|
self[1] | other[1],
|
||||||
|
self[2] | other[2],
|
||||||
|
self[3] | other[3],
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,7 +849,6 @@ impl U32x2 {
|
||||||
pub fn to_i32x2(self) -> I32x2 {
|
pub fn to_i32x2(self) -> I32x2 {
|
||||||
I32x2::new(self[0] as i32, self[1] as i32)
|
I32x2::new(self[0] as i32, self[1] as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitAnd<U32x2> for U32x2 {
|
impl BitAnd<U32x2> for U32x2 {
|
||||||
|
@ -894,7 +902,12 @@ impl U32x4 {
|
||||||
/// FIXME(pcwalton): Should they? This will assert on overflow in debug.
|
/// FIXME(pcwalton): Should they? This will assert on overflow in debug.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_i32x4(self) -> I32x4 {
|
pub fn to_i32x4(self) -> I32x4 {
|
||||||
I32x4([self[0] as i32, self[1] as i32, self[2] as i32, self[3] as i32])
|
I32x4([
|
||||||
|
self[0] as i32,
|
||||||
|
self[1] as i32,
|
||||||
|
self[2] as i32,
|
||||||
|
self[3] as i32,
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic operations
|
// Basic operations
|
||||||
|
@ -930,6 +943,11 @@ impl Shr<u32> for U32x4 {
|
||||||
type Output = U32x4;
|
type Output = U32x4;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn shr(self, amount: u32) -> U32x4 {
|
fn shr(self, amount: u32) -> U32x4 {
|
||||||
U32x4([self[0] >> amount, self[1] >> amount, self[2] >> amount, self[3] >> amount])
|
U32x4([
|
||||||
|
self[0] >> amount,
|
||||||
|
self[1] >> amount,
|
||||||
|
self[2] >> amount,
|
||||||
|
self[3] >> amount,
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,10 @@ fn test_f32x4_accessors_and_mutators() {
|
||||||
fn test_f32x4_basic_ops() {
|
fn test_f32x4_basic_ops() {
|
||||||
let a = F32x4::new(1.0, 3.0, 5.0, 7.0);
|
let a = F32x4::new(1.0, 3.0, 5.0, 7.0);
|
||||||
let b = F32x4::new(2.0, 2.0, 6.0, 6.0);
|
let b = F32x4::new(2.0, 2.0, 6.0, 6.0);
|
||||||
assert_eq!(a.approx_recip(), F32x4::new(0.99975586, 0.333313, 0.19995117, 0.14282227));
|
assert_eq!(
|
||||||
|
a.approx_recip(),
|
||||||
|
F32x4::new(0.99975586, 0.333313, 0.19995117, 0.14282227)
|
||||||
|
);
|
||||||
assert_eq!(a.min(b), F32x4::new(1.0, 2.0, 5.0, 6.0));
|
assert_eq!(a.min(b), F32x4::new(1.0, 2.0, 5.0, 6.0));
|
||||||
assert_eq!(a.max(b), F32x4::new(2.0, 3.0, 6.0, 7.0));
|
assert_eq!(a.max(b), F32x4::new(2.0, 3.0, 6.0, 7.0));
|
||||||
let c = F32x4::new(-1.0, 1.3, -20.0, 3.6);
|
let c = F32x4::new(-1.0, 1.3, -20.0, 3.6);
|
||||||
|
|
|
@ -13,14 +13,14 @@ use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Index, IndexMut, Mul, Not, Shr, Sub};
|
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Index, IndexMut, Mul, Not, Shr, Sub};
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
use std::arch::x86::{__m128, __m128i};
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
use std::arch::x86;
|
use std::arch::x86;
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
use std::arch::x86_64::{__m128, __m128i};
|
use std::arch::x86::{__m128, __m128i};
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
use std::arch::x86_64 as x86;
|
use std::arch::x86_64 as x86;
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
use std::arch::x86_64::{__m128, __m128i};
|
||||||
|
|
||||||
mod swizzle_f32x4;
|
mod swizzle_f32x4;
|
||||||
mod swizzle_i32x4;
|
mod swizzle_i32x4;
|
||||||
|
@ -285,20 +285,12 @@ impl F32x4 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn packed_eq(self, other: F32x4) -> U32x4 {
|
pub fn packed_eq(self, other: F32x4) -> U32x4 {
|
||||||
unsafe {
|
unsafe { U32x4(x86::_mm_castps_si128(x86::_mm_cmpeq_ps(self.0, other.0))) }
|
||||||
U32x4(x86::_mm_castps_si128(x86::_mm_cmpeq_ps(
|
|
||||||
self.0, other.0,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn packed_gt(self, other: F32x4) -> U32x4 {
|
pub fn packed_gt(self, other: F32x4) -> U32x4 {
|
||||||
unsafe {
|
unsafe { U32x4(x86::_mm_castps_si128(x86::_mm_cmpgt_ps(self.0, other.0))) }
|
||||||
U32x4(x86::_mm_castps_si128(x86::_mm_cmpgt_ps(
|
|
||||||
self.0, other.0,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@ keywords = ["pathfinder", "svg", "vector", "graphics", "gpu"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
hashbrown = "0.7"
|
hashbrown = "0.7"
|
||||||
usvg = "0.9"
|
usvg = "0.10.0"
|
||||||
|
|
||||||
[dependencies.pathfinder_color]
|
[dependencies.pathfinder_color]
|
||||||
path = "../color"
|
path = "../color"
|
||||||
|
|
131
svg/src/lib.rs
131
svg/src/lib.rs
|
@ -25,7 +25,7 @@ use pathfinder_content::transform::Transform2FPathIter;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
use pathfinder_renderer::paint::Paint;
|
use pathfinder_renderer::paint::Paint;
|
||||||
use pathfinder_renderer::scene::{ClipPath, ClipPathId, DrawPath, Scene};
|
use pathfinder_renderer::scene::{ClipPath, ClipPathId, DrawPath, Scene};
|
||||||
use pathfinder_simd::default::F32x2;
|
use pathfinder_simd::default::F32x2;
|
||||||
|
@ -80,7 +80,9 @@ impl SVGScene {
|
||||||
let root = &tree.root();
|
let root = &tree.root();
|
||||||
match *root.borrow() {
|
match *root.borrow() {
|
||||||
NodeKind::Svg(ref svg) => {
|
NodeKind::Svg(ref svg) => {
|
||||||
built_svg.scene.set_view_box(usvg_rect_to_euclid_rect(&svg.view_box.rect));
|
built_svg
|
||||||
|
.scene
|
||||||
|
.set_view_box(usvg_rect_to_euclid_rect(&svg.view_box.rect));
|
||||||
for kid in root.children() {
|
for kid in root.children() {
|
||||||
built_svg.process_node(&kid, &State::new(), &mut None);
|
built_svg.process_node(&kid, &State::new(), &mut None);
|
||||||
}
|
}
|
||||||
|
@ -91,24 +93,24 @@ impl SVGScene {
|
||||||
built_svg
|
built_svg
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_node(&mut self,
|
fn process_node(&mut self, node: &Node, state: &State, clip_outline: &mut Option<Outline>) {
|
||||||
node: &Node,
|
|
||||||
state: &State,
|
|
||||||
clip_outline: &mut Option<Outline>) {
|
|
||||||
let mut state = (*state).clone();
|
let mut state = (*state).clone();
|
||||||
let node_transform = usvg_transform_to_transform_2d(&node.transform());
|
let node_transform = usvg_transform_to_transform_2d(&node.transform());
|
||||||
state.transform = state.transform * node_transform;
|
state.transform = state.transform * node_transform;
|
||||||
match *node.borrow() {
|
match *node.borrow() {
|
||||||
NodeKind::Group(ref group) => {
|
NodeKind::Group(ref group) => {
|
||||||
if group.filter.is_some() {
|
if group.filter.is_some() {
|
||||||
self.result_flags.insert(BuildResultFlags::UNSUPPORTED_FILTER_ATTR);
|
self.result_flags
|
||||||
|
.insert(BuildResultFlags::UNSUPPORTED_FILTER_ATTR);
|
||||||
}
|
}
|
||||||
if group.mask.is_some() {
|
if group.mask.is_some() {
|
||||||
self.result_flags.insert(BuildResultFlags::UNSUPPORTED_MASK_ATTR);
|
self.result_flags
|
||||||
|
.insert(BuildResultFlags::UNSUPPORTED_MASK_ATTR);
|
||||||
}
|
}
|
||||||
if let Some(ref clip_path_name) = group.clip_path {
|
if let Some(ref clip_path_name) = group.clip_path {
|
||||||
if let Some(clip_outline) = self.clip_paths.get(clip_path_name) {
|
if let Some(clip_outline) = self.clip_paths.get(clip_path_name) {
|
||||||
let transformed_outline = clip_outline.clone().transformed(&state.transform);
|
let transformed_outline =
|
||||||
|
clip_outline.clone().transformed(&state.transform);
|
||||||
let mut clip_path = ClipPath::new(transformed_outline);
|
let mut clip_path = ClipPath::new(transformed_outline);
|
||||||
clip_path.set_clip_path(state.clip_path);
|
clip_path.set_clip_path(state.clip_path);
|
||||||
clip_path.set_name(format!("ClipPath({})", clip_path_name));
|
clip_path.set_name(format!("ClipPath({})", clip_path_name));
|
||||||
|
@ -126,31 +128,38 @@ impl SVGScene {
|
||||||
let path = UsvgPathToSegments::new(path.data.iter().cloned());
|
let path = UsvgPathToSegments::new(path.data.iter().cloned());
|
||||||
let path = Transform2FPathIter::new(path, &state.transform);
|
let path = Transform2FPathIter::new(path, &state.transform);
|
||||||
if clip_outline.is_some() {
|
if clip_outline.is_some() {
|
||||||
self.result_flags.insert(BuildResultFlags::UNSUPPORTED_MULTIPLE_CLIP_PATHS);
|
self.result_flags
|
||||||
|
.insert(BuildResultFlags::UNSUPPORTED_MULTIPLE_CLIP_PATHS);
|
||||||
}
|
}
|
||||||
*clip_outline = Some(Outline::from_segments(path));
|
*clip_outline = Some(Outline::from_segments(path));
|
||||||
}
|
}
|
||||||
NodeKind::Path(ref path) if state.path_destination == PathDestination::Draw &&
|
NodeKind::Path(ref path)
|
||||||
path.visibility == Visibility::Visible => {
|
if state.path_destination == PathDestination::Draw
|
||||||
|
&& path.visibility == Visibility::Visible =>
|
||||||
|
{
|
||||||
if let Some(ref fill) = path.fill {
|
if let Some(ref fill) = path.fill {
|
||||||
let path = UsvgPathToSegments::new(path.data.iter().cloned());
|
let path = UsvgPathToSegments::new(path.data.iter().cloned());
|
||||||
let outline = Outline::from_segments(path);
|
let outline = Outline::from_segments(path);
|
||||||
|
|
||||||
let name = format!("Fill({})", node.id());
|
let name = format!("Fill({})", node.id());
|
||||||
self.push_draw_path(outline,
|
self.push_draw_path(
|
||||||
|
outline,
|
||||||
name,
|
name,
|
||||||
&state,
|
&state,
|
||||||
&fill.paint,
|
&fill.paint,
|
||||||
fill.opacity,
|
fill.opacity,
|
||||||
fill.rule);
|
fill.rule,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref stroke) = path.stroke {
|
if let Some(ref stroke) = path.stroke {
|
||||||
let stroke_style = StrokeStyle {
|
let stroke_style = StrokeStyle {
|
||||||
line_width: f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH),
|
line_width: f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH),
|
||||||
line_cap: LineCap::from_usvg_line_cap(stroke.linecap),
|
line_cap: LineCap::from_usvg_line_cap(stroke.linecap),
|
||||||
line_join: LineJoin::from_usvg_line_join(stroke.linejoin,
|
line_join: LineJoin::from_usvg_line_join(
|
||||||
stroke.miterlimit.value() as f32),
|
stroke.linejoin,
|
||||||
|
stroke.miterlimit.value() as f32,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = UsvgPathToSegments::new(path.data.iter().cloned());
|
let path = UsvgPathToSegments::new(path.data.iter().cloned());
|
||||||
|
@ -168,12 +177,14 @@ impl SVGScene {
|
||||||
let outline = stroke_to_fill.into_outline();
|
let outline = stroke_to_fill.into_outline();
|
||||||
|
|
||||||
let name = format!("Stroke({})", node.id());
|
let name = format!("Stroke({})", node.id());
|
||||||
self.push_draw_path(outline,
|
self.push_draw_path(
|
||||||
|
outline,
|
||||||
name,
|
name,
|
||||||
&state,
|
&state,
|
||||||
&stroke.paint,
|
&stroke.paint,
|
||||||
stroke.opacity,
|
stroke.opacity,
|
||||||
UsvgFillRule::NonZero);
|
UsvgFillRule::NonZero,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeKind::Path(..) => {}
|
NodeKind::Path(..) => {}
|
||||||
|
@ -184,7 +195,8 @@ impl SVGScene {
|
||||||
self.process_node(&kid, &state, &mut clip_outline);
|
self.process_node(&kid, &state, &mut clip_outline);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.clip_paths.insert(node.id().to_owned(), clip_outline.unwrap());
|
self.clip_paths
|
||||||
|
.insert(node.id().to_owned(), clip_outline.unwrap());
|
||||||
}
|
}
|
||||||
NodeKind::Defs => {
|
NodeKind::Defs => {
|
||||||
// FIXME(pcwalton): This is wrong.
|
// FIXME(pcwalton): This is wrong.
|
||||||
|
@ -197,18 +209,22 @@ impl SVGScene {
|
||||||
let from = vec2f(svg_linear_gradient.x1 as f32, svg_linear_gradient.y1 as f32);
|
let from = vec2f(svg_linear_gradient.x1 as f32, svg_linear_gradient.y1 as f32);
|
||||||
let to = vec2f(svg_linear_gradient.x2 as f32, svg_linear_gradient.y2 as f32);
|
let to = vec2f(svg_linear_gradient.x2 as f32, svg_linear_gradient.y2 as f32);
|
||||||
let gradient = Gradient::linear_from_points(from, to);
|
let gradient = Gradient::linear_from_points(from, to);
|
||||||
self.add_gradient(gradient,
|
self.add_gradient(
|
||||||
|
gradient,
|
||||||
svg_linear_gradient.id.clone(),
|
svg_linear_gradient.id.clone(),
|
||||||
&svg_linear_gradient.base)
|
&svg_linear_gradient.base,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
NodeKind::RadialGradient(ref svg_radial_gradient) => {
|
NodeKind::RadialGradient(ref svg_radial_gradient) => {
|
||||||
let from = vec2f(svg_radial_gradient.fx as f32, svg_radial_gradient.fy as f32);
|
let from = vec2f(svg_radial_gradient.fx as f32, svg_radial_gradient.fy as f32);
|
||||||
let to = vec2f(svg_radial_gradient.cx as f32, svg_radial_gradient.cy as f32);
|
let to = vec2f(svg_radial_gradient.cx as f32, svg_radial_gradient.cy as f32);
|
||||||
let radii = F32x2::new(0.0, svg_radial_gradient.r.value() as f32);
|
let radii = F32x2::new(0.0, svg_radial_gradient.r.value() as f32);
|
||||||
let gradient = Gradient::radial(LineSegment2F::new(from, to), radii);
|
let gradient = Gradient::radial(LineSegment2F::new(from, to), radii);
|
||||||
self.add_gradient(gradient,
|
self.add_gradient(
|
||||||
|
gradient,
|
||||||
svg_radial_gradient.id.clone(),
|
svg_radial_gradient.id.clone(),
|
||||||
&svg_radial_gradient.base)
|
&svg_radial_gradient.base,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
NodeKind::Filter(..) => {
|
NodeKind::Filter(..) => {
|
||||||
self.result_flags
|
self.result_flags
|
||||||
|
@ -230,10 +246,12 @@ impl SVGScene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_gradient(&mut self,
|
fn add_gradient(
|
||||||
|
&mut self,
|
||||||
mut gradient: Gradient,
|
mut gradient: Gradient,
|
||||||
id: String,
|
id: String,
|
||||||
usvg_base_gradient: &BaseGradient) {
|
usvg_base_gradient: &BaseGradient,
|
||||||
|
) {
|
||||||
for stop in &usvg_base_gradient.stops {
|
for stop in &usvg_base_gradient.stops {
|
||||||
let mut stop = ColorStop::from_usvg_stop(stop);
|
let mut stop = ColorStop::from_usvg_stop(stop);
|
||||||
if usvg_base_gradient.spread_method == SpreadMethod::Reflect {
|
if usvg_base_gradient.spread_method == SpreadMethod::Reflect {
|
||||||
|
@ -261,22 +279,32 @@ impl SVGScene {
|
||||||
let transform = usvg_transform_to_transform_2d(&usvg_base_gradient.transform);
|
let transform = usvg_transform_to_transform_2d(&usvg_base_gradient.transform);
|
||||||
|
|
||||||
// TODO(pcwalton): What should we do with `gradientUnits`?
|
// TODO(pcwalton): What should we do with `gradientUnits`?
|
||||||
self.gradients.insert(id, GradientInfo { gradient, transform });
|
self.gradients.insert(
|
||||||
|
id,
|
||||||
|
GradientInfo {
|
||||||
|
gradient,
|
||||||
|
transform,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_draw_path(&mut self,
|
fn push_draw_path(
|
||||||
|
&mut self,
|
||||||
mut outline: Outline,
|
mut outline: Outline,
|
||||||
name: String,
|
name: String,
|
||||||
state: &State,
|
state: &State,
|
||||||
paint: &UsvgPaint,
|
paint: &UsvgPaint,
|
||||||
opacity: Opacity,
|
opacity: Opacity,
|
||||||
fill_rule: UsvgFillRule) {
|
fill_rule: UsvgFillRule,
|
||||||
|
) {
|
||||||
outline.transform(&state.transform);
|
outline.transform(&state.transform);
|
||||||
let paint = Paint::from_svg_paint(paint,
|
let paint = Paint::from_svg_paint(
|
||||||
|
paint,
|
||||||
&state.transform,
|
&state.transform,
|
||||||
opacity,
|
opacity,
|
||||||
&self.gradients,
|
&self.gradients,
|
||||||
&mut self.result_flags);
|
&mut self.result_flags,
|
||||||
|
);
|
||||||
let style = self.scene.push_paint(&paint);
|
let style = self.scene.push_paint(&paint);
|
||||||
let fill_rule = FillRule::from_usvg_fill_rule(fill_rule);
|
let fill_rule = FillRule::from_usvg_fill_rule(fill_rule);
|
||||||
let mut path = DrawPath::new(outline, style);
|
let mut path = DrawPath::new(outline, style);
|
||||||
|
@ -323,22 +351,24 @@ impl Display for BuildResultFlags {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PaintExt {
|
trait PaintExt {
|
||||||
fn from_svg_paint(svg_paint: &UsvgPaint,
|
fn from_svg_paint(
|
||||||
|
svg_paint: &UsvgPaint,
|
||||||
transform: &Transform2F,
|
transform: &Transform2F,
|
||||||
opacity: Opacity,
|
opacity: Opacity,
|
||||||
gradients: &HashMap<String, GradientInfo>,
|
gradients: &HashMap<String, GradientInfo>,
|
||||||
result_flags: &mut BuildResultFlags)
|
result_flags: &mut BuildResultFlags,
|
||||||
-> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PaintExt for Paint {
|
impl PaintExt for Paint {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_svg_paint(svg_paint: &UsvgPaint,
|
fn from_svg_paint(
|
||||||
|
svg_paint: &UsvgPaint,
|
||||||
transform: &Transform2F,
|
transform: &Transform2F,
|
||||||
opacity: Opacity,
|
opacity: Opacity,
|
||||||
gradients: &HashMap<String, GradientInfo>,
|
gradients: &HashMap<String, GradientInfo>,
|
||||||
result_flags: &mut BuildResultFlags)
|
result_flags: &mut BuildResultFlags,
|
||||||
-> Paint {
|
) -> Paint {
|
||||||
let mut paint;
|
let mut paint;
|
||||||
match *svg_paint {
|
match *svg_paint {
|
||||||
UsvgPaint::Color(color) => paint = Paint::from_color(ColorU::from_svg_color(color)),
|
UsvgPaint::Color(color) => paint = Paint::from_color(ColorU::from_svg_color(color)),
|
||||||
|
@ -366,13 +396,21 @@ impl PaintExt for Paint {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> RectF {
|
fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> RectF {
|
||||||
RectF::new(vec2f(rect.x() as f32, rect.y() as f32),
|
RectF::new(
|
||||||
vec2f(rect.width() as f32, rect.height() as f32))
|
vec2f(rect.x() as f32, rect.y() as f32),
|
||||||
|
vec2f(rect.width() as f32, rect.height() as f32),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usvg_transform_to_transform_2d(transform: &UsvgTransform) -> Transform2F {
|
fn usvg_transform_to_transform_2d(transform: &UsvgTransform) -> Transform2F {
|
||||||
Transform2F::row_major(transform.a as f32, transform.c as f32, transform.e as f32,
|
Transform2F::row_major(
|
||||||
transform.b as f32, transform.d as f32, transform.f as f32)
|
transform.a as f32,
|
||||||
|
transform.c as f32,
|
||||||
|
transform.e as f32,
|
||||||
|
transform.b as f32,
|
||||||
|
transform.d as f32,
|
||||||
|
transform.f as f32,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UsvgPathToSegments<I>
|
struct UsvgPathToSegments<I>
|
||||||
|
@ -435,8 +473,10 @@ where
|
||||||
let ctrl0 = vec2f(x1 as f32, y1 as f32);
|
let ctrl0 = vec2f(x1 as f32, y1 as f32);
|
||||||
let ctrl1 = vec2f(x2 as f32, y2 as f32);
|
let ctrl1 = vec2f(x2 as f32, y2 as f32);
|
||||||
let to = vec2f(x as f32, y as f32);
|
let to = vec2f(x as f32, y as f32);
|
||||||
let mut segment = Segment::cubic(LineSegment2F::new(self.last_subpath_point, to),
|
let mut segment = Segment::cubic(
|
||||||
LineSegment2F::new(ctrl0, ctrl1));
|
LineSegment2F::new(self.last_subpath_point, to),
|
||||||
|
LineSegment2F::new(ctrl0, ctrl1),
|
||||||
|
);
|
||||||
if self.just_moved {
|
if self.just_moved {
|
||||||
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
|
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
|
||||||
}
|
}
|
||||||
|
@ -465,7 +505,12 @@ trait ColorUExt {
|
||||||
impl ColorUExt for ColorU {
|
impl ColorUExt for ColorU {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_svg_color(svg_color: SvgColor) -> ColorU {
|
fn from_svg_color(svg_color: SvgColor) -> ColorU {
|
||||||
ColorU { r: svg_color.red, g: svg_color.green, b: svg_color.blue, a: !0 }
|
ColorU {
|
||||||
|
r: svg_color.red,
|
||||||
|
g: svg_color.green,
|
||||||
|
b: svg_color.blue,
|
||||||
|
a: !0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,16 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::ops::Add;
|
|
||||||
use pathfinder_color::{ColorF, ColorU};
|
use pathfinder_color::{ColorF, ColorU};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::{Outline, Contour};
|
use pathfinder_content::outline::{Contour, Outline};
|
||||||
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||||
use pathfinder_geometry::vector::vec2f;
|
use pathfinder_geometry::vector::vec2f;
|
||||||
use pathfinder_renderer::scene::{DrawPath, Scene};
|
use pathfinder_renderer::scene::{DrawPath, Scene};
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
use swf_types::tags::SetBackgroundColor;
|
use swf_types::tags::SetBackgroundColor;
|
||||||
use swf_types::{Tag, SRgb8, Movie};
|
use swf_types::{Movie, SRgb8, Tag};
|
||||||
|
|
||||||
use crate::shapes::{GraphicLayers, PaintOrLine};
|
use crate::shapes::{GraphicLayers, PaintOrLine};
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ impl Add for Twips {
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
struct Point2<T> {
|
struct Point2<T> {
|
||||||
x: T,
|
x: T,
|
||||||
y: T
|
y: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Point2<Twips> {
|
impl Point2<Twips> {
|
||||||
|
@ -66,7 +66,10 @@ impl Point2<Twips> {
|
||||||
impl Add for Point2<Twips> {
|
impl Add for Point2<Twips> {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
fn add(self, rhs: Self) -> Self {
|
fn add(self, rhs: Self) -> Self {
|
||||||
Point2 { x: self.x + rhs.x, y: self.y + rhs.y }
|
Point2 {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,11 +101,11 @@ impl Stage {
|
||||||
g: self.background_color.g,
|
g: self.background_color.g,
|
||||||
b: self.background_color.b,
|
b: self.background_color.b,
|
||||||
a: 255,
|
a: 255,
|
||||||
}.to_f32()
|
}
|
||||||
|
.to_f32()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct SymbolLibrary(Vec<Symbol>);
|
pub struct SymbolLibrary(Vec<Symbol>);
|
||||||
|
|
||||||
impl SymbolLibrary {
|
impl SymbolLibrary {
|
||||||
|
@ -126,7 +129,7 @@ pub fn process_swf_tags(movie: &Movie) -> (SymbolLibrary, Stage) {
|
||||||
background_color: SRgb8 {
|
background_color: SRgb8 {
|
||||||
r: 255,
|
r: 255,
|
||||||
g: 255,
|
g: 255,
|
||||||
b: 255
|
b: 255,
|
||||||
},
|
},
|
||||||
width: stage_width.as_f32() as i32,
|
width: stage_width.as_f32() as i32,
|
||||||
height: stage_height.as_f32() as i32,
|
height: stage_height.as_f32() as i32,
|
||||||
|
@ -136,14 +139,14 @@ pub fn process_swf_tags(movie: &Movie) -> (SymbolLibrary, Stage) {
|
||||||
match tag {
|
match tag {
|
||||||
Tag::SetBackgroundColor(SetBackgroundColor { color }) => {
|
Tag::SetBackgroundColor(SetBackgroundColor { color }) => {
|
||||||
stage.background_color = *color;
|
stage.background_color = *color;
|
||||||
},
|
}
|
||||||
Tag::DefineShape(shape) => {
|
Tag::DefineShape(shape) => {
|
||||||
symbol_library.add_symbol(Symbol::Graphic(shapes::decode_shape(shape)));
|
symbol_library.add_symbol(Symbol::Graphic(shapes::decode_shape(shape)));
|
||||||
// We will assume that symbol ids just go up, and are 1 based.
|
// We will assume that symbol ids just go up, and are 1 based.
|
||||||
let symbol_id: SymbolId = shape.id;
|
let symbol_id: SymbolId = shape.id;
|
||||||
debug_assert!(symbol_id as usize == symbol_library.0.len());
|
debug_assert!(symbol_id as usize == symbol_library.0.len());
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(symbol_library, stage)
|
(symbol_library, stage)
|
||||||
|
@ -166,12 +169,15 @@ pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) {
|
||||||
let Point2 { x, y } = segment.to.as_f32();
|
let Point2 { x, y } = segment.to.as_f32();
|
||||||
match segment.ctrl {
|
match segment.ctrl {
|
||||||
Some(ctrl) => {
|
Some(ctrl) => {
|
||||||
let Point2 { x: ctrl_x, y: ctrl_y } = ctrl.as_f32();
|
let Point2 {
|
||||||
|
x: ctrl_x,
|
||||||
|
y: ctrl_y,
|
||||||
|
} = ctrl.as_f32();
|
||||||
contour.push_quadratic(vec2f(ctrl_x, ctrl_y), vec2f(x, y));
|
contour.push_quadratic(vec2f(ctrl_x, ctrl_y), vec2f(x, y));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
contour.push_endpoint(vec2f(x, y));
|
contour.push_endpoint(vec2f(x, y));
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if shape.is_closed() {
|
if shape.is_closed() {
|
||||||
|
@ -183,11 +189,14 @@ pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let PaintOrLine::Line(line) = style_layer.kind() {
|
if let PaintOrLine::Line(line) = style_layer.kind() {
|
||||||
let mut stroke_to_fill = OutlineStrokeToFill::new(&path, StrokeStyle {
|
let mut stroke_to_fill = OutlineStrokeToFill::new(
|
||||||
|
&path,
|
||||||
|
StrokeStyle {
|
||||||
line_width: line.width.as_f32(),
|
line_width: line.width.as_f32(),
|
||||||
line_cap: line.cap,
|
line_cap: line.cap,
|
||||||
line_join: line.join,
|
line_join: line.join,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
stroke_to_fill.offset();
|
stroke_to_fill.offset();
|
||||||
path = stroke_to_fill.into_outline();
|
path = stroke_to_fill.into_outline();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,16 +8,16 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::{Twips, Point2};
|
use crate::{Point2, Twips};
|
||||||
|
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_content::stroke::{LineJoin, LineCap};
|
use pathfinder_content::stroke::{LineCap, LineJoin};
|
||||||
use pathfinder_renderer::paint::Paint;
|
use pathfinder_renderer::paint::Paint;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use swf_types::tags::DefineShape;
|
use swf_types::tags::DefineShape;
|
||||||
use swf_types::{CapStyle, FillStyle, JoinStyle, LineStyle, ShapeRecord, StraightSRgba8, Vector2D};
|
|
||||||
use swf_types::{fill_styles, join_styles, shape_records};
|
use swf_types::{fill_styles, join_styles, shape_records};
|
||||||
|
use swf_types::{CapStyle, FillStyle, JoinStyle, LineStyle, ShapeRecord, StraightSRgba8, Vector2D};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub(crate) struct LineSegment {
|
pub(crate) struct LineSegment {
|
||||||
|
@ -44,7 +44,7 @@ impl LineDirection {
|
||||||
fn reverse(&mut self) {
|
fn reverse(&mut self) {
|
||||||
*self = match self {
|
*self = match self {
|
||||||
LineDirection::Right => LineDirection::Left,
|
LineDirection::Right => LineDirection::Left,
|
||||||
LineDirection::Left => LineDirection::Right
|
LineDirection::Left => LineDirection::Right,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,19 +194,16 @@ impl StyleLayer {
|
||||||
if self.is_fill() {
|
if self.is_fill() {
|
||||||
// I think sorting is only necessary when we want to have closed shapes,
|
// I think sorting is only necessary when we want to have closed shapes,
|
||||||
// lines don't really need this?
|
// lines don't really need this?
|
||||||
self.shapes.sort_unstable_by(|a, b| {
|
self.shapes
|
||||||
match (a.is_closed(), b.is_closed()) {
|
.sort_unstable_by(|a, b| match (a.is_closed(), b.is_closed()) {
|
||||||
(true, true) | (false, false) => Ordering::Equal,
|
(true, true) | (false, false) => Ordering::Equal,
|
||||||
(true, false) => Ordering::Less,
|
(true, false) => Ordering::Less,
|
||||||
(false, true) => Ordering::Greater,
|
(false, true) => Ordering::Greater,
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// A cursor at the index of the first unclosed shape, if any.
|
// A cursor at the index of the first unclosed shape, if any.
|
||||||
let first_open_index = self.shapes
|
let first_open_index = self.shapes.iter().position(|frag| !frag.is_closed());
|
||||||
.iter()
|
|
||||||
.position(|frag| !frag.is_closed());
|
|
||||||
|
|
||||||
if let Some(first_open_index) = first_open_index {
|
if let Some(first_open_index) = first_open_index {
|
||||||
if self.shapes.len() - first_open_index >= 2 {
|
if self.shapes.len() - first_open_index >= 2 {
|
||||||
|
@ -235,31 +232,27 @@ impl StyleLayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_new_styles<'a>(
|
fn get_new_styles<'a>(
|
||||||
fills: &'a Vec<FillStyle>,
|
fills: &'a Vec<FillStyle>,
|
||||||
lines: &'a Vec<LineStyle>
|
lines: &'a Vec<LineStyle>,
|
||||||
) -> impl Iterator<Item = PaintOrLine> + 'a {
|
) -> impl Iterator<Item = PaintOrLine> + 'a {
|
||||||
// This enforces the order that fills and line groupings are added in.
|
// This enforces the order that fills and line groupings are added in.
|
||||||
// Fills always come first.
|
// Fills always come first.
|
||||||
fills.iter().filter_map(|fill_style| {
|
fills
|
||||||
match fill_style {
|
.iter()
|
||||||
FillStyle::Solid(
|
.filter_map(|fill_style| match fill_style {
|
||||||
fill_styles::Solid {
|
FillStyle::Solid(fill_styles::Solid {
|
||||||
color: StraightSRgba8 {
|
color: StraightSRgba8 { r, g, b, a },
|
||||||
r,
|
}) => Some(PaintOrLine::Paint(Paint::from_color(ColorU {
|
||||||
g,
|
r: *r,
|
||||||
b,
|
g: *g,
|
||||||
a
|
b: *b,
|
||||||
}
|
a: *a,
|
||||||
}
|
}))),
|
||||||
) => {
|
_ => unimplemented!("Unimplemented fill style"),
|
||||||
Some(PaintOrLine::Paint(Paint::from_color(ColorU { r: *r, g: *g, b: *b, a: *a })))
|
})
|
||||||
}
|
.chain(lines.iter().filter_map(
|
||||||
_ => unimplemented!("Unimplemented fill style")
|
|LineStyle {
|
||||||
}
|
|
||||||
}).chain(
|
|
||||||
lines.iter().filter_map(|LineStyle {
|
|
||||||
width,
|
width,
|
||||||
fill,
|
fill,
|
||||||
join,
|
join,
|
||||||
|
@ -275,26 +268,27 @@ fn get_new_styles<'a>(
|
||||||
..
|
..
|
||||||
}| {
|
}| {
|
||||||
if let FillStyle::Solid(fill_styles::Solid {
|
if let FillStyle::Solid(fill_styles::Solid {
|
||||||
color: StraightSRgba8 {
|
color: StraightSRgba8 { r, g, b, a },
|
||||||
r,
|
}) = fill
|
||||||
g,
|
{
|
||||||
b,
|
|
||||||
a
|
|
||||||
}
|
|
||||||
}) = fill {
|
|
||||||
// NOTE: PathFinder doesn't support different cap styles for start and end of
|
// 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.
|
// 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.
|
// Alternately, we split a line in two with a diff cap style for each.
|
||||||
// assert_eq!(start_cap, end_cap);
|
// assert_eq!(start_cap, end_cap);
|
||||||
Some(PaintOrLine::Line(SwfLineStyle {
|
Some(PaintOrLine::Line(SwfLineStyle {
|
||||||
width: Twips(*width as i32),
|
width: Twips(*width as i32),
|
||||||
color: Paint::from_color(ColorU { r: *r, g: *g, b: *b, a: *a }),
|
color: Paint::from_color(ColorU {
|
||||||
|
r: *r,
|
||||||
|
g: *g,
|
||||||
|
b: *b,
|
||||||
|
a: *a,
|
||||||
|
}),
|
||||||
join: match join {
|
join: match join {
|
||||||
JoinStyle::Bevel => LineJoin::Bevel,
|
JoinStyle::Bevel => LineJoin::Bevel,
|
||||||
JoinStyle::Round => LineJoin::Round,
|
JoinStyle::Round => LineJoin::Round,
|
||||||
JoinStyle::Miter(join_styles::Miter { limit }) => {
|
JoinStyle::Miter(join_styles::Miter { limit }) => {
|
||||||
LineJoin::Miter(*limit as f32)
|
LineJoin::Miter(*limit as f32)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
cap: match start_cap {
|
cap: match start_cap {
|
||||||
CapStyle::None => LineCap::Butt,
|
CapStyle::None => LineCap::Butt,
|
||||||
|
@ -305,8 +299,8 @@ fn get_new_styles<'a>(
|
||||||
} else {
|
} else {
|
||||||
unimplemented!("unimplemented line fill style");
|
unimplemented!("unimplemented line fill style");
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
|
pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
|
||||||
|
@ -339,15 +333,13 @@ pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
|
||||||
|
|
||||||
for record in &shape.records {
|
for record in &shape.records {
|
||||||
match record {
|
match record {
|
||||||
ShapeRecord::StyleChange(
|
ShapeRecord::StyleChange(shape_records::StyleChange {
|
||||||
shape_records::StyleChange {
|
|
||||||
move_to,
|
move_to,
|
||||||
new_styles,
|
new_styles,
|
||||||
line_style,
|
line_style,
|
||||||
left_fill,
|
left_fill,
|
||||||
right_fill,
|
right_fill,
|
||||||
}
|
}) => {
|
||||||
) => {
|
|
||||||
// Start a whole new style grouping.
|
// Start a whole new style grouping.
|
||||||
if let Some(new_style) = new_styles {
|
if let Some(new_style) = new_styles {
|
||||||
// Consolidate current style grouping and begin a new one.
|
// Consolidate current style grouping and begin a new one.
|
||||||
|
@ -406,7 +398,10 @@ pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
|
||||||
|
|
||||||
// Move to, start new shape fragments with the current styles.
|
// Move to, start new shape fragments with the current styles.
|
||||||
if let Some(Vector2D { x, y }) = move_to {
|
if let Some(Vector2D { x, y }) = move_to {
|
||||||
let to: Point2<Twips> = Point2 { x: Twips(*x), y: Twips(*y) };
|
let to: Point2<Twips> = Point2 {
|
||||||
|
x: Twips(*x),
|
||||||
|
y: Twips(*y),
|
||||||
|
};
|
||||||
prev_pos = Some(to);
|
prev_pos = Some(to);
|
||||||
|
|
||||||
// If we didn't start a new shape for the current fill due to a fill
|
// If we didn't start a new shape for the current fill due to a fill
|
||||||
|
@ -433,34 +428,27 @@ pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
|
||||||
.push_new_shape(LineDirection::Right);
|
.push_new_shape(LineDirection::Right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ShapeRecord::Edge(
|
ShapeRecord::Edge(shape_records::Edge {
|
||||||
shape_records::Edge {
|
|
||||||
delta,
|
delta,
|
||||||
control_delta,
|
control_delta,
|
||||||
}
|
}) => {
|
||||||
) => {
|
|
||||||
let from = prev_pos.unwrap();
|
let from = prev_pos.unwrap();
|
||||||
let to = Point2 {
|
let to = Point2 {
|
||||||
x: from.x + Twips(delta.x),
|
x: from.x + Twips(delta.x),
|
||||||
y: from.y + Twips(delta.y)
|
y: from.y + Twips(delta.y),
|
||||||
};
|
};
|
||||||
prev_pos = Some(to);
|
prev_pos = Some(to);
|
||||||
let new_segment = LineSegment {
|
let new_segment = LineSegment {
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
ctrl: control_delta.map(|Vector2D { x, y }| {
|
ctrl: control_delta.map(|Vector2D { x, y }| Point2 {
|
||||||
Point2 {
|
|
||||||
x: from.x + Twips(x),
|
x: from.x + Twips(x),
|
||||||
y: from.y + Twips(y),
|
y: from.y + Twips(y),
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
if some_fill_set && !both_fills_same {
|
if some_fill_set && !both_fills_same {
|
||||||
for fill_id in [
|
for fill_id in [current_right_fill, current_left_fill].iter() {
|
||||||
current_right_fill,
|
|
||||||
current_left_fill
|
|
||||||
].iter() {
|
|
||||||
if let Some(fill_id) = fill_id {
|
if let Some(fill_id) = fill_id {
|
||||||
graphic
|
graphic
|
||||||
.with_fill_style_mut(*fill_id)
|
.with_fill_style_mut(*fill_id)
|
||||||
|
@ -472,8 +460,10 @@ pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
|
||||||
} else if both_fills_set_and_same {
|
} else if both_fills_set_and_same {
|
||||||
for (fill_id, direction) in [
|
for (fill_id, direction) in [
|
||||||
(current_right_fill, LineDirection::Right),
|
(current_right_fill, LineDirection::Right),
|
||||||
(current_left_fill, LineDirection::Left)
|
(current_left_fill, LineDirection::Left),
|
||||||
].iter() {
|
]
|
||||||
|
.iter()
|
||||||
|
{
|
||||||
// NOTE: If both left and right fill are set the same,
|
// NOTE: If both left and right fill are set the same,
|
||||||
// then we don't record the edge as part of the current shape;
|
// 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
|
// it's will just be an internal stroke inside an otherwise solid
|
||||||
|
@ -508,7 +498,7 @@ pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers {
|
||||||
fn find_matches(
|
fn find_matches(
|
||||||
mut first_open_index: usize,
|
mut first_open_index: usize,
|
||||||
shapes: &mut Vec<Shape>,
|
shapes: &mut Vec<Shape>,
|
||||||
reverse: bool
|
reverse: bool,
|
||||||
) -> Option<Vec<Shape>> {
|
) -> Option<Vec<Shape>> {
|
||||||
let mut dropped_pieces = None;
|
let mut dropped_pieces = None;
|
||||||
while first_open_index < shapes.len() {
|
while first_open_index < shapes.len() {
|
||||||
|
@ -563,7 +553,11 @@ pub(crate) struct GraphicLayers {
|
||||||
|
|
||||||
impl GraphicLayers {
|
impl GraphicLayers {
|
||||||
fn new() -> GraphicLayers {
|
fn new() -> GraphicLayers {
|
||||||
GraphicLayers { style_layers: Vec::new(), stroke_layer_offset: None, base_layer_offset: 0 }
|
GraphicLayers {
|
||||||
|
style_layers: Vec::new(),
|
||||||
|
stroke_layer_offset: None,
|
||||||
|
base_layer_offset: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin_style_group(&mut self) {
|
fn begin_style_group(&mut self) {
|
||||||
|
@ -572,22 +566,30 @@ impl GraphicLayers {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin_fill_style(&mut self, fill: Paint) {
|
fn begin_fill_style(&mut self, fill: Paint) {
|
||||||
self.style_layers.push(StyleLayer { fill: PaintOrLine::Paint(fill), shapes: Vec::new() })
|
self.style_layers.push(StyleLayer {
|
||||||
|
fill: PaintOrLine::Paint(fill),
|
||||||
|
shapes: Vec::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin_line_style(&mut self, line: SwfLineStyle) {
|
fn begin_line_style(&mut self, line: SwfLineStyle) {
|
||||||
if self.stroke_layer_offset.is_none() {
|
if self.stroke_layer_offset.is_none() {
|
||||||
self.stroke_layer_offset = Some(self.style_layers.len());
|
self.stroke_layer_offset = Some(self.style_layers.len());
|
||||||
}
|
}
|
||||||
self.style_layers.push(StyleLayer { fill: PaintOrLine::Line(line), shapes: Vec::new() })
|
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> {
|
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)
|
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> {
|
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)
|
self.style_layers
|
||||||
|
.get_mut((self.stroke_layer_offset.unwrap() + line_id) - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn layers(&self) -> &Vec<StyleLayer> {
|
pub(crate) fn layers(&self) -> &Vec<StyleLayer> {
|
||||||
|
@ -606,4 +608,3 @@ impl GraphicLayers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ repository = "https://github.com/servo/pathfinder"
|
||||||
homepage = "https://github.com/servo/pathfinder"
|
homepage = "https://github.com/servo/pathfinder"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
font-kit = "0.6"
|
font-kit = "0.13"
|
||||||
|
|
||||||
[dependencies.pathfinder_content]
|
[dependencies.pathfinder_content]
|
||||||
path = "../content"
|
path = "../content"
|
||||||
|
|
107
text/src/lib.rs
107
text/src/lib.rs
|
@ -19,7 +19,7 @@ use pathfinder_content::outline::{Contour, Outline};
|
||||||
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
use pathfinder_renderer::paint::PaintId;
|
use pathfinder_renderer::paint::PaintId;
|
||||||
use pathfinder_renderer::scene::{ClipPathId, DrawPath, Scene};
|
use pathfinder_renderer::scene::{ClipPathId, DrawPath, Scene};
|
||||||
use skribo::{FontCollection, Layout, TextStyle};
|
use skribo::{FontCollection, Layout, TextStyle};
|
||||||
|
@ -28,12 +28,18 @@ use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FontContext<F> where F: Loader {
|
pub struct FontContext<F>
|
||||||
|
where
|
||||||
|
F: Loader,
|
||||||
|
{
|
||||||
font_info: HashMap<String, FontInfo<F>>,
|
font_info: HashMap<String, FontInfo<F>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct FontInfo<F> where F: Loader {
|
struct FontInfo<F>
|
||||||
|
where
|
||||||
|
F: Loader,
|
||||||
|
{
|
||||||
font: F,
|
font: F,
|
||||||
metrics: Metrics,
|
metrics: Metrics,
|
||||||
outline_cache: HashMap<GlyphId, Outline>,
|
outline_cache: HashMap<GlyphId, Outline>,
|
||||||
|
@ -63,7 +69,10 @@ impl Default for FontRenderOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FontInfoRefMut<'a, F> where F: Loader {
|
enum FontInfoRefMut<'a, F>
|
||||||
|
where
|
||||||
|
F: Loader,
|
||||||
|
{
|
||||||
Ref(&'a mut FontInfo<F>),
|
Ref(&'a mut FontInfo<F>),
|
||||||
Owned(FontInfo<F>),
|
Owned(FontInfo<F>),
|
||||||
}
|
}
|
||||||
|
@ -71,26 +80,33 @@ enum FontInfoRefMut<'a, F> where F: Loader {
|
||||||
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash)]
|
||||||
pub struct GlyphId(pub u32);
|
pub struct GlyphId(pub u32);
|
||||||
|
|
||||||
impl<F> FontContext<F> where F: Loader {
|
impl<F> FontContext<F>
|
||||||
|
where
|
||||||
|
F: Loader,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> FontContext<F> {
|
pub fn new() -> FontContext<F> {
|
||||||
FontContext { font_info: HashMap::new() }
|
FontContext {
|
||||||
|
font_info: HashMap::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_glyph(&mut self,
|
fn push_glyph(
|
||||||
|
&mut self,
|
||||||
scene: &mut Scene,
|
scene: &mut Scene,
|
||||||
font: &F,
|
font: &F,
|
||||||
font_key: Option<&str>,
|
font_key: Option<&str>,
|
||||||
glyph_id: GlyphId,
|
glyph_id: GlyphId,
|
||||||
glyph_offset: Vector2F,
|
glyph_offset: Vector2F,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
render_options: &FontRenderOptions)
|
render_options: &FontRenderOptions,
|
||||||
-> Result<(), GlyphLoadingError> {
|
) -> Result<(), GlyphLoadingError> {
|
||||||
// Insert the font into the cache if needed.
|
// Insert the font into the cache if needed.
|
||||||
let mut font_info = match font_key {
|
let mut font_info = match font_key {
|
||||||
Some(font_key) => {
|
Some(font_key) => {
|
||||||
if !self.font_info.contains_key(&*font_key) {
|
if !self.font_info.contains_key(&*font_key) {
|
||||||
self.font_info.insert(font_key.to_owned(), FontInfo::new((*font).clone()));
|
self.font_info
|
||||||
|
.insert(font_key.to_owned(), FontInfo::new((*font).clone()));
|
||||||
}
|
}
|
||||||
FontInfoRefMut::Ref(self.font_info.get_mut(&*font_key).unwrap())
|
FontInfoRefMut::Ref(self.font_info.get_mut(&*font_key).unwrap())
|
||||||
}
|
}
|
||||||
|
@ -115,8 +131,8 @@ impl<F> FontContext<F> where F: Loader {
|
||||||
|
|
||||||
let metrics = &font_info.metrics;
|
let metrics = &font_info.metrics;
|
||||||
let font_scale = font_size / metrics.units_per_em as f32;
|
let font_scale = font_size / metrics.units_per_em as f32;
|
||||||
let render_transform = render_options.transform *
|
let render_transform = render_options.transform
|
||||||
Transform2F::from_scale(vec2f(font_scale, -font_scale)).translate(glyph_offset);
|
* Transform2F::from_scale(vec2f(font_scale, -font_scale)).translate(glyph_offset);
|
||||||
|
|
||||||
let mut outline = match cached_outline {
|
let mut outline = match cached_outline {
|
||||||
Some(mut cached_outline) => {
|
Some(mut cached_outline) => {
|
||||||
|
@ -131,7 +147,11 @@ impl<F> FontContext<F> where F: Loader {
|
||||||
render_transform
|
render_transform
|
||||||
};
|
};
|
||||||
let mut outline_builder = OutlinePathBuilder::new(&transform);
|
let mut outline_builder = OutlinePathBuilder::new(&transform);
|
||||||
font.outline(glyph_id.0, render_options.hinting_options, &mut outline_builder)?;
|
font.outline(
|
||||||
|
glyph_id.0,
|
||||||
|
render_options.hinting_options,
|
||||||
|
&mut outline_builder,
|
||||||
|
)?;
|
||||||
let mut outline = outline_builder.build();
|
let mut outline = outline_builder.build();
|
||||||
if can_cache_outline {
|
if can_cache_outline {
|
||||||
font_info.outline_cache.insert(glyph_id, outline.clone());
|
font_info.outline_cache.insert(glyph_id, outline.clone());
|
||||||
|
@ -159,22 +179,25 @@ impl<F> FontContext<F> where F: Loader {
|
||||||
/// Attempts to look up a font in the font cache.
|
/// Attempts to look up a font in the font cache.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_cached_font(&self, postscript_name: &str) -> Option<&F> {
|
pub fn get_cached_font(&self, postscript_name: &str) -> Option<&F> {
|
||||||
self.font_info.get(postscript_name).map(|font_info| &font_info.font)
|
self.font_info
|
||||||
|
.get(postscript_name)
|
||||||
|
.map(|font_info| &font_info.font)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontContext<DefaultLoader> {
|
impl FontContext<DefaultLoader> {
|
||||||
pub fn push_layout(&mut self,
|
pub fn push_layout(
|
||||||
|
&mut self,
|
||||||
scene: &mut Scene,
|
scene: &mut Scene,
|
||||||
layout: &Layout,
|
layout: &Layout,
|
||||||
style: &TextStyle,
|
style: &TextStyle,
|
||||||
render_options: &FontRenderOptions)
|
render_options: &FontRenderOptions,
|
||||||
-> Result<(), GlyphLoadingError> {
|
) -> Result<(), GlyphLoadingError> {
|
||||||
let mut cached_font_key: Option<CachedFontKey<DefaultLoader>> = None;
|
let mut cached_font_key: Option<CachedFontKey<DefaultLoader>> = None;
|
||||||
for glyph in &layout.glyphs {
|
for glyph in &layout.glyphs {
|
||||||
match cached_font_key {
|
match cached_font_key {
|
||||||
Some(ref cached_font_key) if Arc::ptr_eq(&cached_font_key.font,
|
Some(ref cached_font_key)
|
||||||
&glyph.font.font) => {}
|
if Arc::ptr_eq(&cached_font_key.font, &glyph.font.font) => {}
|
||||||
_ => {
|
_ => {
|
||||||
cached_font_key = Some(CachedFontKey {
|
cached_font_key = Some(CachedFontKey {
|
||||||
font: glyph.font.font.clone(),
|
font: glyph.font.font.clone(),
|
||||||
|
@ -183,43 +206,59 @@ impl FontContext<DefaultLoader> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let cached_font_key = cached_font_key.as_ref().unwrap();
|
let cached_font_key = cached_font_key.as_ref().unwrap();
|
||||||
self.push_glyph(scene,
|
self.push_glyph(
|
||||||
|
scene,
|
||||||
&*cached_font_key.font,
|
&*cached_font_key.font,
|
||||||
cached_font_key.key.as_ref().map(|key| &**key),
|
cached_font_key.key.as_ref().map(|key| &**key),
|
||||||
GlyphId(glyph.glyph_id),
|
GlyphId(glyph.glyph_id),
|
||||||
glyph.offset,
|
glyph.offset,
|
||||||
style.size,
|
style.size,
|
||||||
&render_options)?;
|
&render_options,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn push_text(&mut self,
|
pub fn push_text(
|
||||||
|
&mut self,
|
||||||
scene: &mut Scene,
|
scene: &mut Scene,
|
||||||
text: &str,
|
text: &str,
|
||||||
style: &TextStyle,
|
style: &TextStyle,
|
||||||
collection: &FontCollection,
|
collection: &FontCollection,
|
||||||
render_options: &FontRenderOptions)
|
render_options: &FontRenderOptions,
|
||||||
-> Result<(), GlyphLoadingError> {
|
) -> Result<(), GlyphLoadingError> {
|
||||||
let layout = skribo::layout(style, collection, text);
|
let layout = skribo::layout(style, collection, text);
|
||||||
self.push_layout(scene, &layout, style, render_options)
|
self.push_layout(scene, &layout, style, render_options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CachedFontKey<F> where F: Loader {
|
struct CachedFontKey<F>
|
||||||
|
where
|
||||||
|
F: Loader,
|
||||||
|
{
|
||||||
font: Arc<F>,
|
font: Arc<F>,
|
||||||
key: Option<String>,
|
key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> FontInfo<F> where F: Loader {
|
impl<F> FontInfo<F>
|
||||||
|
where
|
||||||
|
F: Loader,
|
||||||
|
{
|
||||||
fn new(font: F) -> FontInfo<F> {
|
fn new(font: F) -> FontInfo<F> {
|
||||||
let metrics = font.metrics();
|
let metrics = font.metrics();
|
||||||
FontInfo { font, metrics, outline_cache: HashMap::new() }
|
FontInfo {
|
||||||
|
font,
|
||||||
|
metrics,
|
||||||
|
outline_cache: HashMap::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, F> FontInfoRefMut<'a, F> where F: Loader {
|
impl<'a, F> FontInfoRefMut<'a, F>
|
||||||
|
where
|
||||||
|
F: Loader,
|
||||||
|
{
|
||||||
fn get_mut(&mut self) -> &mut FontInfo<F> {
|
fn get_mut(&mut self) -> &mut FontInfo<F> {
|
||||||
match *self {
|
match *self {
|
||||||
FontInfoRefMut::Ref(ref mut reference) => &mut **reference,
|
FontInfoRefMut::Ref(ref mut reference) => &mut **reference,
|
||||||
|
@ -251,7 +290,8 @@ impl OutlinePathBuilder {
|
||||||
|
|
||||||
fn flush_current_contour(&mut self) {
|
fn flush_current_contour(&mut self) {
|
||||||
if !self.current_contour.is_empty() {
|
if !self.current_contour.is_empty() {
|
||||||
self.outline.push_contour(mem::replace(&mut self.current_contour, Contour::new()));
|
self.outline
|
||||||
|
.push_contour(mem::replace(&mut self.current_contour, Contour::new()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,13 +312,16 @@ impl OutlineSink for OutlinePathBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn quadratic_curve_to(&mut self, ctrl: Vector2F, to: Vector2F) {
|
fn quadratic_curve_to(&mut self, ctrl: Vector2F, to: Vector2F) {
|
||||||
self.current_contour.push_quadratic(self.transform * ctrl, self.transform * to);
|
self.current_contour
|
||||||
|
.push_quadratic(self.transform * ctrl, self.transform * to);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cubic_curve_to(&mut self, ctrl: LineSegment2F, to: Vector2F) {
|
fn cubic_curve_to(&mut self, ctrl: LineSegment2F, to: Vector2F) {
|
||||||
self.current_contour.push_cubic(self.transform * ctrl.from(),
|
self.current_contour.push_cubic(
|
||||||
|
self.transform * ctrl.from(),
|
||||||
self.transform * ctrl.to(),
|
self.transform * ctrl.to(),
|
||||||
self.transform * to);
|
self.transform * to,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&mut self) {
|
fn close(&mut self) {
|
||||||
|
|
594
ui/src/lib.rs
594
ui/src/lib.rs
File diff suppressed because it is too large
Load Diff
|
@ -69,17 +69,20 @@ fn main() {
|
||||||
.version("0.1")
|
.version("0.1")
|
||||||
.author("The Pathfinder Project Developers")
|
.author("The Pathfinder Project Developers")
|
||||||
.about("Generates area lookup tables for use with Pathfinder")
|
.about("Generates area lookup tables for use with Pathfinder")
|
||||||
.arg(Arg::with_name("OUTPUT-PATH").help("The `.png` image to produce")
|
.arg(
|
||||||
|
Arg::with_name("OUTPUT-PATH")
|
||||||
|
.help("The `.png` image to produce")
|
||||||
.required(true)
|
.required(true)
|
||||||
.index(1));
|
.index(1),
|
||||||
|
);
|
||||||
|
|
||||||
let matches = app.get_matches();
|
let matches = app.get_matches();
|
||||||
let image = ImageBuffer::from_fn(WIDTH, HEIGHT, |u, v| {
|
let image = ImageBuffer::from_fn(WIDTH, HEIGHT, |u, v| {
|
||||||
if u == 0 {
|
if u == 0 {
|
||||||
return Rgba([255, 255, 255, 255])
|
return Rgba([255, 255, 255, 255]);
|
||||||
}
|
}
|
||||||
if u == WIDTH - 1 {
|
if u == WIDTH - 1 {
|
||||||
return Rgba([0, 0, 0, 0])
|
return Rgba([0, 0, 0, 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let y = ((u as f32) - (WIDTH / 2) as f32) / 16.0;
|
let y = ((u as f32) - (WIDTH / 2) as f32) / 16.0;
|
||||||
|
|
|
@ -9,4 +9,4 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pathfinder_export = { path = "../../export" }
|
pathfinder_export = { path = "../../export" }
|
||||||
pathfinder_svg = { path = "../../svg" }
|
pathfinder_svg = { path = "../../svg" }
|
||||||
usvg = "0.9"
|
usvg = "0.10"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{Read, BufWriter};
|
|
||||||
use std::error::Error;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use pathfinder_svg::SVGScene;
|
|
||||||
use pathfinder_export::{Export, FileFormat};
|
use pathfinder_export::{Export, FileFormat};
|
||||||
use usvg::{Tree, Options};
|
use pathfinder_svg::SVGScene;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, Read};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use usvg::{Options, Tree};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let mut args = std::env::args_os().skip(1);
|
let mut args = std::env::args_os().skip(1);
|
||||||
|
@ -20,7 +20,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let format = match output.extension().and_then(|s| s.to_str()) {
|
let format = match output.extension().and_then(|s| s.to_str()) {
|
||||||
Some("pdf") => FileFormat::PDF,
|
Some("pdf") => FileFormat::PDF,
|
||||||
Some("ps") => FileFormat::PS,
|
Some("ps") => FileFormat::PS,
|
||||||
_ => return Err("output filename must have .ps or .pdf extension".into())
|
_ => return Err("output filename must have .ps or .pdf extension".into()),
|
||||||
};
|
};
|
||||||
scene.export(&mut writer, format).unwrap();
|
scene.export(&mut writer, format).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -134,12 +134,7 @@ impl ColorLut for ColorU {
|
||||||
|
|
||||||
// Quantize to the smallest value that yields the same table index.
|
// Quantize to the smallest value that yields the same table index.
|
||||||
fn quantized_floor(&self) -> ColorU {
|
fn quantized_floor(&self) -> ColorU {
|
||||||
ColorU::new(
|
ColorU::new(self.r & LUM_MASK, self.g & LUM_MASK, self.b & LUM_MASK, 255)
|
||||||
self.r & LUM_MASK,
|
|
||||||
self.g & LUM_MASK,
|
|
||||||
self.b & LUM_MASK,
|
|
||||||
255,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quantize to the largest value that yields the same table index.
|
// Quantize to the largest value that yields the same table index.
|
||||||
|
@ -176,10 +171,13 @@ fn apply_contrast(srca: f32, contrast: f32) -> f32 {
|
||||||
// The approach here is not necessarily the one with the lowest error
|
// The approach here is not necessarily the one with the lowest error
|
||||||
// See https://bel.fi/alankila/lcd/alpcor.html for a similar kind of thing
|
// See https://bel.fi/alankila/lcd/alpcor.html for a similar kind of thing
|
||||||
// that just search for the adjusted alpha value
|
// that just search for the adjusted alpha value
|
||||||
pub fn build_gamma_correcting_lut(table: &mut [u8; 256], src: u8, contrast: f32,
|
pub fn build_gamma_correcting_lut(
|
||||||
|
table: &mut [u8; 256],
|
||||||
|
src: u8,
|
||||||
|
contrast: f32,
|
||||||
src_space: LuminanceColorSpace,
|
src_space: LuminanceColorSpace,
|
||||||
dst_convert: LuminanceColorSpace) {
|
dst_convert: LuminanceColorSpace,
|
||||||
|
) {
|
||||||
let src = src as f32 / 255.0;
|
let src = src as f32 / 255.0;
|
||||||
let lin_src = src_space.to_luma(src);
|
let lin_src = src_space.to_luma(src);
|
||||||
// Guess at the dst. The perceptual inverse provides smaller visual
|
// Guess at the dst. The perceptual inverse provides smaller visual
|
||||||
|
@ -247,11 +245,13 @@ impl GammaLut {
|
||||||
|
|
||||||
for (i, entry) in self.tables.iter_mut().enumerate() {
|
for (i, entry) in self.tables.iter_mut().enumerate() {
|
||||||
let luminance = scale255(LUM_BITS, i as u8);
|
let luminance = scale255(LUM_BITS, i as u8);
|
||||||
build_gamma_correcting_lut(entry,
|
build_gamma_correcting_lut(
|
||||||
|
entry,
|
||||||
luminance,
|
luminance,
|
||||||
contrast,
|
contrast,
|
||||||
paint_color_space,
|
paint_color_space,
|
||||||
device_color_space);
|
device_color_space,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +280,11 @@ impl GammaLut {
|
||||||
let table_b = self.get_table(color.b);
|
let table_b = self.get_table(color.b);
|
||||||
|
|
||||||
for pixel in pixels.chunks_mut(4) {
|
for pixel in pixels.chunks_mut(4) {
|
||||||
let (b, g, r) = (table_b[pixel[0] as usize], table_g[pixel[1] as usize], table_r[pixel[2] as usize]);
|
let (b, g, r) = (
|
||||||
|
table_b[pixel[0] as usize],
|
||||||
|
table_g[pixel[1] as usize],
|
||||||
|
table_r[pixel[2] as usize],
|
||||||
|
);
|
||||||
pixel[0] = b;
|
pixel[0] = b;
|
||||||
pixel[1] = g;
|
pixel[1] = g;
|
||||||
pixel[2] = r;
|
pixel[2] = r;
|
||||||
|
@ -301,7 +305,6 @@ impl GammaLut {
|
||||||
pixel[3] = alpha;
|
pixel[3] = alpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end impl GammaLut
|
} // end impl GammaLut
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -316,9 +319,12 @@ mod tests {
|
||||||
((src * alpha + dst * (255. - alpha)) / 255.) as f32
|
((src * alpha + dst * (255. - alpha)) / 255.) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn absdiff(a: u32, b: u32) -> u32 {
|
fn absdiff(a: u32, b: u32) -> u32 {
|
||||||
if a < b { b - a } else { a - b }
|
if a < b {
|
||||||
|
b - a
|
||||||
|
} else {
|
||||||
|
a - b
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -338,7 +344,8 @@ mod tests {
|
||||||
let lin_src = (src as f32 / 255.).powf(g) * 255.;
|
let lin_src = (src as f32 / 255.).powf(g) * 255.;
|
||||||
|
|
||||||
let preblend_result = over(dst, src, preblend as u32);
|
let preblend_result = over(dst, src, preblend as u32);
|
||||||
let true_result = ((overf(lin_dst, lin_src, alpha as f32) / 255.).powf(1. / g) * 255.) as u32;
|
let true_result =
|
||||||
|
((overf(lin_dst, lin_src, alpha as f32) / 255.).powf(1. / g) * 255.) as u32;
|
||||||
let diff = absdiff(preblend_result, true_result);
|
let diff = absdiff(preblend_result, true_result);
|
||||||
//println!("{} -- {} {} = {}", alpha, preblend_result, true_result, diff);
|
//println!("{} -- {} {} = {}", alpha, preblend_result, true_result, diff);
|
||||||
max_diff = max(max_diff, diff);
|
max_diff = max(max_diff, diff);
|
||||||
|
@ -347,7 +354,6 @@ mod tests {
|
||||||
//println!("{} {} max {}", src, dst, max_diff);
|
//println!("{} {} max {}", src, dst, max_diff);
|
||||||
assert!(max_diff <= 33);
|
assert!(max_diff <= 33);
|
||||||
dst += 1;
|
dst += 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
src += 1;
|
src += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,9 +42,12 @@ pub fn main() {
|
||||||
.version("0.1")
|
.version("0.1")
|
||||||
.author("The Pathfinder Project Developers")
|
.author("The Pathfinder Project Developers")
|
||||||
.about("Generates gamma lookup tables for use with Pathfinder")
|
.about("Generates gamma lookup tables for use with Pathfinder")
|
||||||
.arg(Arg::with_name("OUTPUT-PATH").help("The `.png` image to produce")
|
.arg(
|
||||||
|
Arg::with_name("OUTPUT-PATH")
|
||||||
|
.help("The `.png` image to produce")
|
||||||
.required(true)
|
.required(true)
|
||||||
.index(1));
|
.index(1),
|
||||||
|
);
|
||||||
let matches = app.get_matches();
|
let matches = app.get_matches();
|
||||||
|
|
||||||
let gamma_lut = GammaLut::new(CONTRAST, GAMMA, GAMMA);
|
let gamma_lut = GammaLut::new(CONTRAST, GAMMA, GAMMA);
|
||||||
|
|
|
@ -5,4 +5,4 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
usvg = "0.9"
|
usvg = "0.10"
|
||||||
|
|
|
@ -49,9 +49,18 @@ fn process_node(node: &Node) {
|
||||||
match segment {
|
match segment {
|
||||||
PathSegment::MoveTo { x, y } => println!(" path.moveTo({}, {});", x, y),
|
PathSegment::MoveTo { x, y } => println!(" path.moveTo({}, {});", x, y),
|
||||||
PathSegment::LineTo { x, y } => println!(" path.lineTo({}, {});", x, y),
|
PathSegment::LineTo { x, y } => println!(" path.lineTo({}, {});", x, y),
|
||||||
PathSegment::CurveTo { x1, y1, x2, y2, x, y } => {
|
PathSegment::CurveTo {
|
||||||
println!(" path.cubicTo({}, {}, {}, {}, {}, {});",
|
x1,
|
||||||
x1, y1, x2, y2, x, y);
|
y1,
|
||||||
|
x2,
|
||||||
|
y2,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
} => {
|
||||||
|
println!(
|
||||||
|
" path.cubicTo({}, {}, {}, {}, {}, {});",
|
||||||
|
x1, y1, x2, y2, x, y
|
||||||
|
);
|
||||||
}
|
}
|
||||||
PathSegment::ClosePath => println!(" path.close();"),
|
PathSegment::ClosePath => println!(" path.close();"),
|
||||||
}
|
}
|
||||||
|
@ -78,10 +87,12 @@ fn process_node(node: &Node) {
|
||||||
|
|
||||||
fn set_color(paint: &Paint) {
|
fn set_color(paint: &Paint) {
|
||||||
if let Paint::Color(color) = *paint {
|
if let Paint::Color(color) = *paint {
|
||||||
println!(" paint.setColor(0x{:x});",
|
println!(
|
||||||
((color.red as u32) << 16) |
|
" paint.setColor(0x{:x});",
|
||||||
((color.green as u32) << 8) |
|
((color.red as u32) << 16)
|
||||||
((color.blue as u32) << 0) |
|
| ((color.green as u32) << 8)
|
||||||
(0xff << 24));
|
| ((color.blue as u32) << 0)
|
||||||
|
| (0xff << 24)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
use pathfinder_webgl::WebGlDevice;
|
use pathfinder_webgl::WebGlDevice;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::{self, HtmlCanvasElement, WebGl2RenderingContext};
|
use web_sys::{self, HtmlCanvasElement, WebGl2RenderingContext};
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
@ -45,7 +45,8 @@ struct WebCanvasState {
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = "createContext")]
|
#[wasm_bindgen(js_name = "createContext")]
|
||||||
pub fn create_context(html_canvas: HtmlCanvasElement) -> PFCanvasRenderingContext2D {
|
pub fn create_context(html_canvas: HtmlCanvasElement) -> PFCanvasRenderingContext2D {
|
||||||
let context = html_canvas.get_context("webgl2")
|
let context = html_canvas
|
||||||
|
.get_context("webgl2")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.dyn_into::<WebGl2RenderingContext>()
|
.dyn_into::<WebGl2RenderingContext>()
|
||||||
|
@ -89,15 +90,21 @@ impl PFCanvasRenderingContext2D {
|
||||||
#[wasm_bindgen(js_name = "pfFlush")]
|
#[wasm_bindgen(js_name = "pfFlush")]
|
||||||
pub fn pf_flush(&mut self) {
|
pub fn pf_flush(&mut self) {
|
||||||
// Update framebuffer size.
|
// Update framebuffer size.
|
||||||
let framebuffer_size = vec2i(self.html_canvas.width() as i32,
|
let framebuffer_size = vec2i(
|
||||||
self.html_canvas.height() as i32);
|
self.html_canvas.width() as i32,
|
||||||
|
self.html_canvas.height() as i32,
|
||||||
|
);
|
||||||
self.renderer.options_mut().dest = DestFramebuffer::full_window(framebuffer_size);
|
self.renderer.options_mut().dest = DestFramebuffer::full_window(framebuffer_size);
|
||||||
self.renderer.options_mut().background_color = None;
|
self.renderer.options_mut().background_color = None;
|
||||||
self.renderer.dest_framebuffer_size_changed();
|
self.renderer.dest_framebuffer_size_changed();
|
||||||
|
|
||||||
// TODO(pcwalton): This is inefficient!
|
// TODO(pcwalton): This is inefficient!
|
||||||
let mut scene = (*self.context.canvas_mut().scene()).clone();
|
let mut scene = (*self.context.canvas_mut().scene()).clone();
|
||||||
scene.build_and_render(&mut self.renderer, BuildOptions::default(), SequentialExecutor);
|
scene.build_and_render(
|
||||||
|
&mut self.renderer,
|
||||||
|
BuildOptions::default(),
|
||||||
|
SequentialExecutor,
|
||||||
|
);
|
||||||
|
|
||||||
self.context.canvas_mut().set_size(framebuffer_size);
|
self.context.canvas_mut().set_size(framebuffer_size);
|
||||||
}
|
}
|
||||||
|
@ -116,17 +123,20 @@ impl PFCanvasRenderingContext2D {
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = "clearRect")]
|
#[wasm_bindgen(js_name = "clearRect")]
|
||||||
pub fn clear_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
|
pub fn clear_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
|
||||||
self.context.clear_rect(RectF::new(vec2f(x, y), vec2f(width, height)));
|
self.context
|
||||||
|
.clear_rect(RectF::new(vec2f(x, y), vec2f(width, height)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = "fillRect")]
|
#[wasm_bindgen(js_name = "fillRect")]
|
||||||
pub fn fill_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
|
pub fn fill_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
|
||||||
self.context.fill_rect(RectF::new(vec2f(x, y), vec2f(width, height)));
|
self.context
|
||||||
|
.fill_rect(RectF::new(vec2f(x, y), vec2f(width, height)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = "strokeRect")]
|
#[wasm_bindgen(js_name = "strokeRect")]
|
||||||
pub fn stroke_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
|
pub fn stroke_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
|
||||||
self.context.stroke_rect(RectF::new(vec2f(x, y), vec2f(width, height)));
|
self.context
|
||||||
|
.stroke_rect(RectF::new(vec2f(x, y), vec2f(width, height)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Drawing text
|
// TODO(pcwalton): Drawing text
|
||||||
|
@ -219,12 +229,14 @@ impl PFCanvasRenderingContext2D {
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = "bezierCurveTo")]
|
#[wasm_bindgen(js_name = "bezierCurveTo")]
|
||||||
pub fn bezier_curve_to(&mut self, cp1x: f32, cp1y: f32, cp2x: f32, cp2y: f32, x: f32, y: f32) {
|
pub fn bezier_curve_to(&mut self, cp1x: f32, cp1y: f32, cp2x: f32, cp2y: f32, x: f32, y: f32) {
|
||||||
self.default_path.bezier_curve_to(vec2f(cp1x, cp1y), vec2f(cp2x, cp2y), vec2f(x, y))
|
self.default_path
|
||||||
|
.bezier_curve_to(vec2f(cp1x, cp1y), vec2f(cp2x, cp2y), vec2f(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = "quadraticCurveTo")]
|
#[wasm_bindgen(js_name = "quadraticCurveTo")]
|
||||||
pub fn quadratic_curve_to(&mut self, cpx: f32, cpy: f32, x: f32, y: f32) {
|
pub fn quadratic_curve_to(&mut self, cpx: f32, cpy: f32, x: f32, y: f32) {
|
||||||
self.default_path.quadratic_curve_to(vec2f(cpx, cpy), vec2f(x, y))
|
self.default_path
|
||||||
|
.quadratic_curve_to(vec2f(cpx, cpy), vec2f(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = "closePath")]
|
#[wasm_bindgen(js_name = "closePath")]
|
||||||
|
@ -260,9 +272,11 @@ fn parse_fill_or_stroke_style(string: &str) -> Option<FillStyle> {
|
||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
Ok(css_color) => css_color,
|
Ok(css_color) => css_color,
|
||||||
};
|
};
|
||||||
let color = ColorU::new(css_color.r,
|
let color = ColorU::new(
|
||||||
|
css_color.r,
|
||||||
css_color.g,
|
css_color.g,
|
||||||
css_color.b,
|
css_color.b,
|
||||||
(css_color.a * 255.0).round() as u8);
|
(css_color.a * 255.0).round() as u8,
|
||||||
|
);
|
||||||
Some(FillStyle::Color(color))
|
Some(FillStyle::Color(color))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use js_sys::{Uint8Array, Uint16Array, Float32Array, Object};
|
use js_sys::{Float32Array, Object, Uint16Array, Uint8Array};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps};
|
use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps};
|
||||||
|
@ -186,12 +186,16 @@ impl WebGlDevice {
|
||||||
self.clear(&render_state.options.clear_ops);
|
self.clear(&render_state.options.clear_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.context.use_program(Some(&render_state.program.gl_program));
|
self.context
|
||||||
self.context.bind_vertex_array(Some(&render_state.vertex_array.gl_vertex_array));
|
.use_program(Some(&render_state.program.gl_program));
|
||||||
|
self.context
|
||||||
|
.bind_vertex_array(Some(&render_state.vertex_array.gl_vertex_array));
|
||||||
|
|
||||||
self.bind_textures_and_images(&render_state.program,
|
self.bind_textures_and_images(
|
||||||
|
&render_state.program,
|
||||||
&render_state.textures,
|
&render_state.textures,
|
||||||
&render_state.images);
|
&render_state.images,
|
||||||
|
);
|
||||||
|
|
||||||
for (uniform, data) in render_state.uniforms {
|
for (uniform, data) in render_state.uniforms {
|
||||||
self.set_uniform(uniform, data);
|
self.set_uniform(uniform, data);
|
||||||
|
@ -203,14 +207,16 @@ impl WebGlDevice {
|
||||||
&self,
|
&self,
|
||||||
program: &WebGlProgram,
|
program: &WebGlProgram,
|
||||||
texture_bindings: &[TextureBinding<WebGlTextureParameter, WebGlTexture>],
|
texture_bindings: &[TextureBinding<WebGlTextureParameter, WebGlTexture>],
|
||||||
_: &[ImageBinding<(), WebGlTexture>]) {
|
_: &[ImageBinding<(), WebGlTexture>],
|
||||||
|
) {
|
||||||
for &(texture_parameter, texture) in texture_bindings {
|
for &(texture_parameter, texture) in texture_bindings {
|
||||||
self.bind_texture(texture, texture_parameter.texture_unit);
|
self.bind_texture(texture, texture_parameter.texture_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
let parameters = program.parameters.borrow();
|
let parameters = program.parameters.borrow();
|
||||||
for (texture_unit, uniform) in parameters.textures.iter().enumerate() {
|
for (texture_unit, uniform) in parameters.textures.iter().enumerate() {
|
||||||
self.context.uniform1i(uniform.location.as_ref(), texture_unit as i32);
|
self.context
|
||||||
|
.uniform1i(uniform.location.as_ref(), texture_unit as i32);
|
||||||
self.ck();
|
self.ck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,9 +492,7 @@ impl Device for WebGlDevice {
|
||||||
size: Vector2I,
|
size: Vector2I,
|
||||||
data_ref: TextureDataRef,
|
data_ref: TextureDataRef,
|
||||||
) -> WebGlTexture {
|
) -> WebGlTexture {
|
||||||
let data = unsafe {
|
let data = unsafe { check_and_extract_data(data_ref, size, format) };
|
||||||
check_and_extract_data(data_ref, size, format)
|
|
||||||
};
|
|
||||||
|
|
||||||
let texture = self.context.create_texture().unwrap();
|
let texture = self.context.create_texture().unwrap();
|
||||||
let texture = WebGlTexture {
|
let texture = WebGlTexture {
|
||||||
|
@ -568,7 +572,10 @@ impl Device for WebGlDevice {
|
||||||
.create_program()
|
.create_program()
|
||||||
.expect("unable to create program object");
|
.expect("unable to create program object");
|
||||||
match shaders {
|
match shaders {
|
||||||
ProgramKind::Raster { ref vertex, ref fragment } => {
|
ProgramKind::Raster {
|
||||||
|
ref vertex,
|
||||||
|
ref fragment,
|
||||||
|
} => {
|
||||||
self.context.attach_shader(&gl_program, &vertex.gl_shader);
|
self.context.attach_shader(&gl_program, &vertex.gl_shader);
|
||||||
self.context.attach_shader(&gl_program, &fragment.gl_shader);
|
self.context.attach_shader(&gl_program, &fragment.gl_shader);
|
||||||
}
|
}
|
||||||
|
@ -622,7 +629,9 @@ impl Device for WebGlDevice {
|
||||||
|
|
||||||
fn get_uniform(&self, program: &WebGlProgram, name: &str) -> WebGlUniform {
|
fn get_uniform(&self, program: &WebGlProgram, name: &str) -> WebGlUniform {
|
||||||
let name = format!("u{}", name);
|
let name = format!("u{}", name);
|
||||||
let location = self.context.get_uniform_location(&program.gl_program, &name);
|
let location = self
|
||||||
|
.context
|
||||||
|
.get_uniform_location(&program.gl_program, &name);
|
||||||
self.ck();
|
self.ck();
|
||||||
WebGlUniform { location: location }
|
WebGlUniform { location: location }
|
||||||
}
|
}
|
||||||
|
@ -638,7 +647,10 @@ impl Device for WebGlDevice {
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
WebGlTextureParameter { uniform, texture_unit: index as u32 }
|
WebGlTextureParameter {
|
||||||
|
uniform,
|
||||||
|
texture_unit: index as u32,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_image_parameter(&self, _: &WebGlProgram, _: &str) {
|
fn get_image_parameter(&self, _: &WebGlProgram, _: &str) {
|
||||||
|
@ -744,12 +756,7 @@ impl Device for WebGlDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_buffer<T>(
|
fn allocate_buffer<T>(&self, buffer: &WebGlBuffer, data: BufferData<T>, target: BufferTarget) {
|
||||||
&self,
|
|
||||||
buffer: &WebGlBuffer,
|
|
||||||
data: BufferData<T>,
|
|
||||||
target: BufferTarget,
|
|
||||||
) {
|
|
||||||
let target = match target {
|
let target = match target {
|
||||||
BufferTarget::Vertex => WebGl::ARRAY_BUFFER,
|
BufferTarget::Vertex => WebGl::ARRAY_BUFFER,
|
||||||
BufferTarget::Index => WebGl::ELEMENT_ARRAY_BUFFER,
|
BufferTarget::Index => WebGl::ELEMENT_ARRAY_BUFFER,
|
||||||
|
@ -770,16 +777,22 @@ impl Device for WebGlDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_to_buffer<T>(&self,
|
fn upload_to_buffer<T>(
|
||||||
|
&self,
|
||||||
buffer: &Self::Buffer,
|
buffer: &Self::Buffer,
|
||||||
position: usize,
|
position: usize,
|
||||||
data: &[T],
|
data: &[T],
|
||||||
target: BufferTarget) {
|
target: BufferTarget,
|
||||||
|
) {
|
||||||
let target = target.to_gl_target();
|
let target = target.to_gl_target();
|
||||||
self.context.bind_buffer(target, Some(&buffer.buffer)); self.ck();
|
self.context.bind_buffer(target, Some(&buffer.buffer));
|
||||||
self.context.buffer_sub_data_with_i32_and_u8_array(target,
|
self.ck();
|
||||||
|
self.context.buffer_sub_data_with_i32_and_u8_array(
|
||||||
|
target,
|
||||||
position as i32,
|
position as i32,
|
||||||
slice_to_u8(data)); self.ck();
|
slice_to_u8(data),
|
||||||
|
);
|
||||||
|
self.ck();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -794,44 +807,46 @@ impl Device for WebGlDevice {
|
||||||
|
|
||||||
fn set_texture_sampling_mode(&self, texture: &Self::Texture, flags: TextureSamplingFlags) {
|
fn set_texture_sampling_mode(&self, texture: &Self::Texture, flags: TextureSamplingFlags) {
|
||||||
self.bind_texture(texture, 0);
|
self.bind_texture(texture, 0);
|
||||||
self.context
|
self.context.tex_parameteri(
|
||||||
.tex_parameteri(WebGl::TEXTURE_2D,
|
WebGl::TEXTURE_2D,
|
||||||
WebGl::TEXTURE_MIN_FILTER,
|
WebGl::TEXTURE_MIN_FILTER,
|
||||||
if flags.contains(TextureSamplingFlags::NEAREST_MIN) {
|
if flags.contains(TextureSamplingFlags::NEAREST_MIN) {
|
||||||
WebGl::NEAREST as i32
|
WebGl::NEAREST as i32
|
||||||
} else {
|
} else {
|
||||||
WebGl::LINEAR as i32
|
WebGl::LINEAR as i32
|
||||||
});
|
},
|
||||||
self.context
|
);
|
||||||
.tex_parameteri(WebGl::TEXTURE_2D,
|
self.context.tex_parameteri(
|
||||||
|
WebGl::TEXTURE_2D,
|
||||||
WebGl::TEXTURE_MAG_FILTER,
|
WebGl::TEXTURE_MAG_FILTER,
|
||||||
if flags.contains(TextureSamplingFlags::NEAREST_MAG) {
|
if flags.contains(TextureSamplingFlags::NEAREST_MAG) {
|
||||||
WebGl::NEAREST as i32
|
WebGl::NEAREST as i32
|
||||||
} else {
|
} else {
|
||||||
WebGl::LINEAR as i32
|
WebGl::LINEAR as i32
|
||||||
});
|
},
|
||||||
self.context
|
);
|
||||||
.tex_parameteri(WebGl::TEXTURE_2D,
|
self.context.tex_parameteri(
|
||||||
|
WebGl::TEXTURE_2D,
|
||||||
WebGl::TEXTURE_WRAP_S,
|
WebGl::TEXTURE_WRAP_S,
|
||||||
if flags.contains(TextureSamplingFlags::REPEAT_U) {
|
if flags.contains(TextureSamplingFlags::REPEAT_U) {
|
||||||
WebGl::REPEAT as i32
|
WebGl::REPEAT as i32
|
||||||
} else {
|
} else {
|
||||||
WebGl::CLAMP_TO_EDGE as i32
|
WebGl::CLAMP_TO_EDGE as i32
|
||||||
});
|
},
|
||||||
self.context
|
);
|
||||||
.tex_parameteri(WebGl::TEXTURE_2D,
|
self.context.tex_parameteri(
|
||||||
|
WebGl::TEXTURE_2D,
|
||||||
WebGl::TEXTURE_WRAP_T,
|
WebGl::TEXTURE_WRAP_T,
|
||||||
if flags.contains(TextureSamplingFlags::REPEAT_V) {
|
if flags.contains(TextureSamplingFlags::REPEAT_V) {
|
||||||
WebGl::REPEAT as i32
|
WebGl::REPEAT as i32
|
||||||
} else {
|
} else {
|
||||||
WebGl::CLAMP_TO_EDGE as i32
|
WebGl::CLAMP_TO_EDGE as i32
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_to_texture(&self, texture: &WebGlTexture, rect: RectI, data_ref: TextureDataRef) {
|
fn upload_to_texture(&self, texture: &WebGlTexture, rect: RectI, data_ref: TextureDataRef) {
|
||||||
let data = unsafe {
|
let data = unsafe { check_and_extract_data(data_ref, rect.size(), texture.format) };
|
||||||
check_and_extract_data(data_ref, rect.size(), texture.format)
|
|
||||||
};
|
|
||||||
assert!(rect.size().x() >= 0);
|
assert!(rect.size().x() >= 0);
|
||||||
assert!(rect.size().y() >= 0);
|
assert!(rect.size().y() >= 0);
|
||||||
assert!(rect.max_x() <= texture.size.x());
|
assert!(rect.max_x() <= texture.size.x());
|
||||||
|
|
Loading…
Reference in New Issue