diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index dd95ea46..15ac1dbe 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -82,8 +82,15 @@ impl<'a> SceneBuilder<'a> { let path_object = &scene.paths[path_index]; let outline = scene.apply_render_options(path_object.outline(), built_options); let paint_id = path_object.paint(); + let object_is_opaque = scene.paints[paint_id.0 as usize].is_opaque(); + + let mut tiler = Tiler::new(self, + &outline, + view_box, + path_index as u16, + paint_id, + object_is_opaque); - let mut tiler = Tiler::new(self, &outline, view_box, paint_id, path_index as u16); tiler.generate_tiles(); self.listener.send(RenderCommand::AddFills(tiler.built_object.fills)); diff --git a/renderer/src/paint.rs b/renderer/src/paint.rs index 9777e5b8..be48ce88 100644 --- a/renderer/src/paint.rs +++ b/renderer/src/paint.rs @@ -9,12 +9,27 @@ // except according to those terms. use crate::gpu_data::PaintData; -use crate::scene::{PaintId, Scene}; +use crate::scene::Scene; use pathfinder_geometry::basic::point::Point2DI32; +use pathfinder_geometry::color::ColorU; const PAINT_TEXTURE_WIDTH: i32 = 256; const PAINT_TEXTURE_HEIGHT: i32 = 256; +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct Paint { + pub color: ColorU, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct PaintId(pub u16); + +impl Paint { + pub(crate) fn is_opaque(&self) -> bool { + self.color.a == 255 + } +} + impl Scene { pub fn build_paint_data(&self) -> PaintData { let size = Point2DI32::new(PAINT_TEXTURE_WIDTH, PAINT_TEXTURE_HEIGHT); diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 8497575e..64479c34 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -14,6 +14,7 @@ use crate::builder::SceneBuilder; use crate::concurrent::executor::Executor; use crate::options::{PreparedRenderOptions, PreparedRenderTransform}; use crate::options::{RenderCommandListener, RenderOptions}; +use crate::paint::{Paint, PaintId}; use hashbrown::HashMap; use pathfinder_geometry::basic::point::Point2DF32; use pathfinder_geometry::basic::rect::RectF32; @@ -222,11 +223,3 @@ impl PathObject { self.paint } } - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Paint { - pub color: ColorU, -} - -#[derive(Clone, Copy, PartialEq, Debug)] -pub struct PaintId(pub u16); diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index cfceb05f..fb2c3eaf 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -10,8 +10,7 @@ use crate::builder::SceneBuilder; use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, TileObjectPrimitive}; -use crate::paint; -use crate::scene::PaintId; +use crate::paint::{self, PaintId}; use crate::sorted_vector::SortedVector; use pathfinder_geometry::basic::line_segment::LineSegmentF32; use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32}; @@ -33,6 +32,7 @@ pub(crate) struct Tiler<'a> { pub built_object: BuiltObject, paint_id: PaintId, object_index: u16, + object_is_opaque: bool, point_queue: SortedVector, active_edges: SortedVector, @@ -45,8 +45,9 @@ impl<'a> Tiler<'a> { builder: &'a SceneBuilder<'a>, outline: &'a Outline, view_box: RectF32, - paint_id: PaintId, object_index: u16, + paint_id: PaintId, + object_is_opaque: bool, ) -> Tiler<'a> { let bounds = outline .bounds() @@ -58,8 +59,9 @@ impl<'a> Tiler<'a> { builder, outline, built_object, - paint_id, object_index, + paint_id, + object_is_opaque, point_queue: SortedVector::new(), active_edges: SortedVector::new(), @@ -112,11 +114,18 @@ impl<'a> Tiler<'a> { let tile_coords = self .built_object .local_tile_index_to_coords(tile_index as u32); + if tile.is_solid() { - if tile.backdrop != 0 { - self.builder.z_buffer.update(tile_coords, self.object_index); + // Blank tiles are always skipped. + if tile.backdrop == 0 { + continue; + } + + // If this is a solid tile, poke it into the Z-buffer and stop here. + if self.object_is_opaque { + self.builder.z_buffer.update(tile_coords, self.object_index); + continue; } - continue; } let origin_uv = paint::paint_id_to_tex_coords(self.paint_id); diff --git a/svg/src/lib.rs b/svg/src/lib.rs index 249bb8fe..bb8b89b6 100644 --- a/svg/src/lib.rs +++ b/svg/src/lib.rs @@ -21,10 +21,11 @@ use pathfinder_geometry::color::ColorU; use pathfinder_geometry::outline::Outline; use pathfinder_geometry::segment::{Segment, SegmentFlags}; use pathfinder_geometry::stroke::OutlineStrokeToFill; -use pathfinder_renderer::scene::{Paint, PathObject, Scene}; +use pathfinder_renderer::paint::Paint; +use pathfinder_renderer::scene::{PathObject, Scene}; use std::fmt::{Display, Formatter, Result as FormatResult}; use std::mem; -use usvg::{Color as SvgColor, Node, NodeExt, NodeKind, Paint as UsvgPaint}; +use usvg::{Color as SvgColor, Node, NodeExt, NodeKind, Opacity, Paint as UsvgPaint}; use usvg::{PathSegment as UsvgPathSegment, Rect as UsvgRect, Transform as UsvgTransform}; use usvg::{Tree, Visibility}; @@ -114,9 +115,11 @@ impl BuiltSVG { } NodeKind::Path(ref path) if path.visibility == Visibility::Visible => { if let Some(ref fill) = path.fill { - let style = self - .scene - .push_paint(&Paint::from_svg_paint(&fill.paint, &mut self.result_flags)); + let style = self.scene.push_paint(&Paint::from_svg_paint( + &fill.paint, + fill.opacity, + &mut self.result_flags, + )); let path = UsvgPathToSegments::new(path.segments.iter().cloned()); let path = Transform2DF32PathIter::new(path, &transform); @@ -129,6 +132,7 @@ impl BuiltSVG { if let Some(ref stroke) = path.stroke { let style = self.scene.push_paint(&Paint::from_svg_paint( &stroke.paint, + stroke.opacity, &mut self.result_flags, )); let stroke_width = f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH); @@ -235,15 +239,17 @@ impl Display for BuildResultFlags { } trait PaintExt { - fn from_svg_paint(svg_paint: &UsvgPaint, result_flags: &mut BuildResultFlags) -> Self; + fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags) + -> Self; } impl PaintExt for Paint { #[inline] - fn from_svg_paint(svg_paint: &UsvgPaint, result_flags: &mut BuildResultFlags) -> Paint { + fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags) + -> Paint { Paint { color: match *svg_paint { - UsvgPaint::Color(color) => ColorU::from_svg_color(color), + UsvgPaint::Color(color) => ColorU::from_svg_color(color, opacity), UsvgPaint::Link(_) => { // TODO(pcwalton) result_flags.insert(BuildResultFlags::UNSUPPORTED_LINK_PAINT); @@ -358,17 +364,17 @@ where } trait ColorUExt { - fn from_svg_color(svg_color: SvgColor) -> Self; + fn from_svg_color(svg_color: SvgColor, opacity: Opacity) -> Self; } impl ColorUExt for ColorU { #[inline] - fn from_svg_color(svg_color: SvgColor) -> ColorU { + fn from_svg_color(svg_color: SvgColor, opacity: Opacity) -> ColorU { ColorU { r: svg_color.red, g: svg_color.green, b: svg_color.blue, - a: 255, + a: (opacity.value() * 255.0).round() as u8, } } }