Implement the HSL filters (called "non-separable blend modes" in the spec).
These cannot be implemented with the standard OpenGL blending functions, so we have to do them manually in a shader, which requires a good deal of machinery to create intermediate framebuffers and so forth.
This commit is contained in:
parent
67d12adb6c
commit
5421525eaa
|
@ -531,6 +531,10 @@ pub enum CompositeOperation {
|
||||||
Lighter,
|
Lighter,
|
||||||
Lighten,
|
Lighten,
|
||||||
Darken,
|
Darken,
|
||||||
|
Hue,
|
||||||
|
Saturation,
|
||||||
|
Color,
|
||||||
|
Luminosity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompositeOperation {
|
impl CompositeOperation {
|
||||||
|
@ -544,6 +548,10 @@ impl CompositeOperation {
|
||||||
CompositeOperation::Lighter => BlendMode::Lighter,
|
CompositeOperation::Lighter => BlendMode::Lighter,
|
||||||
CompositeOperation::Lighten => BlendMode::Lighten,
|
CompositeOperation::Lighten => BlendMode::Lighten,
|
||||||
CompositeOperation::Darken => BlendMode::Darken,
|
CompositeOperation::Darken => BlendMode::Darken,
|
||||||
|
CompositeOperation::Hue => BlendMode::Hue,
|
||||||
|
CompositeOperation::Saturation => BlendMode::Saturation,
|
||||||
|
CompositeOperation::Color => BlendMode::Color,
|
||||||
|
CompositeOperation::Luminosity => BlendMode::Luminosity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub enum CompositeOp {
|
||||||
SrcOver,
|
SrcOver,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Blend modes that can be applied to individual paths without creating layers for them.
|
/// Blend modes that can be applied to individual paths.
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub enum BlendMode {
|
pub enum BlendMode {
|
||||||
Clear,
|
Clear,
|
||||||
|
@ -73,6 +73,10 @@ pub enum BlendMode {
|
||||||
Lighter,
|
Lighter,
|
||||||
Lighten,
|
Lighten,
|
||||||
Darken,
|
Darken,
|
||||||
|
Hue,
|
||||||
|
Saturation,
|
||||||
|
Color,
|
||||||
|
Luminosity,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
@ -105,7 +109,11 @@ impl BlendMode {
|
||||||
BlendMode::Xor |
|
BlendMode::Xor |
|
||||||
BlendMode::Lighter |
|
BlendMode::Lighter |
|
||||||
BlendMode::Lighten |
|
BlendMode::Lighten |
|
||||||
BlendMode::Darken => false,
|
BlendMode::Darken |
|
||||||
|
BlendMode::Hue |
|
||||||
|
BlendMode::Saturation |
|
||||||
|
BlendMode::Color |
|
||||||
|
BlendMode::Luminosity => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin, Path2D};
|
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D};
|
||||||
|
use pathfinder_canvas::{FillStyle, LineJoin, Path2D};
|
||||||
use pathfinder_color::{ColorF, ColorU};
|
use pathfinder_color::{ColorF, ColorU};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::gradient::{ColorStop, Gradient};
|
use pathfinder_content::gradient::{ColorStop, Gradient};
|
||||||
|
|
|
@ -145,6 +145,9 @@ impl GLDevice {
|
||||||
UniformData::Float(value) => {
|
UniformData::Float(value) => {
|
||||||
gl::Uniform1f(uniform.location, value); ck();
|
gl::Uniform1f(uniform.location, value); ck();
|
||||||
}
|
}
|
||||||
|
UniformData::IVec3(value) => {
|
||||||
|
gl::Uniform3i(uniform.location, value[0], value[1], value[2]); ck();
|
||||||
|
}
|
||||||
UniformData::Int(value) => {
|
UniformData::Int(value) => {
|
||||||
gl::Uniform1i(uniform.location, value); ck();
|
gl::Uniform1i(uniform.location, value); ck();
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,7 @@ pub enum ShaderKind {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum UniformData {
|
pub enum UniformData {
|
||||||
Float(f32),
|
Float(f32),
|
||||||
|
IVec3([i32; 3]),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
Mat2(F32x4),
|
Mat2(F32x4),
|
||||||
Mat4([F32x4; 4]),
|
Mat4([F32x4; 4]),
|
||||||
|
|
|
@ -873,6 +873,11 @@ impl MetalDevice {
|
||||||
UniformData::Float(value) => {
|
UniformData::Float(value) => {
|
||||||
uniform_buffer_data.write_f32::<NativeEndian>(value).unwrap()
|
uniform_buffer_data.write_f32::<NativeEndian>(value).unwrap()
|
||||||
}
|
}
|
||||||
|
UniformData::IVec3(values) => {
|
||||||
|
uniform_buffer_data.write_i32::<NativeEndian>(values[0]).unwrap();
|
||||||
|
uniform_buffer_data.write_i32::<NativeEndian>(values[1]).unwrap();
|
||||||
|
uniform_buffer_data.write_i32::<NativeEndian>(values[2]).unwrap();
|
||||||
|
}
|
||||||
UniformData::Int(value) => {
|
UniformData::Int(value) => {
|
||||||
uniform_buffer_data.write_i32::<NativeEndian>(value).unwrap()
|
uniform_buffer_data.write_i32::<NativeEndian>(value).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -1251,6 +1256,9 @@ impl UniformDataExt for UniformData {
|
||||||
UniformData::Float(ref data) => {
|
UniformData::Float(ref data) => {
|
||||||
Some(slice::from_raw_parts(data as *const f32 as *const u8, 4 * 1))
|
Some(slice::from_raw_parts(data as *const f32 as *const u8, 4 * 1))
|
||||||
}
|
}
|
||||||
|
UniformData::IVec3(ref data) => {
|
||||||
|
Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 3))
|
||||||
|
}
|
||||||
UniformData::Int(ref data) => {
|
UniformData::Int(ref data) => {
|
||||||
Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 1))
|
Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 1))
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
//! Packs data onto the GPU.
|
//! Packs data onto the GPU.
|
||||||
|
|
||||||
use crate::concurrent::executor::Executor;
|
use crate::concurrent::executor::Executor;
|
||||||
use crate::gpu::renderer::MASK_TILES_ACROSS;
|
use crate::gpu::renderer::{BlendModeProgram, MASK_TILES_ACROSS};
|
||||||
use crate::gpu_data::{AlphaTile, AlphaTileVertex, FillBatchPrimitive, MaskTile, MaskTileVertex};
|
use crate::gpu_data::{AlphaTile, AlphaTileVertex, FillBatchPrimitive, MaskTile, MaskTileVertex};
|
||||||
use crate::gpu_data::{PaintPageId, RenderCommand, SolidTileBatch, TileObjectPrimitive};
|
use crate::gpu_data::{PaintPageId, RenderCommand, SolidTileBatch, TileObjectPrimitive};
|
||||||
use crate::options::{PreparedBuildOptions, RenderCommandListener};
|
use crate::options::{PreparedBuildOptions, RenderCommandListener};
|
||||||
|
@ -90,13 +90,22 @@ impl<'a> SceneBuilder<'a> {
|
||||||
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.
|
||||||
let bounding_quad = self.built_options.bounding_quad();
|
let bounding_quad = self.built_options.bounding_quad();
|
||||||
|
|
||||||
let clip_path_count = self.scene.clip_paths.len();
|
let clip_path_count = self.scene.clip_paths.len();
|
||||||
let draw_path_count = self.scene.paths.len();
|
let draw_path_count = self.scene.paths.len();
|
||||||
let total_path_count = clip_path_count + draw_path_count;
|
let total_path_count = clip_path_count + draw_path_count;
|
||||||
self.listener.send(RenderCommand::Start { bounding_quad, path_count: total_path_count });
|
|
||||||
|
|
||||||
|
let needs_readable_framebuffer = self.needs_readable_framebuffer();
|
||||||
|
|
||||||
|
self.listener.send(RenderCommand::Start {
|
||||||
|
bounding_quad,
|
||||||
|
path_count: total_path_count,
|
||||||
|
needs_readable_framebuffer,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build paint data.
|
||||||
let PaintInfo {
|
let PaintInfo {
|
||||||
data: paint_data,
|
data: paint_data,
|
||||||
metadata: paint_metadata,
|
metadata: paint_metadata,
|
||||||
|
@ -249,7 +258,8 @@ impl<'a> SceneBuilder<'a> {
|
||||||
culled_tiles.push_mask_tiles(&built_draw_path.path);
|
culled_tiles.push_mask_tiles(&built_draw_path.path);
|
||||||
|
|
||||||
// Create a new `DrawAlphaTiles` display item if we don't have one or if we have to
|
// Create a new `DrawAlphaTiles` display item if we don't have one or if we have to
|
||||||
// break a batch due to blend mode or paint page.
|
// break a batch due to blend mode or paint page. Note that every path with a blend
|
||||||
|
// mode that requires a readable framebuffer needs its own batch.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): If we really wanted to, we could use tile maps to avoid batch
|
// TODO(pcwalton): If we really wanted to, we could use tile maps to avoid batch
|
||||||
// breaks in some cases…
|
// breaks in some cases…
|
||||||
|
@ -259,7 +269,9 @@ impl<'a> SceneBuilder<'a> {
|
||||||
paint_page,
|
paint_page,
|
||||||
blend_mode
|
blend_mode
|
||||||
}) if paint_page == built_draw_path.paint_page &&
|
}) if paint_page == built_draw_path.paint_page &&
|
||||||
blend_mode == built_draw_path.blend_mode => {}
|
blend_mode == built_draw_path.blend_mode &&
|
||||||
|
!BlendModeProgram::from_blend_mode(
|
||||||
|
built_draw_path.blend_mode).needs_readable_framebuffer() => {}
|
||||||
_ => {
|
_ => {
|
||||||
culled_tiles.display_list.push(CulledDisplayItem::DrawAlphaTiles {
|
culled_tiles.display_list.push(CulledDisplayItem::DrawAlphaTiles {
|
||||||
tiles: vec![],
|
tiles: vec![],
|
||||||
|
@ -377,6 +389,30 @@ impl<'a> SceneBuilder<'a> {
|
||||||
// FIXME(pcwalton): Check for overflow!
|
// FIXME(pcwalton): Check for overflow!
|
||||||
self.next_mask_tile_index.fetch_add(1, Ordering::Relaxed) as u16
|
self.next_mask_tile_index.fetch_add(1, Ordering::Relaxed) as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn needs_readable_framebuffer(&self) -> bool {
|
||||||
|
let mut framebuffer_nesting = 0;
|
||||||
|
for display_item in &self.scene.display_list {
|
||||||
|
match *display_item {
|
||||||
|
DisplayItem::DrawRenderTarget { .. } => {}
|
||||||
|
DisplayItem::PushRenderTarget(_) => framebuffer_nesting += 1,
|
||||||
|
DisplayItem::PopRenderTarget => framebuffer_nesting -= 1,
|
||||||
|
DisplayItem::DrawPaths { start_index, end_index } => {
|
||||||
|
if framebuffer_nesting > 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for path_index in start_index..end_index {
|
||||||
|
let blend_mode = self.scene.paths[path_index as usize].blend_mode();
|
||||||
|
let blend_mode_program = BlendModeProgram::from_blend_mode(blend_mode);
|
||||||
|
if blend_mode_program.needs_readable_framebuffer() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltPath {
|
impl BuiltPath {
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
|
|
||||||
use crate::gpu::debug::DebugUIPresenter;
|
use crate::gpu::debug::DebugUIPresenter;
|
||||||
use crate::gpu::options::{DestFramebuffer, RendererOptions};
|
use crate::gpu::options::{DestFramebuffer, RendererOptions};
|
||||||
use crate::gpu::shaders::{AlphaTileProgram, AlphaTileVertexArray, FillProgram, FillVertexArray};
|
use crate::gpu::shaders::{AlphaTileHSLProgram, AlphaTileProgram, AlphaTileVertexArray};
|
||||||
|
use crate::gpu::shaders::{CopyTileProgram, CopyTileVertexArray, FillProgram, FillVertexArray};
|
||||||
use crate::gpu::shaders::{FilterBasicProgram, FilterBasicVertexArray, FilterTextProgram};
|
use crate::gpu::shaders::{FilterBasicProgram, FilterBasicVertexArray, FilterTextProgram};
|
||||||
use crate::gpu::shaders::{FilterTextVertexArray, MAX_FILLS_PER_BATCH, MaskTileProgram};
|
use crate::gpu::shaders::{FilterTextVertexArray, MAX_FILLS_PER_BATCH, MaskTileProgram};
|
||||||
use crate::gpu::shaders::{MaskTileVertexArray, ReprojectionProgram, ReprojectionVertexArray};
|
use crate::gpu::shaders::{MaskTileVertexArray, ReprojectionProgram, ReprojectionVertexArray};
|
||||||
|
@ -18,6 +19,7 @@ use crate::gpu::shaders::{SolidTileProgram, SolidTileVertexArray};
|
||||||
use crate::gpu::shaders::{StencilProgram, StencilVertexArray};
|
use crate::gpu::shaders::{StencilProgram, StencilVertexArray};
|
||||||
use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, PaintData, PaintPageContents};
|
use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, PaintData, PaintPageContents};
|
||||||
use crate::gpu_data::{PaintPageId, RenderCommand, SolidTileVertex};
|
use crate::gpu_data::{PaintPageId, RenderCommand, SolidTileVertex};
|
||||||
|
use crate::options::BoundingQuad;
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use pathfinder_color::{self as color, ColorF};
|
use pathfinder_color::{self as color, ColorF};
|
||||||
use pathfinder_content::effects::{BlendMode, CompositeOp, DefringingKernel, Effects, Filter};
|
use pathfinder_content::effects::{BlendMode, CompositeOp, DefringingKernel, Effects, Filter};
|
||||||
|
@ -51,6 +53,9 @@ const TEXTURE_CACHE_SIZE: usize = 8;
|
||||||
const MASK_FRAMEBUFFER_WIDTH: i32 = TILE_WIDTH as i32 * MASK_TILES_ACROSS as i32;
|
const MASK_FRAMEBUFFER_WIDTH: i32 = TILE_WIDTH as i32 * MASK_TILES_ACROSS as i32;
|
||||||
const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * MASK_TILES_DOWN as i32;
|
const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * MASK_TILES_DOWN as i32;
|
||||||
|
|
||||||
|
const BLEND_TERM_DEST: i32 = 0;
|
||||||
|
const BLEND_TERM_SRC: i32 = 1;
|
||||||
|
|
||||||
pub struct Renderer<D>
|
pub struct Renderer<D>
|
||||||
where
|
where
|
||||||
D: Device,
|
D: Device,
|
||||||
|
@ -64,13 +69,18 @@ where
|
||||||
fill_program: FillProgram<D>,
|
fill_program: FillProgram<D>,
|
||||||
mask_winding_tile_program: MaskTileProgram<D>,
|
mask_winding_tile_program: MaskTileProgram<D>,
|
||||||
mask_evenodd_tile_program: MaskTileProgram<D>,
|
mask_evenodd_tile_program: MaskTileProgram<D>,
|
||||||
|
copy_tile_program: CopyTileProgram<D>,
|
||||||
solid_tile_program: SolidTileProgram<D>,
|
solid_tile_program: SolidTileProgram<D>,
|
||||||
alpha_tile_program: AlphaTileProgram<D>,
|
alpha_tile_program: AlphaTileProgram<D>,
|
||||||
|
alpha_tile_hsl_program: AlphaTileHSLProgram<D>,
|
||||||
mask_winding_tile_vertex_array: MaskTileVertexArray<D>,
|
mask_winding_tile_vertex_array: MaskTileVertexArray<D>,
|
||||||
mask_evenodd_tile_vertex_array: MaskTileVertexArray<D>,
|
mask_evenodd_tile_vertex_array: MaskTileVertexArray<D>,
|
||||||
|
copy_tile_vertex_array: CopyTileVertexArray<D>,
|
||||||
solid_tile_vertex_array: SolidTileVertexArray<D>,
|
solid_tile_vertex_array: SolidTileVertexArray<D>,
|
||||||
alpha_tile_vertex_array: AlphaTileVertexArray<D>,
|
alpha_tile_vertex_array: AlphaTileVertexArray<D>,
|
||||||
|
alpha_tile_hsl_vertex_array: AlphaTileVertexArray<D>,
|
||||||
area_lut_texture: D::Texture,
|
area_lut_texture: D::Texture,
|
||||||
|
alpha_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,
|
||||||
quads_vertex_indices_buffer: D::Buffer,
|
quads_vertex_indices_buffer: D::Buffer,
|
||||||
|
@ -78,6 +88,8 @@ where
|
||||||
fill_vertex_array: FillVertexArray<D>,
|
fill_vertex_array: FillVertexArray<D>,
|
||||||
fill_framebuffer: D::Framebuffer,
|
fill_framebuffer: D::Framebuffer,
|
||||||
mask_framebuffer: D::Framebuffer,
|
mask_framebuffer: D::Framebuffer,
|
||||||
|
dest_blend_framebuffer: D::Framebuffer,
|
||||||
|
intermediate_dest_framebuffer: D::Framebuffer,
|
||||||
paint_textures: Vec<PaintTexture<D>>,
|
paint_textures: Vec<PaintTexture<D>>,
|
||||||
render_targets: Vec<RenderTargetInfo<D>>,
|
render_targets: Vec<RenderTargetInfo<D>>,
|
||||||
render_target_stack: Vec<RenderTargetId>,
|
render_target_stack: Vec<RenderTargetId>,
|
||||||
|
@ -115,7 +127,7 @@ where
|
||||||
pub debug_ui_presenter: DebugUIPresenter<D>,
|
pub debug_ui_presenter: DebugUIPresenter<D>,
|
||||||
|
|
||||||
// Extra info
|
// Extra info
|
||||||
use_depth: bool,
|
flags: RendererFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> Renderer<D>
|
impl<D> Renderer<D>
|
||||||
|
@ -134,8 +146,10 @@ where
|
||||||
let mask_evenodd_tile_program = MaskTileProgram::new(FillRule::EvenOdd,
|
let mask_evenodd_tile_program = MaskTileProgram::new(FillRule::EvenOdd,
|
||||||
&device,
|
&device,
|
||||||
resources);
|
resources);
|
||||||
|
let copy_tile_program = CopyTileProgram::new(&device, resources);
|
||||||
let solid_tile_program = SolidTileProgram::new(&device, resources);
|
let solid_tile_program = SolidTileProgram::new(&device, resources);
|
||||||
let alpha_tile_program = AlphaTileProgram::new(&device, resources);
|
let alpha_tile_program = AlphaTileProgram::new(&device, resources);
|
||||||
|
let alpha_tile_hsl_program = AlphaTileHSLProgram::new(&device, resources);
|
||||||
let filter_basic_program = FilterBasicProgram::new(&device, resources);
|
let filter_basic_program = FilterBasicProgram::new(&device, resources);
|
||||||
let filter_text_program = FilterTextProgram::new(&device, resources);
|
let filter_text_program = FilterTextProgram::new(&device, resources);
|
||||||
let stencil_program = StencilProgram::new(&device, resources);
|
let stencil_program = StencilProgram::new(&device, resources);
|
||||||
|
@ -144,6 +158,7 @@ where
|
||||||
let area_lut_texture = device.create_texture_from_png(resources, "area-lut");
|
let area_lut_texture = device.create_texture_from_png(resources, "area-lut");
|
||||||
let gamma_lut_texture = device.create_texture_from_png(resources, "gamma-lut");
|
let gamma_lut_texture = device.create_texture_from_png(resources, "gamma-lut");
|
||||||
|
|
||||||
|
let alpha_tile_vertex_buffer = device.create_buffer();
|
||||||
let quad_vertex_positions_buffer = device.create_buffer();
|
let quad_vertex_positions_buffer = device.create_buffer();
|
||||||
device.allocate_buffer(
|
device.allocate_buffer(
|
||||||
&quad_vertex_positions_buffer,
|
&quad_vertex_positions_buffer,
|
||||||
|
@ -176,9 +191,22 @@ where
|
||||||
&mask_evenodd_tile_program,
|
&mask_evenodd_tile_program,
|
||||||
&quads_vertex_indices_buffer,
|
&quads_vertex_indices_buffer,
|
||||||
);
|
);
|
||||||
|
let copy_tile_vertex_array = CopyTileVertexArray::new(
|
||||||
|
&device,
|
||||||
|
©_tile_program,
|
||||||
|
&alpha_tile_vertex_buffer,
|
||||||
|
&quads_vertex_indices_buffer,
|
||||||
|
);
|
||||||
let alpha_tile_vertex_array = AlphaTileVertexArray::new(
|
let alpha_tile_vertex_array = AlphaTileVertexArray::new(
|
||||||
&device,
|
&device,
|
||||||
&alpha_tile_program,
|
&alpha_tile_program,
|
||||||
|
&alpha_tile_vertex_buffer,
|
||||||
|
&quads_vertex_indices_buffer,
|
||||||
|
);
|
||||||
|
let alpha_tile_hsl_vertex_array = AlphaTileVertexArray::new(
|
||||||
|
&device,
|
||||||
|
&alpha_tile_hsl_program.alpha_tile_program,
|
||||||
|
&alpha_tile_vertex_buffer,
|
||||||
&quads_vertex_indices_buffer,
|
&quads_vertex_indices_buffer,
|
||||||
);
|
);
|
||||||
let solid_tile_vertex_array = SolidTileVertexArray::new(
|
let solid_tile_vertex_array = SolidTileVertexArray::new(
|
||||||
|
@ -218,12 +246,17 @@ where
|
||||||
device.create_texture(TextureFormat::R8, mask_framebuffer_size);
|
device.create_texture(TextureFormat::R8, mask_framebuffer_size);
|
||||||
let mask_framebuffer = device.create_framebuffer(mask_framebuffer_texture);
|
let mask_framebuffer = device.create_framebuffer(mask_framebuffer_texture);
|
||||||
|
|
||||||
|
let window_size = dest_framebuffer.window_size(&device);
|
||||||
|
let dest_blend_texture = device.create_texture(TextureFormat::RGBA8, window_size);
|
||||||
|
let dest_blend_framebuffer = device.create_framebuffer(dest_blend_texture);
|
||||||
|
let intermediate_dest_texture = device.create_texture(TextureFormat::RGBA8, window_size);
|
||||||
|
let intermediate_dest_framebuffer = device.create_framebuffer(intermediate_dest_texture);
|
||||||
|
|
||||||
let clear_paint_texture =
|
let clear_paint_texture =
|
||||||
device.create_texture_from_data(TextureFormat::RGBA8,
|
device.create_texture_from_data(TextureFormat::RGBA8,
|
||||||
Vector2I::splat(1),
|
Vector2I::splat(1),
|
||||||
TextureDataRef::U8(&[0, 0, 0, 255]));
|
TextureDataRef::U8(&[0, 0, 0, 255]));
|
||||||
|
|
||||||
let window_size = dest_framebuffer.window_size(&device);
|
|
||||||
let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size);
|
let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size);
|
||||||
|
|
||||||
Renderer {
|
Renderer {
|
||||||
|
@ -234,13 +267,18 @@ where
|
||||||
fill_program,
|
fill_program,
|
||||||
mask_winding_tile_program,
|
mask_winding_tile_program,
|
||||||
mask_evenodd_tile_program,
|
mask_evenodd_tile_program,
|
||||||
|
copy_tile_program,
|
||||||
solid_tile_program,
|
solid_tile_program,
|
||||||
alpha_tile_program,
|
alpha_tile_program,
|
||||||
|
alpha_tile_hsl_program,
|
||||||
mask_winding_tile_vertex_array,
|
mask_winding_tile_vertex_array,
|
||||||
mask_evenodd_tile_vertex_array,
|
mask_evenodd_tile_vertex_array,
|
||||||
solid_tile_vertex_array,
|
solid_tile_vertex_array,
|
||||||
alpha_tile_vertex_array,
|
alpha_tile_vertex_array,
|
||||||
|
copy_tile_vertex_array,
|
||||||
|
alpha_tile_hsl_vertex_array,
|
||||||
area_lut_texture,
|
area_lut_texture,
|
||||||
|
alpha_tile_vertex_buffer,
|
||||||
quad_vertex_positions_buffer,
|
quad_vertex_positions_buffer,
|
||||||
quad_vertex_indices_buffer,
|
quad_vertex_indices_buffer,
|
||||||
quads_vertex_indices_buffer,
|
quads_vertex_indices_buffer,
|
||||||
|
@ -248,6 +286,8 @@ where
|
||||||
fill_vertex_array,
|
fill_vertex_array,
|
||||||
fill_framebuffer,
|
fill_framebuffer,
|
||||||
mask_framebuffer,
|
mask_framebuffer,
|
||||||
|
dest_blend_framebuffer,
|
||||||
|
intermediate_dest_framebuffer,
|
||||||
paint_textures: vec![],
|
paint_textures: vec![],
|
||||||
render_targets: vec![],
|
render_targets: vec![],
|
||||||
render_target_stack: vec![],
|
render_target_stack: vec![],
|
||||||
|
@ -275,7 +315,7 @@ where
|
||||||
buffered_fills: vec![],
|
buffered_fills: vec![],
|
||||||
texture_cache: TextureCache::new(),
|
texture_cache: TextureCache::new(),
|
||||||
|
|
||||||
use_depth: false,
|
flags: RendererFlags::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,11 +327,8 @@ where
|
||||||
|
|
||||||
pub fn render_command(&mut self, command: &RenderCommand) {
|
pub fn render_command(&mut self, command: &RenderCommand) {
|
||||||
match *command {
|
match *command {
|
||||||
RenderCommand::Start { bounding_quad, path_count } => {
|
RenderCommand::Start { bounding_quad, path_count, needs_readable_framebuffer } => {
|
||||||
if self.use_depth {
|
self.start_rendering(bounding_quad, path_count, needs_readable_framebuffer);
|
||||||
self.draw_stencil(&bounding_quad);
|
|
||||||
}
|
|
||||||
self.stats.path_count = path_count;
|
|
||||||
}
|
}
|
||||||
RenderCommand::AddPaintData(ref paint_data) => self.upload_paint_data(paint_data),
|
RenderCommand::AddPaintData(ref paint_data) => self.upload_paint_data(paint_data),
|
||||||
RenderCommand::AddFills(ref fills) => self.add_fills(fills),
|
RenderCommand::AddFills(ref fills) => self.add_fills(fills),
|
||||||
|
@ -328,12 +365,31 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_scene(&mut self) {
|
pub fn end_scene(&mut self) {
|
||||||
|
self.blit_intermediate_dest_framebuffer_if_necessary();
|
||||||
|
|
||||||
self.end_composite_timer_query();
|
self.end_composite_timer_query();
|
||||||
self.pending_timers.push_back(mem::replace(&mut self.current_timers, RenderTimers::new()));
|
self.pending_timers.push_back(mem::replace(&mut self.current_timers, RenderTimers::new()));
|
||||||
|
|
||||||
self.device.end_commands();
|
self.device.end_commands();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_rendering(&mut self,
|
||||||
|
bounding_quad: BoundingQuad,
|
||||||
|
path_count: usize,
|
||||||
|
mut needs_readable_framebuffer: bool) {
|
||||||
|
if let DestFramebuffer::Other(_) = self.dest_framebuffer {
|
||||||
|
needs_readable_framebuffer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.flags.contains(RendererFlags::USE_DEPTH) {
|
||||||
|
self.draw_stencil(&bounding_quad);
|
||||||
|
}
|
||||||
|
self.stats.path_count = path_count;
|
||||||
|
|
||||||
|
self.flags.set(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED,
|
||||||
|
needs_readable_framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw_debug_ui(&self) {
|
pub fn draw_debug_ui(&self) {
|
||||||
self.debug_ui_presenter.draw(&self.device);
|
self.debug_ui_presenter.draw(&self.device);
|
||||||
}
|
}
|
||||||
|
@ -392,12 +448,12 @@ where
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable_depth(&mut self) {
|
pub fn disable_depth(&mut self) {
|
||||||
self.use_depth = false;
|
self.flags.remove(RendererFlags::USE_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn enable_depth(&mut self) {
|
pub fn enable_depth(&mut self) {
|
||||||
self.use_depth = true;
|
self.flags.insert(RendererFlags::USE_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -481,12 +537,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_alpha_tiles(&mut self, alpha_tiles: &[AlphaTile]) {
|
fn upload_alpha_tiles(&mut self, alpha_tiles: &[AlphaTile]) {
|
||||||
self.device.allocate_buffer(
|
self.device.allocate_buffer(&self.alpha_tile_vertex_buffer,
|
||||||
&self.alpha_tile_vertex_array.vertex_buffer,
|
|
||||||
BufferData::Memory(&alpha_tiles),
|
BufferData::Memory(&alpha_tiles),
|
||||||
BufferTarget::Vertex,
|
BufferTarget::Vertex,
|
||||||
BufferUploadMode::Dynamic,
|
BufferUploadMode::Dynamic);
|
||||||
);
|
|
||||||
self.ensure_index_buffer(alpha_tiles.len());
|
self.ensure_index_buffer(alpha_tiles.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,18 +699,32 @@ where
|
||||||
tile_count: u32,
|
tile_count: u32,
|
||||||
paint_page: PaintPageId,
|
paint_page: PaintPageId,
|
||||||
blend_mode: BlendMode) {
|
blend_mode: BlendMode) {
|
||||||
|
let blend_mode_program = BlendModeProgram::from_blend_mode(blend_mode);
|
||||||
|
if blend_mode_program.needs_readable_framebuffer() {
|
||||||
|
self.copy_alpha_tiles_to_dest_blend_texture(tile_count);
|
||||||
|
}
|
||||||
|
|
||||||
let clear_color = self.clear_color_for_draw_operation();
|
let clear_color = self.clear_color_for_draw_operation();
|
||||||
|
|
||||||
|
let (alpha_tile_program, alpha_tile_vertex_array) = match blend_mode_program {
|
||||||
|
BlendModeProgram::Regular => (&self.alpha_tile_program, &self.alpha_tile_vertex_array),
|
||||||
|
BlendModeProgram::HSL => {
|
||||||
|
(&self.alpha_tile_hsl_program.alpha_tile_program,
|
||||||
|
&self.alpha_tile_hsl_vertex_array)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let draw_viewport = self.draw_viewport();
|
||||||
|
|
||||||
let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)];
|
let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)];
|
||||||
let mut uniforms = vec![
|
let mut uniforms = vec![
|
||||||
(&self.alpha_tile_program.transform_uniform,
|
(&alpha_tile_program.transform_uniform,
|
||||||
UniformData::Mat4(self.tile_transform().to_columns())),
|
UniformData::Mat4(self.tile_transform().to_columns())),
|
||||||
(&self.alpha_tile_program.tile_size_uniform,
|
(&alpha_tile_program.tile_size_uniform,
|
||||||
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
||||||
(&self.alpha_tile_program.stencil_texture_uniform, UniformData::TextureUnit(0)),
|
(&alpha_tile_program.stencil_texture_uniform, UniformData::TextureUnit(0)),
|
||||||
(&self.alpha_tile_program.stencil_texture_size_uniform,
|
(&alpha_tile_program.framebuffer_size_uniform,
|
||||||
UniformData::Vec2(F32x2::new(MASK_FRAMEBUFFER_WIDTH as f32,
|
UniformData::Vec2(draw_viewport.size().to_f32().0)),
|
||||||
MASK_FRAMEBUFFER_HEIGHT as f32))),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let paint_texture = match blend_mode {
|
let paint_texture = match blend_mode {
|
||||||
|
@ -671,22 +739,24 @@ where
|
||||||
textures.push(paint_texture);
|
textures.push(paint_texture);
|
||||||
uniforms.push((&self.alpha_tile_program.paint_texture_uniform,
|
uniforms.push((&self.alpha_tile_program.paint_texture_uniform,
|
||||||
UniformData::TextureUnit(1)));
|
UniformData::TextureUnit(1)));
|
||||||
uniforms.push((&self.alpha_tile_program.paint_texture_size_uniform,
|
|
||||||
UniformData::Vec2(self.device
|
match blend_mode_program {
|
||||||
.texture_size(paint_texture)
|
BlendModeProgram::Regular => {}
|
||||||
.0
|
BlendModeProgram::HSL => {
|
||||||
.to_f32x2())));
|
self.set_uniforms_for_hsl_blend_mode(&mut textures, &mut uniforms, blend_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.device.draw_elements(tile_count * 6, &RenderState {
|
self.device.draw_elements(tile_count * 6, &RenderState {
|
||||||
target: &self.draw_render_target(),
|
target: &self.draw_render_target(),
|
||||||
program: &self.alpha_tile_program.program,
|
program: &alpha_tile_program.program,
|
||||||
vertex_array: &self.alpha_tile_vertex_array.vertex_array,
|
vertex_array: &alpha_tile_vertex_array.vertex_array,
|
||||||
primitive: Primitive::Triangles,
|
primitive: Primitive::Triangles,
|
||||||
textures: &textures,
|
textures: &textures,
|
||||||
uniforms: &uniforms,
|
uniforms: &uniforms,
|
||||||
viewport: self.draw_viewport(),
|
viewport: draw_viewport,
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
blend: Some(blend_mode.to_blend_state()),
|
blend: blend_mode.to_blend_state(),
|
||||||
stencil: self.stencil_state(),
|
stencil: self.stencil_state(),
|
||||||
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
|
@ -696,6 +766,60 @@ where
|
||||||
self.preserve_draw_framebuffer();
|
self.preserve_draw_framebuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_uniforms_for_hsl_blend_mode<'a>(&'a self,
|
||||||
|
textures: &mut Vec<&'a D::Texture>,
|
||||||
|
uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
|
||||||
|
blend_mode: BlendMode) {
|
||||||
|
let hsl_terms = match blend_mode {
|
||||||
|
BlendMode::Hue => [BLEND_TERM_SRC, BLEND_TERM_DEST, BLEND_TERM_DEST],
|
||||||
|
BlendMode::Saturation => [BLEND_TERM_DEST, BLEND_TERM_SRC, BLEND_TERM_DEST],
|
||||||
|
BlendMode::Luminosity => [BLEND_TERM_DEST, BLEND_TERM_DEST, BLEND_TERM_SRC ],
|
||||||
|
BlendMode::Color => [BLEND_TERM_SRC, BLEND_TERM_SRC, BLEND_TERM_DEST],
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
|
||||||
|
uniforms.push((&self.alpha_tile_hsl_program.dest_uniform, UniformData::TextureUnit(2)));
|
||||||
|
uniforms.push((&self.alpha_tile_hsl_program.blend_hsl_uniform,
|
||||||
|
UniformData::IVec3(hsl_terms)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_alpha_tiles_to_dest_blend_texture(&mut self, tile_count: u32) {
|
||||||
|
let mut textures = vec![];
|
||||||
|
let mut uniforms = vec![
|
||||||
|
(&self.copy_tile_program.transform_uniform,
|
||||||
|
UniformData::Mat4(self.tile_transform().to_columns())),
|
||||||
|
(&self.copy_tile_program.tile_size_uniform,
|
||||||
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
||||||
|
];
|
||||||
|
|
||||||
|
let draw_framebuffer = match self.draw_render_target() {
|
||||||
|
RenderTarget::Framebuffer(framebuffer) => framebuffer,
|
||||||
|
RenderTarget::Default => panic!("Can't copy alpha tiles from default framebuffer!"),
|
||||||
|
};
|
||||||
|
let draw_texture = self.device.framebuffer_texture(&draw_framebuffer);
|
||||||
|
|
||||||
|
textures.push(draw_texture);
|
||||||
|
uniforms.push((&self.copy_tile_program.src_uniform, UniformData::TextureUnit(0)));
|
||||||
|
|
||||||
|
self.device.draw_elements(tile_count * 6, &RenderState {
|
||||||
|
target: &RenderTarget::Framebuffer(&self.dest_blend_framebuffer),
|
||||||
|
program: &self.copy_tile_program.program,
|
||||||
|
vertex_array: &self.copy_tile_vertex_array.vertex_array,
|
||||||
|
primitive: Primitive::Triangles,
|
||||||
|
textures: &textures,
|
||||||
|
uniforms: &uniforms,
|
||||||
|
viewport: self.draw_viewport(),
|
||||||
|
options: RenderOptions {
|
||||||
|
clear_ops: ClearOps {
|
||||||
|
color: Some(ColorF::transparent_black()),
|
||||||
|
..ClearOps::default()
|
||||||
|
},
|
||||||
|
..RenderOptions::default()
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_solid_tiles(&mut self, tile_count: u32, paint_page: PaintPageId) {
|
fn draw_solid_tiles(&mut self, tile_count: u32, paint_page: PaintPageId) {
|
||||||
let clear_color = self.clear_color_for_draw_operation();
|
let clear_color = self.clear_color_for_draw_operation();
|
||||||
|
|
||||||
|
@ -711,8 +835,6 @@ where
|
||||||
textures.push(paint_texture);
|
textures.push(paint_texture);
|
||||||
uniforms.push((&self.solid_tile_program.paint_texture_uniform,
|
uniforms.push((&self.solid_tile_program.paint_texture_uniform,
|
||||||
UniformData::TextureUnit(0)));
|
UniformData::TextureUnit(0)));
|
||||||
uniforms.push((&self.solid_tile_program.paint_texture_size_uniform,
|
|
||||||
UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x2())));
|
|
||||||
|
|
||||||
self.device.draw_elements(6 * tile_count, &RenderState {
|
self.device.draw_elements(6 * tile_count, &RenderState {
|
||||||
target: &self.draw_render_target(),
|
target: &self.draw_render_target(),
|
||||||
|
@ -800,7 +922,7 @@ where
|
||||||
],
|
],
|
||||||
viewport: self.draw_viewport(),
|
viewport: self.draw_viewport(),
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
blend: Some(BlendMode::SrcOver.to_blend_state()),
|
blend: BlendMode::SrcOver.to_blend_state(),
|
||||||
depth: Some(DepthState { func: DepthFunc::Less, write: false, }),
|
depth: Some(DepthState { func: DepthFunc::Less, write: false, }),
|
||||||
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
|
@ -817,6 +939,9 @@ where
|
||||||
RenderTarget::Framebuffer(framebuffer)
|
RenderTarget::Framebuffer(framebuffer)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
if self.flags.contains(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED) {
|
||||||
|
RenderTarget::Framebuffer(&self.intermediate_dest_framebuffer)
|
||||||
|
} else {
|
||||||
match self.dest_framebuffer {
|
match self.dest_framebuffer {
|
||||||
DestFramebuffer::Default { .. } => RenderTarget::Default,
|
DestFramebuffer::Default { .. } => RenderTarget::Default,
|
||||||
DestFramebuffer::Other(ref framebuffer) => {
|
DestFramebuffer::Other(ref framebuffer) => {
|
||||||
|
@ -826,6 +951,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn push_render_target(&mut self, render_target_id: RenderTargetId) {
|
fn push_render_target(&mut self, render_target_id: RenderTargetId) {
|
||||||
self.render_target_stack.push(render_target_id);
|
self.render_target_stack.push(render_target_id);
|
||||||
|
@ -859,15 +985,12 @@ where
|
||||||
let clear_color = self.clear_color_for_draw_operation();
|
let clear_color = self.clear_color_for_draw_operation();
|
||||||
let source_framebuffer = &self.render_targets[render_target_id.0 as usize].framebuffer;
|
let source_framebuffer = &self.render_targets[render_target_id.0 as usize].framebuffer;
|
||||||
let source_texture = self.device.framebuffer_texture(source_framebuffer);
|
let source_texture = self.device.framebuffer_texture(source_framebuffer);
|
||||||
let source_texture_size = self.device.texture_size(source_texture);
|
|
||||||
let main_viewport = self.main_viewport();
|
let main_viewport = self.main_viewport();
|
||||||
|
|
||||||
let uniforms = vec![
|
let uniforms = vec![
|
||||||
(&self.filter_basic_program.framebuffer_size_uniform,
|
(&self.filter_basic_program.framebuffer_size_uniform,
|
||||||
UniformData::Vec2(main_viewport.size().to_f32().0)),
|
UniformData::Vec2(main_viewport.size().to_f32().0)),
|
||||||
(&self.filter_basic_program.source_uniform, UniformData::TextureUnit(0)),
|
(&self.filter_basic_program.source_uniform, UniformData::TextureUnit(0)),
|
||||||
(&self.filter_basic_program.source_size_uniform,
|
|
||||||
UniformData::Vec2(source_texture_size.0.to_f32x2())),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let blend_state = match composite_op {
|
let blend_state = match composite_op {
|
||||||
|
@ -884,7 +1007,7 @@ where
|
||||||
viewport: main_viewport,
|
viewport: main_viewport,
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
||||||
blend: Some(blend_state),
|
blend: blend_state,
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -941,8 +1064,30 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn blit_intermediate_dest_framebuffer_if_necessary(&mut self) {
|
||||||
|
if !self.flags.contains(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let main_viewport = self.main_viewport();
|
||||||
|
|
||||||
|
let uniforms = [(&self.filter_basic_program.source_uniform, UniformData::TextureUnit(0))];
|
||||||
|
let textures = [(self.device.framebuffer_texture(&self.intermediate_dest_framebuffer))];
|
||||||
|
|
||||||
|
self.device.draw_elements(6, &RenderState {
|
||||||
|
target: &RenderTarget::Default,
|
||||||
|
program: &self.filter_basic_program.program,
|
||||||
|
vertex_array: &self.filter_basic_vertex_array.vertex_array,
|
||||||
|
primitive: Primitive::Triangles,
|
||||||
|
textures: &textures[..],
|
||||||
|
uniforms: &uniforms[..],
|
||||||
|
viewport: main_viewport,
|
||||||
|
options: RenderOptions::default(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn stencil_state(&self) -> Option<StencilState> {
|
fn stencil_state(&self) -> Option<StencilState> {
|
||||||
if !self.use_depth {
|
if !self.flags.contains(RendererFlags::USE_DEPTH) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,93 +1308,145 @@ struct RenderTargetInfo<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait BlendModeExt {
|
trait BlendModeExt {
|
||||||
fn to_blend_state(self) -> BlendState;
|
fn to_blend_state(self) -> Option<BlendState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlendModeExt for BlendMode {
|
impl BlendModeExt for BlendMode {
|
||||||
fn to_blend_state(self) -> BlendState {
|
fn to_blend_state(self) -> Option<BlendState> {
|
||||||
match self {
|
match self {
|
||||||
BlendMode::Clear => {
|
BlendMode::Clear => {
|
||||||
BlendState {
|
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::SrcOver => {
|
BlendMode::SrcOver => {
|
||||||
BlendState {
|
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 => {
|
BlendMode::DestOver => {
|
||||||
BlendState {
|
Some(BlendState {
|
||||||
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
dest_rgb_factor: BlendFactor::DestAlpha,
|
dest_rgb_factor: BlendFactor::DestAlpha,
|
||||||
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::DestOut => {
|
BlendMode::DestOut => {
|
||||||
BlendState {
|
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 => {
|
BlendMode::SrcAtop => {
|
||||||
BlendState {
|
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::Xor => {
|
BlendMode::Xor => {
|
||||||
BlendState {
|
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 => {
|
BlendMode::Lighter => {
|
||||||
BlendState {
|
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::Lighten => {
|
BlendMode::Lighten => {
|
||||||
BlendState {
|
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::One,
|
dest_alpha_factor: BlendFactor::One,
|
||||||
op: BlendOp::Max,
|
op: BlendOp::Max,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
BlendMode::Darken => {
|
BlendMode::Darken => {
|
||||||
BlendState {
|
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::One,
|
dest_alpha_factor: BlendFactor::One,
|
||||||
op: BlendOp::Min,
|
op: BlendOp::Min,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
BlendMode::Hue |
|
||||||
|
BlendMode::Saturation |
|
||||||
|
BlendMode::Color |
|
||||||
|
BlendMode::Luminosity => {
|
||||||
|
// Blending is done manually in the shader.
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub(crate) enum BlendModeProgram {
|
||||||
|
Regular,
|
||||||
|
HSL,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlendModeProgram {
|
||||||
|
pub(crate) fn from_blend_mode(blend_mode: BlendMode) -> BlendModeProgram {
|
||||||
|
match blend_mode {
|
||||||
|
BlendMode::Clear |
|
||||||
|
BlendMode::SrcOver |
|
||||||
|
BlendMode::DestOver |
|
||||||
|
BlendMode::DestOut |
|
||||||
|
BlendMode::SrcAtop |
|
||||||
|
BlendMode::Xor |
|
||||||
|
BlendMode::Lighter |
|
||||||
|
BlendMode::Lighten |
|
||||||
|
BlendMode::Darken => BlendModeProgram::Regular,
|
||||||
|
BlendMode::Hue |
|
||||||
|
BlendMode::Saturation |
|
||||||
|
BlendMode::Color |
|
||||||
|
BlendMode::Luminosity => BlendModeProgram::HSL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn needs_readable_framebuffer(self) -> bool {
|
||||||
|
match self {
|
||||||
|
BlendModeProgram::Regular => false,
|
||||||
|
BlendModeProgram::HSL => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
struct RendererFlags: u8 {
|
||||||
|
// Whether we need a depth buffer.
|
||||||
|
const USE_DEPTH = 0x01;
|
||||||
|
// Whether an intermediate destination framebuffer is needed.
|
||||||
|
//
|
||||||
|
// This will be true if any exotic blend modes are used at the top level (not inside a
|
||||||
|
// render target), *and* the output framebuffer is the default framebuffer.
|
||||||
|
const INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED = 0x02;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -176,16 +176,16 @@ impl<D> MaskTileVertexArray<D> where D: Device {
|
||||||
|
|
||||||
pub struct AlphaTileVertexArray<D> where D: Device {
|
pub struct AlphaTileVertexArray<D> where D: Device {
|
||||||
pub vertex_array: D::VertexArray,
|
pub vertex_array: D::VertexArray,
|
||||||
pub vertex_buffer: D::Buffer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> AlphaTileVertexArray<D> where D: Device {
|
impl<D> AlphaTileVertexArray<D> where D: Device {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &D,
|
device: &D,
|
||||||
alpha_tile_program: &AlphaTileProgram<D>,
|
alpha_tile_program: &AlphaTileProgram<D>,
|
||||||
|
alpha_tile_vertex_buffer: &D::Buffer,
|
||||||
quads_vertex_indices_buffer: &D::Buffer,
|
quads_vertex_indices_buffer: &D::Buffer,
|
||||||
) -> AlphaTileVertexArray<D> {
|
) -> AlphaTileVertexArray<D> {
|
||||||
let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer());
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let tile_position_attr =
|
let tile_position_attr =
|
||||||
device.get_vertex_attr(&alpha_tile_program.program, "TilePosition").unwrap();
|
device.get_vertex_attr(&alpha_tile_program.program, "TilePosition").unwrap();
|
||||||
|
@ -194,7 +194,7 @@ impl<D> AlphaTileVertexArray<D> where D: Device {
|
||||||
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();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, &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 {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
|
@ -224,7 +224,7 @@ impl<D> AlphaTileVertexArray<D> where D: Device {
|
||||||
});
|
});
|
||||||
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, vertex_buffer }
|
AlphaTileVertexArray { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +281,38 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CopyTileVertexArray<D> where D: Device {
|
||||||
|
pub vertex_array: D::VertexArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> CopyTileVertexArray<D> where D: Device {
|
||||||
|
pub fn new(
|
||||||
|
device: &D,
|
||||||
|
copy_tile_program: &CopyTileProgram<D>,
|
||||||
|
copy_tile_vertex_buffer: &D::Buffer,
|
||||||
|
quads_vertex_indices_buffer: &D::Buffer,
|
||||||
|
) -> CopyTileVertexArray<D> {
|
||||||
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
|
let tile_position_attr =
|
||||||
|
device.get_vertex_attr(©_tile_program.program, "TilePosition").unwrap();
|
||||||
|
|
||||||
|
device.bind_buffer(&vertex_array, copy_tile_vertex_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
|
||||||
|
size: 2,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I16,
|
||||||
|
stride: ALPHA_TILE_VERTEX_SIZE,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 0,
|
||||||
|
buffer_index: 0,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
|
||||||
|
|
||||||
|
CopyTileVertexArray { vertex_array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FillProgram<D>
|
pub struct FillProgram<D>
|
||||||
where
|
where
|
||||||
D: Device,
|
D: Device,
|
||||||
|
@ -337,7 +369,6 @@ pub struct SolidTileProgram<D> where D: Device {
|
||||||
pub transform_uniform: D::Uniform,
|
pub transform_uniform: D::Uniform,
|
||||||
pub tile_size_uniform: D::Uniform,
|
pub tile_size_uniform: D::Uniform,
|
||||||
pub paint_texture_uniform: D::Uniform,
|
pub paint_texture_uniform: D::Uniform,
|
||||||
pub paint_texture_size_uniform: D::Uniform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> SolidTileProgram<D> where D: Device {
|
impl<D> SolidTileProgram<D> where D: Device {
|
||||||
|
@ -346,13 +377,11 @@ impl<D> SolidTileProgram<D> where D: Device {
|
||||||
let transform_uniform = device.get_uniform(&program, "Transform");
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
let paint_texture_uniform = device.get_uniform(&program, "PaintTexture");
|
let paint_texture_uniform = device.get_uniform(&program, "PaintTexture");
|
||||||
let paint_texture_size_uniform = device.get_uniform(&program, "PaintTextureSize");
|
|
||||||
SolidTileProgram {
|
SolidTileProgram {
|
||||||
program,
|
program,
|
||||||
transform_uniform,
|
transform_uniform,
|
||||||
tile_size_uniform,
|
tile_size_uniform,
|
||||||
paint_texture_uniform,
|
paint_texture_uniform,
|
||||||
paint_texture_size_uniform,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,37 +390,78 @@ pub struct AlphaTileProgram<D> where D: Device {
|
||||||
pub program: D::Program,
|
pub program: D::Program,
|
||||||
pub transform_uniform: D::Uniform,
|
pub transform_uniform: D::Uniform,
|
||||||
pub tile_size_uniform: D::Uniform,
|
pub tile_size_uniform: D::Uniform,
|
||||||
|
pub framebuffer_size_uniform: D::Uniform,
|
||||||
pub stencil_texture_uniform: D::Uniform,
|
pub stencil_texture_uniform: D::Uniform,
|
||||||
pub stencil_texture_size_uniform: D::Uniform,
|
|
||||||
pub paint_texture_uniform: D::Uniform,
|
pub paint_texture_uniform: D::Uniform,
|
||||||
pub paint_texture_size_uniform: D::Uniform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> AlphaTileProgram<D> where D: Device {
|
impl<D> AlphaTileProgram<D> where D: Device {
|
||||||
|
#[inline]
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileProgram<D> {
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileProgram<D> {
|
||||||
let program = device.create_program(resources, "tile_alpha");
|
AlphaTileProgram::from_fragment_shader_name(device, resources, "tile_alpha")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_fragment_shader_name(device: &D,
|
||||||
|
resources: &dyn ResourceLoader,
|
||||||
|
fragment_shader_name: &str)
|
||||||
|
-> AlphaTileProgram<D> {
|
||||||
|
let program = device.create_program_from_shader_names(resources,
|
||||||
|
fragment_shader_name,
|
||||||
|
"tile_alpha",
|
||||||
|
fragment_shader_name);
|
||||||
let transform_uniform = device.get_uniform(&program, "Transform");
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
let stencil_texture_uniform = device.get_uniform(&program, "StencilTexture");
|
let stencil_texture_uniform = device.get_uniform(&program, "StencilTexture");
|
||||||
let stencil_texture_size_uniform = device.get_uniform(&program, "StencilTextureSize");
|
|
||||||
let paint_texture_uniform = device.get_uniform(&program, "PaintTexture");
|
let paint_texture_uniform = device.get_uniform(&program, "PaintTexture");
|
||||||
let paint_texture_size_uniform = device.get_uniform(&program, "PaintTextureSize");
|
|
||||||
AlphaTileProgram {
|
AlphaTileProgram {
|
||||||
program,
|
program,
|
||||||
transform_uniform,
|
transform_uniform,
|
||||||
tile_size_uniform,
|
tile_size_uniform,
|
||||||
|
framebuffer_size_uniform,
|
||||||
stencil_texture_uniform,
|
stencil_texture_uniform,
|
||||||
stencil_texture_size_uniform,
|
|
||||||
paint_texture_uniform,
|
paint_texture_uniform,
|
||||||
paint_texture_size_uniform,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CopyTileProgram<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub transform_uniform: D::Uniform,
|
||||||
|
pub tile_size_uniform: D::Uniform,
|
||||||
|
pub src_uniform: D::Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> CopyTileProgram<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> CopyTileProgram<D> {
|
||||||
|
let program = device.create_program(resources, "tile_copy");
|
||||||
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
|
let src_uniform = device.get_uniform(&program, "Src");
|
||||||
|
CopyTileProgram { program, transform_uniform, tile_size_uniform, src_uniform }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AlphaTileHSLProgram<D> where D: Device {
|
||||||
|
pub alpha_tile_program: AlphaTileProgram<D>,
|
||||||
|
pub dest_uniform: D::Uniform,
|
||||||
|
pub blend_hsl_uniform: D::Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> AlphaTileHSLProgram<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileHSLProgram<D> {
|
||||||
|
let alpha_tile_program = AlphaTileProgram::from_fragment_shader_name(device,
|
||||||
|
resources,
|
||||||
|
"tile_alpha_hsl");
|
||||||
|
let dest_uniform = device.get_uniform(&alpha_tile_program.program, "Dest");
|
||||||
|
let blend_hsl_uniform = device.get_uniform(&alpha_tile_program.program, "BlendHSL");
|
||||||
|
AlphaTileHSLProgram { alpha_tile_program, dest_uniform, blend_hsl_uniform }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FilterBasicProgram<D> where D: Device {
|
pub struct FilterBasicProgram<D> where D: Device {
|
||||||
pub program: D::Program,
|
pub program: D::Program,
|
||||||
pub source_uniform: D::Uniform,
|
pub source_uniform: D::Uniform,
|
||||||
pub source_size_uniform: D::Uniform,
|
|
||||||
pub framebuffer_size_uniform: D::Uniform,
|
pub framebuffer_size_uniform: D::Uniform,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,14 +472,8 @@ impl<D> FilterBasicProgram<D> where D: Device {
|
||||||
"filter",
|
"filter",
|
||||||
"filter_basic");
|
"filter_basic");
|
||||||
let source_uniform = device.get_uniform(&program, "Source");
|
let source_uniform = device.get_uniform(&program, "Source");
|
||||||
let source_size_uniform = device.get_uniform(&program, "SourceSize");
|
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
FilterBasicProgram {
|
FilterBasicProgram { program, source_uniform, framebuffer_size_uniform }
|
||||||
program,
|
|
||||||
source_uniform,
|
|
||||||
source_size_uniform,
|
|
||||||
framebuffer_size_uniform,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,19 @@ use std::time::Duration;
|
||||||
|
|
||||||
pub enum RenderCommand {
|
pub enum RenderCommand {
|
||||||
// Starts rendering a frame.
|
// Starts rendering a frame.
|
||||||
Start { path_count: usize, bounding_quad: BoundingQuad },
|
Start {
|
||||||
|
/// The number of paths that will be rendered.
|
||||||
|
path_count: usize,
|
||||||
|
|
||||||
|
/// A bounding quad for the scene.
|
||||||
|
bounding_quad: BoundingQuad,
|
||||||
|
|
||||||
|
/// Whether the framebuffer we're rendering to must be readable.
|
||||||
|
///
|
||||||
|
/// This is needed if a path that renders directly to the output framebuffer (i.e. not to a
|
||||||
|
/// render target) uses one of the more exotic blend modes.
|
||||||
|
needs_readable_framebuffer: bool,
|
||||||
|
},
|
||||||
|
|
||||||
// Uploads paint data for use with subsequent rendering commands to the GPU.
|
// Uploads paint data for use with subsequent rendering commands to the GPU.
|
||||||
AddPaintData(PaintData),
|
AddPaintData(PaintData),
|
||||||
|
|
|
@ -261,11 +261,18 @@ impl Palette {
|
||||||
Transform2F::from_translation(texture_origin_uv) *
|
Transform2F::from_translation(texture_origin_uv) *
|
||||||
Transform2F::from_scale(gradient_tile_scale / view_box_size.to_f32())
|
Transform2F::from_scale(gradient_tile_scale / view_box_size.to_f32())
|
||||||
}
|
}
|
||||||
Paint::Pattern(_) => {
|
Paint::Pattern(Pattern { source: PatternSource::Image(_), .. }) => {
|
||||||
let texture_origin_uv = rect_to_uv(metadata.tex_rect, texture_scale).origin();
|
let texture_origin_uv = rect_to_uv(metadata.tex_rect, texture_scale).origin();
|
||||||
Transform2F::from_translation(texture_origin_uv) *
|
Transform2F::from_translation(texture_origin_uv) *
|
||||||
Transform2F::from_scale(texture_scale)
|
Transform2F::from_scale(texture_scale)
|
||||||
}
|
}
|
||||||
|
Paint::Pattern(Pattern { source: PatternSource::RenderTarget(_), .. }) => {
|
||||||
|
// FIXME(pcwalton): Only do this in GL, not Metal!
|
||||||
|
let texture_origin_uv = rect_to_uv(metadata.tex_rect,
|
||||||
|
texture_scale).lower_left();
|
||||||
|
Transform2F::from_translation(texture_origin_uv) *
|
||||||
|
Transform2F::from_scale(texture_scale.scale_xy(Vector2F::new(1.0, -1.0)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform sampler2D uSource;
|
uniform sampler2D uSource;
|
||||||
uniform vec2 uSourceSize;
|
|
||||||
|
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,10 @@ precision highp float;
|
||||||
|
|
||||||
uniform sampler2D uStencilTexture;
|
uniform sampler2D uStencilTexture;
|
||||||
uniform sampler2D uPaintTexture;
|
uniform sampler2D uPaintTexture;
|
||||||
uniform vec2 uPaintTextureSize;
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
in vec2 vColorTexCoord;
|
in vec2 vColorTexCoord;
|
||||||
in vec2 vMaskTexCoord;
|
in vec2 vMaskTexCoord;
|
||||||
in vec4 vColor;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ precision highp float;
|
||||||
|
|
||||||
uniform mat4 uTransform;
|
uniform mat4 uTransform;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uStencilTextureSize;
|
|
||||||
|
|
||||||
in ivec2 aTilePosition;
|
in ivec2 aTilePosition;
|
||||||
in vec2 aColorTexCoord;
|
in vec2 aColorTexCoord;
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
uniform sampler2D uStencilTexture;
|
||||||
|
uniform sampler2D uPaintTexture;
|
||||||
|
uniform sampler2D uDest;
|
||||||
|
uniform ivec3 uBlendHSL;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in vec2 vColorTexCoord;
|
||||||
|
in vec2 vMaskTexCoord;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec3 convertHSLToRGB(vec3 hsl){
|
||||||
|
float a = hsl . y * min(hsl . z, 1.0 - hsl . z);
|
||||||
|
vec3 ks = mod(vec3(0.0, 8.0, 4.0)+ vec3(hsl . x * 1.9098593171027443), 12.0);
|
||||||
|
return hsl . zzz - clamp(min(ks - vec3(3.0), vec3(9.0)- ks), - 1.0, 1.0)* a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec3 convertRGBToHSL(vec3 rgb){
|
||||||
|
float v = max((rgb . x, rgb . y), rgb . z);
|
||||||
|
float c = v - min((rgb . x, rgb . y), rgb . z);
|
||||||
|
float l = v - 0.5 * c;
|
||||||
|
|
||||||
|
vec3 tmp = vec3(0.0);
|
||||||
|
bvec3 is_v = equal(rgb, vec3(v));
|
||||||
|
if(is_v . r)
|
||||||
|
tmp = vec3(0.0, rgb . gb);
|
||||||
|
else if(is_v . g)
|
||||||
|
tmp = vec3(2.0, rgb . br);
|
||||||
|
else if(is_v . b)
|
||||||
|
tmp = vec3(4.0, rgb . rg);
|
||||||
|
float h = 1.0471975511965976 *(tmp . x +(tmp . y - tmp . z)/ c);
|
||||||
|
|
||||||
|
float s = 0.0;
|
||||||
|
if(l > 0.0 && l < 1.0)
|
||||||
|
s =(v - l)/ min(l, 1.0 - l);
|
||||||
|
|
||||||
|
return vec3(h, s, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
|
||||||
|
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
|
||||||
|
srcRGBA . a *= coverage;
|
||||||
|
|
||||||
|
vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize;
|
||||||
|
vec4 destRGBA = texture(uDest, destTexCoord);
|
||||||
|
|
||||||
|
vec3 destHSL = convertRGBToHSL(destRGBA . rgb);
|
||||||
|
vec3 srcHSL = convertRGBToHSL(srcRGBA . rgb);
|
||||||
|
bvec3 blendDest = equal(uBlendHSL, ivec3(0));
|
||||||
|
vec3 blendedHSL = vec3(blendDest . x ? destHSL . x : srcHSL . x,
|
||||||
|
blendDest . y ? destHSL . y : srcHSL . y,
|
||||||
|
blendDest . z ? destHSL . z : srcHSL . z);
|
||||||
|
vec3 blendedRGB = convertHSLToRGB(blendedHSL);
|
||||||
|
|
||||||
|
|
||||||
|
vec4 color = vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb +
|
||||||
|
srcRGBA . a * destRGBA . a * blendedRGB +
|
||||||
|
(1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb,
|
||||||
|
1.0);
|
||||||
|
oFragColor = color;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
uniform sampler2D uSrc;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 texCoord = gl_FragCoord . xy / uFramebufferSize;
|
||||||
|
oFragColor = texture(uSrc, texCoord);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
uniform mat4 uTransform;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
|
||||||
|
in ivec2 aTilePosition;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 position = aTilePosition * uTileSize;
|
||||||
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform sampler2D uPaintTexture;
|
uniform sampler2D uPaintTexture;
|
||||||
uniform vec2 uPaintTextureSize;
|
|
||||||
|
|
||||||
in vec2 vColorTexCoord;
|
in vec2 vColorTexCoord;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct spvDescriptorSetBuffer0
|
||||||
|
{
|
||||||
|
texture2d<float> uStencilTexture [[id(0)]];
|
||||||
|
sampler uStencilTextureSmplr [[id(1)]];
|
||||||
|
texture2d<float> uPaintTexture [[id(2)]];
|
||||||
|
sampler uPaintTextureSmplr [[id(3)]];
|
||||||
|
constant float2* uFramebufferSize [[id(4)]];
|
||||||
|
texture2d<float> uDest [[id(5)]];
|
||||||
|
sampler uDestSmplr [[id(6)]];
|
||||||
|
constant int3* uBlendHSL [[id(7)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 oFragColor [[color(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float2 vColorTexCoord [[user(locn0)]];
|
||||||
|
float2 vMaskTexCoord [[user(locn1)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
|
||||||
|
template<typename Tx, typename Ty>
|
||||||
|
Tx mod(Tx x, Ty y)
|
||||||
|
{
|
||||||
|
return x - y * floor(x / y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 convertRGBToHSL(thread const float3& rgb)
|
||||||
|
{
|
||||||
|
float v = fast::max(rgb.y, rgb.z);
|
||||||
|
float c = v - fast::min(rgb.y, rgb.z);
|
||||||
|
float l = v - (0.5 * c);
|
||||||
|
float3 tmp = float3(0.0);
|
||||||
|
bool3 is_v = rgb == float3(v);
|
||||||
|
if (is_v.x)
|
||||||
|
{
|
||||||
|
tmp = float3(0.0, rgb.yz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (is_v.y)
|
||||||
|
{
|
||||||
|
tmp = float3(2.0, rgb.zx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (is_v.z)
|
||||||
|
{
|
||||||
|
tmp = float3(4.0, rgb.xy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float h = 1.0471975803375244140625 * (tmp.x + ((tmp.y - tmp.z) / c));
|
||||||
|
float s = 0.0;
|
||||||
|
if ((l > 0.0) && (l < 1.0))
|
||||||
|
{
|
||||||
|
s = (v - l) / fast::min(l, 1.0 - l);
|
||||||
|
}
|
||||||
|
return float3(h, s, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 convertHSLToRGB(thread const float3& hsl)
|
||||||
|
{
|
||||||
|
float a = hsl.y * fast::min(hsl.z, 1.0 - hsl.z);
|
||||||
|
float3 ks = mod(float3(0.0, 8.0, 4.0) + float3(hsl.x * 1.90985929965972900390625), float3(12.0));
|
||||||
|
return hsl.zzz - (fast::clamp(fast::min(ks - float3(3.0), float3(9.0) - ks), float3(-1.0), float3(1.0)) * a);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float coverage = spvDescriptorSet0.uStencilTexture.sample(spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord).x;
|
||||||
|
float4 srcRGBA = spvDescriptorSet0.uPaintTexture.sample(spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord);
|
||||||
|
srcRGBA.w *= coverage;
|
||||||
|
float2 destTexCoord = gl_FragCoord.xy / (*spvDescriptorSet0.uFramebufferSize);
|
||||||
|
float4 destRGBA = spvDescriptorSet0.uDest.sample(spvDescriptorSet0.uDestSmplr, destTexCoord);
|
||||||
|
float3 param = destRGBA.xyz;
|
||||||
|
float3 destHSL = convertRGBToHSL(param);
|
||||||
|
float3 param_1 = srcRGBA.xyz;
|
||||||
|
float3 srcHSL = convertRGBToHSL(param_1);
|
||||||
|
bool3 blendDest = (*spvDescriptorSet0.uBlendHSL) == int3(0);
|
||||||
|
float _225;
|
||||||
|
if (blendDest.x)
|
||||||
|
{
|
||||||
|
_225 = destHSL.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_225 = srcHSL.x;
|
||||||
|
}
|
||||||
|
float _236;
|
||||||
|
if (blendDest.y)
|
||||||
|
{
|
||||||
|
_236 = destHSL.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_236 = srcHSL.y;
|
||||||
|
}
|
||||||
|
float _247;
|
||||||
|
if (blendDest.z)
|
||||||
|
{
|
||||||
|
_247 = destHSL.z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_247 = srcHSL.z;
|
||||||
|
}
|
||||||
|
float3 blendedHSL = float3(_225, _236, _247);
|
||||||
|
float3 param_2 = blendedHSL;
|
||||||
|
float3 blendedRGB = convertHSLToRGB(param_2);
|
||||||
|
float4 color = float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0);
|
||||||
|
out.oFragColor = color;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct spvDescriptorSetBuffer0
|
||||||
|
{
|
||||||
|
constant float2* uFramebufferSize [[id(0)]];
|
||||||
|
texture2d<float> uSrc [[id(1)]];
|
||||||
|
sampler uSrcSmplr [[id(2)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 oFragColor [[color(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment main0_out main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 texCoord = gl_FragCoord.xy / (*spvDescriptorSet0.uFramebufferSize);
|
||||||
|
out.oFragColor = spvDescriptorSet0.uSrc.sample(spvDescriptorSet0.uSrcSmplr, texCoord);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct spvDescriptorSetBuffer0
|
||||||
|
{
|
||||||
|
constant float2* uTileSize [[id(0)]];
|
||||||
|
constant float4x4* uTransform [[id(1)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
int2 aTilePosition [[attribute(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize);
|
||||||
|
out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ SHADERS=\
|
||||||
stencil.vs.glsl \
|
stencil.vs.glsl \
|
||||||
tile_alpha.fs.glsl \
|
tile_alpha.fs.glsl \
|
||||||
tile_alpha.vs.glsl \
|
tile_alpha.vs.glsl \
|
||||||
|
tile_alpha_hsl.fs.glsl \
|
||||||
|
tile_copy.fs.glsl \
|
||||||
|
tile_copy.vs.glsl \
|
||||||
tile_solid.fs.glsl \
|
tile_solid.fs.glsl \
|
||||||
tile_solid.vs.glsl \
|
tile_solid.vs.glsl \
|
||||||
$(EMPTY)
|
$(EMPTY)
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform sampler2D uSource;
|
uniform sampler2D uSource;
|
||||||
uniform vec2 uSourceSize;
|
|
||||||
|
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,10 @@ precision highp float;
|
||||||
|
|
||||||
uniform sampler2D uStencilTexture;
|
uniform sampler2D uStencilTexture;
|
||||||
uniform sampler2D uPaintTexture;
|
uniform sampler2D uPaintTexture;
|
||||||
uniform vec2 uPaintTextureSize;
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
in vec2 vColorTexCoord;
|
in vec2 vColorTexCoord;
|
||||||
in vec2 vMaskTexCoord;
|
in vec2 vMaskTexCoord;
|
||||||
in vec4 vColor;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ precision highp float;
|
||||||
|
|
||||||
uniform mat4 uTransform;
|
uniform mat4 uTransform;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
uniform vec2 uStencilTextureSize;
|
|
||||||
|
|
||||||
in ivec2 aTilePosition;
|
in ivec2 aTilePosition;
|
||||||
in vec2 aColorTexCoord;
|
in vec2 aColorTexCoord;
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// pathfinder/shaders/tile_alpha_hsl.fs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
#define BLEND_TERM_DEST 0
|
||||||
|
#define BLEND_TERM_SRC 1
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
uniform sampler2D uStencilTexture;
|
||||||
|
uniform sampler2D uPaintTexture;
|
||||||
|
uniform sampler2D uDest;
|
||||||
|
uniform ivec3 uBlendHSL;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in vec2 vColorTexCoord;
|
||||||
|
in vec2 vMaskTexCoord;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
#define PI_2 6.283185307179586
|
||||||
|
#define DEG_30_INV 1.9098593171027443
|
||||||
|
#define DEG_60 1.0471975511965976
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative
|
||||||
|
vec3 convertHSLToRGB(vec3 hsl) {
|
||||||
|
float a = hsl.y * min(hsl.z, 1.0 - hsl.z);
|
||||||
|
vec3 ks = mod(vec3(0.0, 8.0, 4.0) + vec3(hsl.x * DEG_30_INV), 12.0);
|
||||||
|
return hsl.zzz - clamp(min(ks - vec3(3.0), vec3(9.0) - ks), -1.0, 1.0) * a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB
|
||||||
|
vec3 convertRGBToHSL(vec3 rgb) {
|
||||||
|
float v = max((rgb.x, rgb.y), rgb.z);
|
||||||
|
float c = v - min((rgb.x, rgb.y), rgb.z);
|
||||||
|
float l = v - 0.5 * c;
|
||||||
|
|
||||||
|
vec3 tmp = vec3(0.0);
|
||||||
|
bvec3 is_v = equal(rgb, vec3(v));
|
||||||
|
if (is_v.r)
|
||||||
|
tmp = vec3(0.0, rgb.gb);
|
||||||
|
else if (is_v.g)
|
||||||
|
tmp = vec3(2.0, rgb.br);
|
||||||
|
else if (is_v.b)
|
||||||
|
tmp = vec3(4.0, rgb.rg);
|
||||||
|
float h = DEG_60 * (tmp.x + (tmp.y - tmp.z) / c);
|
||||||
|
|
||||||
|
float s = 0.0;
|
||||||
|
if (l > 0.0 && l < 1.0)
|
||||||
|
s = (v - l) / min(l, 1.0 - l);
|
||||||
|
|
||||||
|
return vec3(h, s, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float coverage = texture(uStencilTexture, vMaskTexCoord).r;
|
||||||
|
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
|
||||||
|
srcRGBA.a *= coverage;
|
||||||
|
|
||||||
|
vec2 destTexCoord = gl_FragCoord.xy / uFramebufferSize;
|
||||||
|
vec4 destRGBA = texture(uDest, destTexCoord);
|
||||||
|
|
||||||
|
vec3 destHSL = convertRGBToHSL(destRGBA.rgb);
|
||||||
|
vec3 srcHSL = convertRGBToHSL(srcRGBA.rgb);
|
||||||
|
bvec3 blendDest = equal(uBlendHSL, ivec3(BLEND_TERM_DEST));
|
||||||
|
vec3 blendedHSL = vec3(blendDest.x ? destHSL.x : srcHSL.x,
|
||||||
|
blendDest.y ? destHSL.y : srcHSL.y,
|
||||||
|
blendDest.z ? destHSL.z : srcHSL.z);
|
||||||
|
vec3 blendedRGB = convertHSLToRGB(blendedHSL);
|
||||||
|
|
||||||
|
// FIXME(pcwalton): What should the output alpha be here?
|
||||||
|
vec4 color = vec4(srcRGBA.a * (1.0 - destRGBA.a) * srcRGBA.rgb +
|
||||||
|
srcRGBA.a * destRGBA.a * blendedRGB +
|
||||||
|
(1.0 - srcRGBA.a) * destRGBA.a * destRGBA.rgb,
|
||||||
|
1.0);
|
||||||
|
oFragColor = color;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// pathfinder/shaders/tile_copy.fs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
uniform sampler2D uSrc;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 texCoord = gl_FragCoord.xy / uFramebufferSize;
|
||||||
|
oFragColor = texture(uSrc, texCoord);
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// pathfinder/shaders/tile_copy.vs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
uniform mat4 uTransform;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
|
||||||
|
in ivec2 aTilePosition;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 position = aTilePosition * uTileSize;
|
||||||
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
|
}
|
|
@ -13,7 +13,6 @@
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform sampler2D uPaintTexture;
|
uniform sampler2D uPaintTexture;
|
||||||
uniform vec2 uPaintTextureSize;
|
|
||||||
|
|
||||||
in vec2 vColorTexCoord;
|
in vec2 vColorTexCoord;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue