Separate opacity out from paint.

This allows `globalAlpha` to work on render targets.
This commit is contained in:
Patrick Walton 2020-02-26 12:43:07 -08:00
parent 1deb53fa9c
commit 77b3555828
31 changed files with 230 additions and 206 deletions

View File

@ -103,12 +103,9 @@ impl CanvasRenderingContext2D {
let paint = self.current_state.resolve_paint(&paint); let paint = self.current_state.resolve_paint(&paint);
let paint_id = self.scene.push_paint(&paint); let paint_id = self.scene.push_paint(&paint);
self.scene.push_path(DrawPath::new(outline, let mut path = DrawPath::new(outline, paint_id);
paint_id, path.set_blend_mode(BlendMode::Clear);
None, self.scene.push_path(path);
FillRule::Winding,
BlendMode::Clear,
String::new()))
} }
// Line styles // Line styles
@ -224,8 +221,9 @@ impl CanvasRenderingContext2D {
let mut outline = path.into_outline(); let mut outline = path.into_outline();
outline.transform(&self.current_state.transform); outline.transform(&self.current_state.transform);
let clip_path_id = self.scene let mut clip_path = ClipPath::new(outline);
.push_clip_path(ClipPath::new(outline, fill_rule, String::new())); clip_path.set_fill_rule(fill_rule);
let clip_path_id = self.scene.push_clip_path(clip_path);
self.current_state.clip_path = Some(clip_path_id); self.current_state.clip_path = Some(clip_path_id);
} }
@ -234,6 +232,7 @@ impl CanvasRenderingContext2D {
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();
let composite_op = self.current_state.global_composite_operation.to_composite_op(); let composite_op = self.current_state.global_composite_operation.to_composite_op();
let opacity = (self.current_state.global_alpha * 255.0) as u8;
if !self.current_state.shadow_paint.is_fully_transparent() { if !self.current_state.shadow_paint.is_fully_transparent() {
let render_target_id = self.push_render_target_if_needed(composite_op); let render_target_id = self.push_render_target_if_needed(composite_op);
@ -243,24 +242,24 @@ impl CanvasRenderingContext2D {
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));
self.scene.push_path(DrawPath::new(outline, let mut path = DrawPath::new(outline, paint_id);
paint_id, path.set_clip_path(clip_path);
clip_path, path.set_fill_rule(fill_rule);
fill_rule, path.set_blend_mode(blend_mode);
blend_mode, path.set_opacity(opacity);
String::new())); self.scene.push_path(path);
self.composite_render_target_if_needed(composite_op, render_target_id); self.composite_render_target_if_needed(composite_op, render_target_id);
} }
let render_target_id = self.push_render_target_if_needed(composite_op); let render_target_id = self.push_render_target_if_needed(composite_op);
self.scene.push_path(DrawPath::new(outline, let mut path = DrawPath::new(outline, paint_id);
paint_id, path.set_clip_path(clip_path);
clip_path, path.set_fill_rule(fill_rule);
fill_rule, path.set_blend_mode(blend_mode);
blend_mode, path.set_opacity(opacity);
String::new())); self.scene.push_path(path);
self.composite_render_target_if_needed(composite_op, render_target_id); self.composite_render_target_if_needed(composite_op, render_target_id);
} }
@ -387,12 +386,11 @@ impl State {
} }
fn resolve_paint<'a>(&self, paint: &'a Paint) -> Cow<'a, Paint> { fn resolve_paint<'a>(&self, paint: &'a Paint) -> Cow<'a, Paint> {
if self.global_alpha == 1.0 && (paint.is_color() || self.transform.is_identity()) { if self.transform.is_identity() {
return Cow::Borrowed(paint); return Cow::Borrowed(paint);
} }
let mut paint = (*paint).clone(); let mut paint = (*paint).clone();
paint.set_opacity(self.global_alpha);
paint.apply_transform(&self.transform); paint.apply_transform(&self.transform);
Cow::Owned(paint) Cow::Owned(paint)
} }

View File

@ -148,12 +148,6 @@ impl Gradient {
.lerp(upper_stop.color.to_f32(), (t - lower_stop.offset) / denom) .lerp(upper_stop.color.to_f32(), (t - lower_stop.offset) / denom)
.to_u8() .to_u8()
} }
pub fn set_opacity(&mut self, alpha: f32) {
for stop in &mut self.stops.array {
stop.color.a = (stop.color.a as f32 * alpha).round() as u8;
}
}
} }
impl ColorStop { impl ColorStop {

View File

@ -86,17 +86,6 @@ impl Image {
pub fn is_opaque(&self) -> bool { pub fn is_opaque(&self) -> bool {
self.is_opaque self.is_opaque
} }
pub fn set_opacity(&mut self, alpha: f32) {
debug_assert!(alpha >= 0.0 && alpha <= 1.0);
if alpha == 1.0 {
return;
}
// TODO(pcwalton): Go four pixels at a time with SIMD.
self.pixels.iter_mut().for_each(|pixel| pixel.a = (pixel.a as f32 * alpha).round() as u8);
self.is_opaque = false;
}
} }
impl PatternSource { impl PatternSource {
@ -110,18 +99,6 @@ impl PatternSource {
} }
} }
} }
#[inline]
pub fn set_opacity(&mut self, alpha: f32) {
match *self {
PatternSource::Image(ref mut image) => image.set_opacity(alpha),
PatternSource::RenderTarget(_) => {
// TODO(pcwalton): We'll probably have to introduce and use an Opacity filter for
// this.
unimplemented!()
}
}
}
} }
impl Debug for Image { impl Debug for Image {

View File

@ -365,6 +365,9 @@ impl Device for MetalDevice {
(VertexAttrClass::Int, VertexAttrType::I8, 1) => MTLVertexFormat::Char, (VertexAttrClass::Int, VertexAttrType::I8, 1) => MTLVertexFormat::Char,
(VertexAttrClass::Int, VertexAttrType::U8, 1) => MTLVertexFormat::UChar, (VertexAttrClass::Int, VertexAttrType::U8, 1) => MTLVertexFormat::UChar,
(VertexAttrClass::FloatNorm, VertexAttrType::I8, 1) => MTLVertexFormat::CharNormalized, (VertexAttrClass::FloatNorm, VertexAttrType::I8, 1) => MTLVertexFormat::CharNormalized,
(VertexAttrClass::FloatNorm, VertexAttrType::U8, 1) => {
MTLVertexFormat::UCharNormalized
}
(VertexAttrClass::Int, VertexAttrType::I16, 1) => MTLVertexFormat::Short, (VertexAttrClass::Int, VertexAttrType::I16, 1) => MTLVertexFormat::Short,
(VertexAttrClass::Int, VertexAttrType::U16, 1) => MTLVertexFormat::UShort, (VertexAttrClass::Int, VertexAttrType::U16, 1) => MTLVertexFormat::UShort,
(VertexAttrClass::FloatNorm, VertexAttrType::U16, 1) => { (VertexAttrClass::FloatNorm, VertexAttrType::U16, 1) => {

View File

@ -180,6 +180,7 @@ impl<'a> SceneBuilder<'a> {
TilingPathInfo::Draw { TilingPathInfo::Draw {
paint_metadata, paint_metadata,
blend_mode: path_object.blend_mode(), blend_mode: path_object.blend_mode(),
opacity: path_object.opacity(),
built_clip_path, built_clip_path,
}); });
@ -670,27 +671,32 @@ impl ObjectBuilder {
mask_tile_index: u16, mask_tile_index: u16,
tile_coords: Vector2I, tile_coords: Vector2I,
object_index: u16, object_index: u16,
opacity: u8,
paint_metadata: &PaintMetadata) { paint_metadata: &PaintMetadata) {
alpha_tiles.push(AlphaTile { alpha_tiles.push(AlphaTile {
upper_left: AlphaTileVertex::new(tile_coords, upper_left: AlphaTileVertex::new(tile_coords,
mask_tile_index, mask_tile_index,
Vector2I::default(), Vector2I::default(),
object_index, object_index,
opacity,
paint_metadata), paint_metadata),
upper_right: AlphaTileVertex::new(tile_coords, upper_right: AlphaTileVertex::new(tile_coords,
mask_tile_index, mask_tile_index,
Vector2I::new(1, 0), Vector2I::new(1, 0),
object_index, object_index,
opacity,
paint_metadata), paint_metadata),
lower_left: AlphaTileVertex::new(tile_coords, lower_left: AlphaTileVertex::new(tile_coords,
mask_tile_index, mask_tile_index,
Vector2I::new(0, 1), Vector2I::new(0, 1),
object_index, object_index,
opacity,
paint_metadata), paint_metadata),
lower_right: AlphaTileVertex::new(tile_coords, lower_right: AlphaTileVertex::new(tile_coords,
mask_tile_index, mask_tile_index,
Vector2I::splat(1), Vector2I::splat(1),
object_index, object_index,
opacity,
paint_metadata), paint_metadata),
}); });
} }
@ -723,6 +729,7 @@ impl AlphaTileVertex {
tile_index: u16, tile_index: u16,
tile_offset: Vector2I, tile_offset: Vector2I,
object_index: u16, object_index: u16,
opacity: u8,
paint_metadata: &PaintMetadata) paint_metadata: &PaintMetadata)
-> AlphaTileVertex { -> AlphaTileVertex {
let tile_position = tile_origin + tile_offset; let tile_position = tile_origin + tile_offset;
@ -737,6 +744,7 @@ impl AlphaTileVertex {
mask_u: mask_uv.x() as u16, mask_u: mask_uv.x() as u16,
mask_v: mask_uv.y() as u16, mask_v: mask_uv.y() as u16,
object_index, object_index,
opacity,
pad: 0, pad: 0,
} }
} }

View File

@ -193,6 +193,7 @@ impl<D> AlphaTileVertexArray<D> where D: Device {
"ColorTexCoord").unwrap(); "ColorTexCoord").unwrap();
let mask_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, let mask_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program,
"MaskTexCoord").unwrap(); "MaskTexCoord").unwrap();
let opacity_attr = device.get_vertex_attr(&alpha_tile_program.program, "Opacity").unwrap();
device.bind_buffer(&vertex_array, alpha_tile_vertex_buffer, BufferTarget::Vertex); device.bind_buffer(&vertex_array, alpha_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 {
@ -222,6 +223,15 @@ impl<D> AlphaTileVertexArray<D> where D: Device {
divisor: 0, divisor: 0,
buffer_index: 0, buffer_index: 0,
}); });
device.configure_vertex_attr(&vertex_array, &opacity_attr, &VertexAttrDescriptor {
size: 1,
class: VertexAttrClass::FloatNorm,
attr_type: VertexAttrType::U8,
stride: ALPHA_TILE_VERTEX_SIZE,
offset: 14,
divisor: 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);
AlphaTileVertexArray { vertex_array } AlphaTileVertexArray { vertex_array }

View File

@ -173,7 +173,8 @@ pub struct AlphaTileVertex {
pub color_u: u16, pub color_u: u16,
pub color_v: u16, pub color_v: u16,
pub object_index: u16, pub object_index: u16,
pub pad: u16, pub opacity: u8,
pub pad: u8,
} }
impl Debug for RenderCommand { impl Debug for RenderCommand {

View File

@ -113,18 +113,6 @@ impl Paint {
} }
} }
pub fn set_opacity(&mut self, alpha: f32) {
if alpha == 1.0 {
return;
}
match *self {
Paint::Color(ref mut color) => color.a = (color.a as f32 * alpha).round() as u8,
Paint::Gradient(ref mut gradient) => gradient.set_opacity(alpha),
Paint::Pattern(ref mut pattern) => pattern.source.set_opacity(alpha),
}
}
pub fn apply_transform(&mut self, transform: &Transform2F) { pub fn apply_transform(&mut self, transform: &Transform2F) {
if transform.is_identity() { if transform.is_identity() {
return; return;

View File

@ -226,6 +226,7 @@ pub struct DrawPath {
clip_path: Option<ClipPathId>, clip_path: Option<ClipPathId>,
fill_rule: FillRule, fill_rule: FillRule,
blend_mode: BlendMode, blend_mode: BlendMode,
opacity: u8,
name: String, name: String,
} }
@ -267,14 +268,16 @@ pub enum DisplayItem {
impl DrawPath { impl DrawPath {
#[inline] #[inline]
pub fn new(outline: Outline, pub fn new(outline: Outline, paint: PaintId) -> DrawPath {
paint: PaintId, DrawPath {
clip_path: Option<ClipPathId>, outline,
fill_rule: FillRule, paint,
blend_mode: BlendMode, clip_path: None,
name: String) fill_rule: FillRule::Winding,
-> DrawPath { blend_mode: BlendMode::SrcOver,
DrawPath { outline, paint, clip_path, fill_rule, blend_mode, name } opacity: !0,
name: String::new(),
}
} }
#[inline] #[inline]
@ -287,6 +290,11 @@ impl DrawPath {
self.clip_path self.clip_path
} }
#[inline]
pub fn set_clip_path(&mut self, new_clip_path: Option<ClipPathId>) {
self.clip_path = new_clip_path
}
#[inline] #[inline]
pub(crate) fn paint(&self) -> PaintId { pub(crate) fn paint(&self) -> PaintId {
self.paint self.paint
@ -297,16 +305,41 @@ impl DrawPath {
self.fill_rule self.fill_rule
} }
#[inline]
pub fn set_fill_rule(&mut self, new_fill_rule: FillRule) {
self.fill_rule = new_fill_rule
}
#[inline] #[inline]
pub(crate) fn blend_mode(&self) -> BlendMode { pub(crate) fn blend_mode(&self) -> BlendMode {
self.blend_mode self.blend_mode
} }
#[inline]
pub fn set_blend_mode(&mut self, new_blend_mode: BlendMode) {
self.blend_mode = new_blend_mode
}
#[inline]
pub(crate) fn opacity(&self) -> u8 {
self.opacity
}
#[inline]
pub fn set_opacity(&mut self, new_opacity: u8) {
self.opacity = new_opacity
}
#[inline]
pub fn set_name(&mut self, new_name: String) {
self.name = new_name
}
} }
impl ClipPath { impl ClipPath {
#[inline] #[inline]
pub fn new(outline: Outline, fill_rule: FillRule, name: String) -> ClipPath { pub fn new(outline: Outline) -> ClipPath {
ClipPath { outline, fill_rule, name } ClipPath { outline, fill_rule: FillRule::Winding, name: String::new() }
} }
#[inline] #[inline]
@ -318,6 +351,16 @@ impl ClipPath {
pub(crate) fn fill_rule(&self) -> FillRule { pub(crate) fn fill_rule(&self) -> FillRule {
self.fill_rule self.fill_rule
} }
#[inline]
pub fn set_fill_rule(&mut self, new_fill_rule: FillRule) {
self.fill_rule = new_fill_rule
}
#[inline]
pub fn set_name(&mut self, new_name: String) {
self.name = new_name
}
} }
impl RenderTarget { impl RenderTarget {

View File

@ -46,6 +46,7 @@ pub(crate) enum TilingPathInfo<'a> {
Draw { Draw {
paint_metadata: &'a PaintMetadata, paint_metadata: &'a PaintMetadata,
blend_mode: BlendMode, blend_mode: BlendMode,
opacity: u8,
built_clip_path: Option<&'a BuiltPath>, built_clip_path: Option<&'a BuiltPath>,
}, },
} }
@ -127,10 +128,10 @@ impl<'a> Tiler<'a> {
} }
fn pack_and_cull_draw_path(&mut self) { fn pack_and_cull_draw_path(&mut self) {
let (paint_metadata, blend_mode, built_clip_path) = match self.path_info { let (paint_metadata, blend_mode, opacity, built_clip_path) = match self.path_info {
TilingPathInfo::Clip => unreachable!(), TilingPathInfo::Clip => unreachable!(),
TilingPathInfo::Draw { paint_metadata, blend_mode, built_clip_path } => { TilingPathInfo::Draw { paint_metadata, blend_mode, opacity, built_clip_path } => {
(paint_metadata, blend_mode, built_clip_path) (paint_metadata, blend_mode, opacity, built_clip_path)
} }
}; };
@ -181,7 +182,7 @@ impl<'a> Tiler<'a> {
// Next, if this is a solid tile that completely occludes the background, record // Next, if this is a solid tile that completely occludes the background, record
// that fact and stop here. // that fact and stop here.
if paint_metadata.is_opaque && blend_mode.occludes_backdrop() { if paint_metadata.is_opaque && blend_mode.occludes_backdrop() && opacity == !0 {
self.object_builder.built_path.solid_tiles.push(SolidTile::new(tile_coords)); self.object_builder.built_path.solid_tiles.push(SolidTile::new(tile_coords));
continue; continue;
} }
@ -209,6 +210,7 @@ impl<'a> Tiler<'a> {
mask_tile_index, mask_tile_index,
tile_coords, tile_coords,
self.object_index, self.object_index,
opacity,
paint_metadata); paint_metadata);
} }

View File

@ -36,12 +36,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord; in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){ vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r; float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage); return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
} }
vec4 sampleDestColor(){ vec4 sampleDestColor(){

View File

@ -20,15 +20,18 @@ uniform vec2 uTileSize;
in ivec2 aTilePosition; in ivec2 aTilePosition;
in vec2 aColorTexCoord; in vec2 aColorTexCoord;
in vec2 aMaskTexCoord; in vec2 aMaskTexCoord;
in float aOpacity;
out vec2 vColorTexCoord; out vec2 vColorTexCoord;
out vec2 vMaskTexCoord; out vec2 vMaskTexCoord;
out float vOpacity;
void main(){ void main(){
vec2 position = aTilePosition * uTileSize; vec2 position = aTilePosition * uTileSize;
vMaskTexCoord = aMaskTexCoord; vMaskTexCoord = aMaskTexCoord;
vColorTexCoord = aColorTexCoord; vColorTexCoord = aColorTexCoord;
vOpacity = aOpacity;
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);
} }

View File

@ -38,12 +38,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord; in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){ vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r; float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage); return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
} }
vec4 sampleDestColor(){ vec4 sampleDestColor(){

View File

@ -40,12 +40,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord; in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){ vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r; float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage); return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
} }
vec4 sampleDestColor(){ vec4 sampleDestColor(){

View File

@ -38,12 +38,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord; in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){ vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r; float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage); return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
} }
vec4 sampleDestColor(){ vec4 sampleDestColor(){

View File

@ -38,12 +38,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord; in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){ vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r; float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage); return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
} }
vec4 sampleDestColor(){ vec4 sampleDestColor(){

View File

@ -45,12 +45,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord; in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){ vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r; float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage); return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
} }
vec4 sampleDestColor(){ vec4 sampleDestColor(){

View File

@ -38,12 +38,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord; in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){ vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r; float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage); return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
} }
vec4 sampleDestColor(){ vec4 sampleDestColor(){

View File

@ -23,19 +23,20 @@ struct main0_in
{ {
float2 vColorTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
}; };
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{ {
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage); return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
} }
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{ {
main0_out out = {}; main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
out.oFragColor = float4(srcRGBA.xyz * srcRGBA.w, srcRGBA.w); out.oFragColor = float4(srcRGBA.xyz * srcRGBA.w, srcRGBA.w);
return out; return out;
} }

View File

@ -14,6 +14,7 @@ struct main0_out
{ {
float2 vColorTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
float4 gl_Position [[position]]; float4 gl_Position [[position]];
}; };
@ -22,6 +23,7 @@ struct main0_in
int2 aTilePosition [[attribute(0)]]; int2 aTilePosition [[attribute(0)]];
float2 aColorTexCoord [[attribute(1)]]; float2 aColorTexCoord [[attribute(1)]];
float2 aMaskTexCoord [[attribute(2)]]; float2 aMaskTexCoord [[attribute(2)]];
float aOpacity [[attribute(3)]];
}; };
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
@ -30,6 +32,7 @@ vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer
float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize); float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize);
out.vMaskTexCoord = in.aMaskTexCoord; out.vMaskTexCoord = in.aMaskTexCoord;
out.vColorTexCoord = in.aColorTexCoord; out.vColorTexCoord = in.aColorTexCoord;
out.vOpacity = in.aOpacity;
out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0); out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0);
return out; return out;
} }

View File

@ -26,13 +26,14 @@ struct main0_in
{ {
float2 vColorTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
}; };
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{ {
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage); return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
} }
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr) float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -49,7 +50,7 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{ {
main0_out out = {}; main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 blended = abs(destRGBA.xyz - srcRGBA.xyz); float3 blended = abs(destRGBA.xyz - srcRGBA.xyz);
float4 param = destRGBA; float4 param = destRGBA;

View File

@ -27,13 +27,14 @@ struct main0_in
{ {
float2 vColorTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
}; };
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{ {
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage); return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
} }
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr) float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -50,57 +51,57 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{ {
main0_out out = {}; main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 _118; float3 _122;
if ((*spvDescriptorSet0.uBurn) == 0) if ((*spvDescriptorSet0.uBurn) == 0)
{ {
_118 = destRGBA.xyz; _122 = destRGBA.xyz;
} }
else else
{ {
_118 = float3(1.0) - destRGBA.xyz; _122 = float3(1.0) - destRGBA.xyz;
} }
float3 dest = _118; float3 dest = _122;
float3 _132; float3 _136;
if ((*spvDescriptorSet0.uBurn) == 0) if ((*spvDescriptorSet0.uBurn) == 0)
{ {
_132 = float3(1.0) - srcRGBA.xyz; _136 = float3(1.0) - srcRGBA.xyz;
} }
else else
{ {
_132 = srcRGBA.xyz; _136 = srcRGBA.xyz;
} }
float3 src = _132; float3 src = _136;
bool3 srcNonzero = src != float3(0.0); bool3 srcNonzero = src != float3(0.0);
float _153; float _157;
if (srcNonzero.x) if (srcNonzero.x)
{ {
_153 = dest.x / src.x; _157 = dest.x / src.x;
} }
else else
{ {
_153 = 1.0; _157 = 1.0;
} }
float _166; float _170;
if (srcNonzero.y) if (srcNonzero.y)
{ {
_166 = dest.y / src.y; _170 = dest.y / src.y;
} }
else else
{ {
_166 = 1.0; _170 = 1.0;
} }
float _179; float _183;
if (srcNonzero.z) if (srcNonzero.z)
{ {
_179 = dest.z / src.z; _183 = dest.z / src.z;
} }
else else
{ {
_179 = 1.0; _183 = 1.0;
} }
float3 blended = fast::min(float3(_153, _166, _179), float3(1.0)); float3 blended = fast::min(float3(_157, _170, _183), float3(1.0));
if ((*spvDescriptorSet0.uBurn) != 0) if ((*spvDescriptorSet0.uBurn) != 0)
{ {
blended = float3(1.0) - blended; blended = float3(1.0) - blended;

View File

@ -26,13 +26,14 @@ struct main0_in
{ {
float2 vColorTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
}; };
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{ {
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage); return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
} }
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr) float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -49,7 +50,7 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{ {
main0_out out = {}; main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 dest = destRGBA.xyz; float3 dest = destRGBA.xyz;
float3 src = srcRGBA.xyz; float3 src = srcRGBA.xyz;

View File

@ -27,6 +27,7 @@ struct main0_in
{ {
float2 vColorTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
}; };
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod() // Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
@ -36,11 +37,11 @@ Tx mod(Tx x, Ty y)
return x - y * floor(x / y); return x - y * floor(x / y);
} }
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{ {
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage); return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
} }
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr) float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -85,34 +86,34 @@ float3 convertRGBToHSL(thread const float3& rgb)
float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b) float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b)
{ {
float _125; float _129;
if (cond.x) if (cond.x)
{ {
_125 = a.x; _129 = a.x;
} }
else else
{ {
_125 = b.x; _129 = b.x;
} }
float _137; float _141;
if (cond.y) if (cond.y)
{ {
_137 = a.y; _141 = a.y;
} }
else else
{ {
_137 = b.y; _141 = b.y;
} }
float _149; float _153;
if (cond.z) if (cond.z)
{ {
_149 = a.z; _153 = a.z;
} }
else else
{ {
_149 = b.z; _153 = b.z;
} }
return float3(_125, _137, _149); return float3(_129, _141, _153);
} }
float3 convertHSLToRGB(thread const float3& hsl) float3 convertHSLToRGB(thread const float3& hsl)
@ -130,7 +131,7 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{ {
main0_out out = {}; main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 param = destRGBA.xyz; float3 param = destRGBA.xyz;
float3 destHSL = convertRGBToHSL(param); float3 destHSL = convertRGBToHSL(param);

View File

@ -27,13 +27,14 @@ struct main0_in
{ {
float2 vColorTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
}; };
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{ {
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage); return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
} }
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr) float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -44,34 +45,34 @@ float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSi
float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b) float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b)
{ {
float _118; float _122;
if (cond.x) if (cond.x)
{ {
_118 = a.x; _122 = a.x;
} }
else else
{ {
_118 = b.x; _122 = b.x;
} }
float _130; float _134;
if (cond.y) if (cond.y)
{ {
_130 = a.y; _134 = a.y;
} }
else else
{ {
_130 = b.y; _134 = b.y;
} }
float _142; float _146;
if (cond.z) if (cond.z)
{ {
_142 = a.z; _146 = a.z;
} }
else else
{ {
_142 = b.z; _146 = b.z;
} }
return float3(_118, _130, _142); return float3(_122, _134, _146);
} }
float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB)
@ -82,29 +83,29 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{ {
main0_out out = {}; main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
bool reversed = (*spvDescriptorSet0.uBlendMode) == 3; bool reversed = (*spvDescriptorSet0.uBlendMode) == 3;
float3 _167; float3 _171;
if (reversed) if (reversed)
{ {
_167 = srcRGBA.xyz; _171 = srcRGBA.xyz;
} }
else else
{ {
_167 = destRGBA.xyz; _171 = destRGBA.xyz;
} }
float3 src = _167; float3 src = _171;
float3 _178; float3 _182;
if (reversed) if (reversed)
{ {
_178 = destRGBA.xyz; _182 = destRGBA.xyz;
} }
else else
{ {
_178 = srcRGBA.xyz; _182 = srcRGBA.xyz;
} }
float3 dest = _178; float3 dest = _182;
float3 multiply = src * dest; float3 multiply = src * dest;
float3 blended; float3 blended;
if ((*spvDescriptorSet0.uBlendMode) == 0) if ((*spvDescriptorSet0.uBlendMode) == 0)

View File

@ -26,13 +26,14 @@ struct main0_in
{ {
float2 vColorTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
}; };
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{ {
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage); return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
} }
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr) float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -43,34 +44,34 @@ float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSi
float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b) float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b)
{ {
float _118; float _122;
if (cond.x) if (cond.x)
{ {
_118 = a.x; _122 = a.x;
} }
else else
{ {
_118 = b.x; _122 = b.x;
} }
float _130; float _134;
if (cond.y) if (cond.y)
{ {
_130 = a.y; _134 = a.y;
} }
else else
{ {
_130 = b.y; _134 = b.y;
} }
float _142; float _146;
if (cond.z) if (cond.z)
{ {
_142 = a.z; _146 = a.z;
} }
else else
{ {
_142 = b.z; _146 = b.z;
} }
return float3(_118, _130, _142); return float3(_122, _134, _146);
} }
float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB)
@ -81,7 +82,7 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{ {
main0_out out = {}; main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 dest = destRGBA.xyz; float3 dest = destRGBA.xyz;
float3 src = srcRGBA.xyz; float3 src = srcRGBA.xyz;

View File

@ -18,14 +18,17 @@ uniform vec2 uTileSize;
in ivec2 aTilePosition; in ivec2 aTilePosition;
in vec2 aColorTexCoord; in vec2 aColorTexCoord;
in vec2 aMaskTexCoord; in vec2 aMaskTexCoord;
in float aOpacity;
out vec2 vColorTexCoord; out vec2 vColorTexCoord;
out vec2 vMaskTexCoord; out vec2 vMaskTexCoord;
out float vOpacity;
void main() { void main() {
vec2 position = aTilePosition * uTileSize; vec2 position = aTilePosition * uTileSize;
vMaskTexCoord = aMaskTexCoord; vMaskTexCoord = aMaskTexCoord;
vColorTexCoord = aColorTexCoord; vColorTexCoord = aColorTexCoord;
vOpacity = aOpacity;
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);
} }

View File

@ -15,12 +15,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord; in vec2 vMaskTexCoord;
in float vOpacity;
// NB: This does not premultiply. // NB: This does not premultiply.
vec4 sampleSrcColor() { vec4 sampleSrcColor() {
float coverage = texture(uStencilTexture, vMaskTexCoord).r; float coverage = texture(uStencilTexture, vMaskTexCoord).r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA.rgb, srcRGBA.a * coverage); return vec4(srcRGBA.rgb, srcRGBA.a * coverage * vOpacity);
} }
vec4 sampleDestColor() { vec4 sampleDestColor() {

View File

@ -15,7 +15,6 @@ extern crate bitflags;
use hashbrown::HashMap; use hashbrown::HashMap;
use pathfinder_color::ColorU; use pathfinder_color::ColorU;
use pathfinder_content::effects::BlendMode;
use pathfinder_content::fill::FillRule; use pathfinder_content::fill::FillRule;
use pathfinder_content::outline::Outline; use pathfinder_content::outline::Outline;
use pathfinder_content::segment::{Segment, SegmentFlags}; use pathfinder_content::segment::{Segment, SegmentFlags};
@ -180,9 +179,9 @@ impl BuiltSVG {
} }
if let Some(clip_outline) = clip_outline { if let Some(clip_outline) = clip_outline {
let name = format!("ClipPath({})", node.id());
// FIXME(pcwalton): Is the winding fill rule correct to use? // FIXME(pcwalton): Is the winding fill rule correct to use?
let clip_path = ClipPath::new(clip_outline, FillRule::Winding, name); let mut clip_path = ClipPath::new(clip_outline);
clip_path.set_name(format!("ClipPath({})", node.id()));
let clip_path_id = self.scene.push_clip_path(clip_path); let clip_path_id = self.scene.push_clip_path(clip_path);
self.clip_paths.insert(node.id().to_owned(), clip_path_id); self.clip_paths.insert(node.id().to_owned(), clip_path_id);
} }
@ -232,16 +231,14 @@ impl BuiltSVG {
paint: &UsvgPaint, paint: &UsvgPaint,
opacity: Opacity, opacity: Opacity,
fill_rule: UsvgFillRule) { fill_rule: UsvgFillRule) {
let style = self.scene.push_paint(&Paint::from_svg_paint(paint, let style = self.scene.push_paint(&Paint::from_svg_paint(paint, &mut self.result_flags));
opacity,
&mut self.result_flags));
let fill_rule = FillRule::from_usvg_fill_rule(fill_rule); let fill_rule = FillRule::from_usvg_fill_rule(fill_rule);
self.scene.push_path(DrawPath::new(outline, let mut path = DrawPath::new(outline, style);
style, path.set_clip_path(state.clip_path);
state.clip_path, path.set_fill_rule(fill_rule);
fill_rule, path.set_name(name);
BlendMode::SrcOver, path.set_opacity((opacity.value() * 255.0) as u8);
name)); self.scene.push_path(path);
} }
} }
@ -288,17 +285,15 @@ impl Display for BuildResultFlags {
} }
trait PaintExt { trait PaintExt {
fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags) fn from_svg_paint(svg_paint: &UsvgPaint, result_flags: &mut BuildResultFlags) -> Self;
-> Self;
} }
impl PaintExt for Paint { impl PaintExt for Paint {
#[inline] #[inline]
fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags) fn from_svg_paint(svg_paint: &UsvgPaint, result_flags: &mut BuildResultFlags) -> Paint {
-> Paint {
// TODO(pcwalton): Support gradients. // TODO(pcwalton): Support gradients.
Paint::Color(match *svg_paint { Paint::Color(match *svg_paint {
UsvgPaint::Color(color) => ColorU::from_svg_color(color, opacity), UsvgPaint::Color(color) => ColorU::from_svg_color(color),
UsvgPaint::Link(_) => { UsvgPaint::Link(_) => {
// TODO(pcwalton) // TODO(pcwalton)
result_flags.insert(BuildResultFlags::UNSUPPORTED_LINK_PAINT); result_flags.insert(BuildResultFlags::UNSUPPORTED_LINK_PAINT);
@ -412,18 +407,13 @@ where
} }
trait ColorUExt { trait ColorUExt {
fn from_svg_color(svg_color: SvgColor, opacity: Opacity) -> Self; fn from_svg_color(svg_color: SvgColor) -> Self;
} }
impl ColorUExt for ColorU { impl ColorUExt for ColorU {
#[inline] #[inline]
fn from_svg_color(svg_color: SvgColor, opacity: Opacity) -> ColorU { fn from_svg_color(svg_color: SvgColor) -> ColorU {
ColorU { ColorU { r: svg_color.red, g: svg_color.green, b: svg_color.blue, a: !0 }
r: svg_color.red,
g: svg_color.green,
b: svg_color.blue,
a: (opacity.value() * 255.0).round() as u8,
}
} }
} }

View File

@ -10,7 +10,6 @@
use std::ops::Add; use std::ops::Add;
use pathfinder_color::{ColorF, ColorU}; use pathfinder_color::{ColorF, ColorU};
use pathfinder_content::effects::BlendMode;
use pathfinder_content::fill::FillRule; use pathfinder_content::fill::FillRule;
use pathfinder_content::outline::{Outline, Contour}; use pathfinder_content::outline::{Outline, Contour};
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
@ -196,14 +195,9 @@ pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) {
path = stroke_to_fill.into_outline(); path = stroke_to_fill.into_outline();
} }
scene.push_path(DrawPath::new( let mut path = DrawPath::new(path, paint_id);
path, path.set_fill_rule(FillRule::EvenOdd);
paint_id, scene.push_path(path);
None,
FillRule::EvenOdd,
BlendMode::SrcOver,
String::new()
));
} }
} }
} }

View File

@ -14,8 +14,6 @@ use font_kit::error::GlyphLoadingError;
use font_kit::hinting::HintingOptions; use font_kit::hinting::HintingOptions;
use font_kit::loader::Loader; use font_kit::loader::Loader;
use lyon_path::builder::{FlatPathBuilder, PathBuilder, Build}; use lyon_path::builder::{FlatPathBuilder, PathBuilder, Build};
use pathfinder_content::effects::BlendMode;
use pathfinder_content::fill::FillRule;
use pathfinder_content::outline::{Contour, Outline}; use pathfinder_content::outline::{Contour, Outline};
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
use pathfinder_geometry::transform2d::Transform2F; use pathfinder_geometry::transform2d::Transform2F;
@ -78,13 +76,7 @@ impl SceneExt for Scene {
outline = stroke_to_fill.into_outline(); outline = stroke_to_fill.into_outline();
} }
self.push_path(DrawPath::new(outline, self.push_path(DrawPath::new(outline, paint_id));
paint_id,
None,
FillRule::Winding,
BlendMode::SrcOver,
String::new()));
Ok(()) Ok(())
} }