outline schtuff
Some checks failed
Format / all (push) Has been cancelled
Lint / all (push) Has been cancelled
Test / all (macOS-latest, beta) (push) Has been cancelled
Test / all (macOS-latest, stable) (push) Has been cancelled
Test / all (ubuntu-latest, beta) (push) Has been cancelled
Test / all (ubuntu-latest, stable) (push) Has been cancelled
Test / all (windows-latest, beta) (push) Has been cancelled
Test / all (windows-latest, stable) (push) Has been cancelled
Some checks failed
Format / all (push) Has been cancelled
Lint / all (push) Has been cancelled
Test / all (macOS-latest, beta) (push) Has been cancelled
Test / all (macOS-latest, stable) (push) Has been cancelled
Test / all (ubuntu-latest, beta) (push) Has been cancelled
Test / all (ubuntu-latest, stable) (push) Has been cancelled
Test / all (windows-latest, beta) (push) Has been cancelled
Test / all (windows-latest, stable) (push) Has been cancelled
This commit is contained in:
parent
da3b02cf8a
commit
7e2b1612b9
5 changed files with 216 additions and 68 deletions
155
src/cache.rs
155
src/cache.rs
|
@ -25,6 +25,7 @@ struct Inner {
|
||||||
vertex_buffers: [wgpu::VertexBufferLayout<'static>; 1],
|
vertex_buffers: [wgpu::VertexBufferLayout<'static>; 1],
|
||||||
atlas_layout: BindGroupLayout,
|
atlas_layout: BindGroupLayout,
|
||||||
uniforms_layout: BindGroupLayout,
|
uniforms_layout: BindGroupLayout,
|
||||||
|
stroke_layout: BindGroupLayout,
|
||||||
pipeline_layout: PipelineLayout,
|
pipeline_layout: PipelineLayout,
|
||||||
cache: Mutex<
|
cache: Mutex<
|
||||||
Vec<(
|
Vec<(
|
||||||
|
@ -87,16 +88,6 @@ impl Cache {
|
||||||
offset: mem::size_of::<u32>() as u64 * 6,
|
offset: mem::size_of::<u32>() as u64 * 6,
|
||||||
shader_location: 5,
|
shader_location: 5,
|
||||||
},
|
},
|
||||||
wgpu::VertexAttribute {
|
|
||||||
format: VertexFormat::Uint32,
|
|
||||||
offset: mem::size_of::<u32>() as u64 * 7,
|
|
||||||
shader_location: 6,
|
|
||||||
},
|
|
||||||
wgpu::VertexAttribute {
|
|
||||||
format: VertexFormat::Float32,
|
|
||||||
offset: mem::size_of::<u32>() as u64 * 8,
|
|
||||||
shader_location: 7,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,9 +137,56 @@ impl Cache {
|
||||||
label: Some("glyphon uniforms bind group layout"),
|
label: Some("glyphon uniforms bind group layout"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let stroke_bind_group_layout =
|
||||||
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: Some("Stroke Bind Group Layout"),
|
||||||
|
entries: &[
|
||||||
|
// glyph texture
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
multisampled: false,
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
// glyph sampler
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
// stroke color
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 2,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: std::num::NonZeroU64::new(16),
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
// stroke width
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 3,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: std::num::NonZeroU64::new(4),
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
bind_group_layouts: &[&atlas_layout, &uniforms_layout],
|
bind_group_layouts: &[&atlas_layout, &uniforms_layout, &stroke_bind_group_layout],
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -160,6 +198,7 @@ impl Cache {
|
||||||
atlas_layout,
|
atlas_layout,
|
||||||
pipeline_layout,
|
pipeline_layout,
|
||||||
cache: Mutex::new(Vec::new()),
|
cache: Mutex::new(Vec::new()),
|
||||||
|
stroke_layout: stroke_bind_group_layout,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +228,37 @@ impl Cache {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn create_stroke_bind_group(
|
||||||
|
&self,
|
||||||
|
device: &Device,
|
||||||
|
mask_atlas: &TextureView,
|
||||||
|
stroke_color_buffer: &Buffer,
|
||||||
|
stroke_width_buffer: &Buffer,
|
||||||
|
) -> BindGroup {
|
||||||
|
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: Some("Stroke Bind Group"),
|
||||||
|
layout: &self.0.stroke_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&mask_atlas),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&self.0.sampler),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 2,
|
||||||
|
resource: stroke_color_buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 3,
|
||||||
|
resource: stroke_width_buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn create_uniforms_bind_group(&self, device: &Device, buffer: &Buffer) -> BindGroup {
|
pub(crate) fn create_uniforms_bind_group(&self, device: &Device, buffer: &Buffer) -> BindGroup {
|
||||||
device.create_bind_group(&BindGroupDescriptor {
|
device.create_bind_group(&BindGroupDescriptor {
|
||||||
layout: &self.0.uniforms_layout,
|
layout: &self.0.uniforms_layout,
|
||||||
|
@ -257,4 +327,67 @@ impl Cache {
|
||||||
})
|
})
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_or_create_stroke_pipeline(
|
||||||
|
&self,
|
||||||
|
device: &Device,
|
||||||
|
format: TextureFormat,
|
||||||
|
multisample: MultisampleState,
|
||||||
|
depth_stencil: Option<DepthStencilState>,
|
||||||
|
) -> RenderPipeline {
|
||||||
|
let Inner {
|
||||||
|
cache,
|
||||||
|
pipeline_layout,
|
||||||
|
shader,
|
||||||
|
vertex_buffers,
|
||||||
|
..
|
||||||
|
} = self.0.deref();
|
||||||
|
|
||||||
|
let mut cache = cache.lock().expect("Write pipeline cache");
|
||||||
|
|
||||||
|
let stroke_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: Some("Stroke Shader"),
|
||||||
|
source: ShaderSource::Wgsl(Cow::Borrowed(include_str!("stroke_shader.wgsl"))),
|
||||||
|
});
|
||||||
|
|
||||||
|
cache
|
||||||
|
.iter()
|
||||||
|
.find(|(fmt, ms, ds, _)| fmt == &format && ms == &multisample && ds == &depth_stencil)
|
||||||
|
.map(|(_, _, _, p)| p.clone())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
|
||||||
|
label: Some("glyphon pipeline"),
|
||||||
|
layout: Some(&pipeline_layout),
|
||||||
|
vertex: VertexState {
|
||||||
|
module: shader,
|
||||||
|
entry_point: Some("vs_main"),
|
||||||
|
buffers: vertex_buffers,
|
||||||
|
compilation_options: PipelineCompilationOptions::default(),
|
||||||
|
},
|
||||||
|
fragment: Some(FragmentState {
|
||||||
|
module: &stroke_shader,
|
||||||
|
entry_point: Some("fs_main"),
|
||||||
|
targets: &[Some(ColorTargetState {
|
||||||
|
format,
|
||||||
|
blend: Some(BlendState::ALPHA_BLENDING),
|
||||||
|
write_mask: ColorWrites::default(),
|
||||||
|
})],
|
||||||
|
compilation_options: PipelineCompilationOptions::default(),
|
||||||
|
}),
|
||||||
|
primitive: PrimitiveState {
|
||||||
|
topology: PrimitiveTopology::TriangleStrip,
|
||||||
|
..PrimitiveState::default()
|
||||||
|
},
|
||||||
|
depth_stencil: depth_stencil.clone(),
|
||||||
|
multisample,
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.push((format, multisample, depth_stencil, pipeline.clone()));
|
||||||
|
|
||||||
|
pipeline
|
||||||
|
})
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@ struct VertexInput {
|
||||||
@location(3) color: u32,
|
@location(3) color: u32,
|
||||||
@location(4) content_type_with_srgb: u32,
|
@location(4) content_type_with_srgb: u32,
|
||||||
@location(5) depth: f32,
|
@location(5) depth: f32,
|
||||||
@location(6) stroke_color: u32,
|
|
||||||
@location(7) stroke_size: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
|
@ -15,8 +13,6 @@ struct VertexOutput {
|
||||||
@location(0) color: vec4<f32>,
|
@location(0) color: vec4<f32>,
|
||||||
@location(1) uv: vec2<f32>,
|
@location(1) uv: vec2<f32>,
|
||||||
@location(2) @interpolate(flat) content_type: u32,
|
@location(2) @interpolate(flat) content_type: u32,
|
||||||
@location(3) stroke_color: vec4<f32>,
|
|
||||||
@location(4) stroke_size: f32,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Params {
|
struct Params {
|
||||||
|
@ -46,13 +42,11 @@ fn srgb_to_linear(c: f32) -> f32 {
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn vs_main(in_vert: VertexInput) -> VertexOutput {
|
fn vs_main(in_vert: VertexInput) -> VertexOutput {
|
||||||
var stroke = in_vert.stroke_size;
|
var pos = in_vert.pos;
|
||||||
var width = in_vert.dim & 0xffffu;
|
let width = in_vert.dim & 0xffffu;
|
||||||
var height = (in_vert.dim & 0xffff0000u) >> 16u;
|
let height = (in_vert.dim & 0xffff0000u) >> 16u;
|
||||||
var pos = in_vert.pos;
|
|
||||||
var uv = vec2<u32>(in_vert.uv & 0xffffu, (in_vert.uv & 0xffff0000u) >> 16u);
|
|
||||||
let color = in_vert.color;
|
let color = in_vert.color;
|
||||||
let stroke_color = in_vert.stroke_color;
|
var uv = vec2<u32>(in_vert.uv & 0xffffu, (in_vert.uv & 0xffff0000u) >> 16u);
|
||||||
let v = in_vert.vertex_idx;
|
let v = in_vert.vertex_idx;
|
||||||
|
|
||||||
let corner_position = vec2<u32>(
|
let corner_position = vec2<u32>(
|
||||||
|
@ -86,12 +80,6 @@ fn vs_main(in_vert: VertexInput) -> VertexOutput {
|
||||||
f32(color & 0x000000ffu) / 255.0,
|
f32(color & 0x000000ffu) / 255.0,
|
||||||
f32((color & 0xff000000u) >> 24u) / 255.0,
|
f32((color & 0xff000000u) >> 24u) / 255.0,
|
||||||
);
|
);
|
||||||
vert_output.stroke_color = vec4<f32>(
|
|
||||||
f32((stroke_color & 0x00ff0000u) >> 16u) / 255.0,
|
|
||||||
f32((stroke_color & 0x0000ff00u) >> 8u) / 255.0,
|
|
||||||
f32(stroke_color & 0x000000ffu) / 255.0,
|
|
||||||
f32((stroke_color & 0xff000000u) >> 24u) / 255.0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
case 1u: {
|
case 1u: {
|
||||||
vert_output.color = vec4<f32>(
|
vert_output.color = vec4<f32>(
|
||||||
|
@ -100,12 +88,6 @@ fn vs_main(in_vert: VertexInput) -> VertexOutput {
|
||||||
srgb_to_linear(f32(color & 0x000000ffu) / 255.0),
|
srgb_to_linear(f32(color & 0x000000ffu) / 255.0),
|
||||||
f32((color & 0xff000000u) >> 24u) / 255.0,
|
f32((color & 0xff000000u) >> 24u) / 255.0,
|
||||||
);
|
);
|
||||||
vert_output.stroke_color = vec4<f32>(
|
|
||||||
srgb_to_linear(f32((stroke_color & 0x00ff0000u) >> 16u) / 255.0),
|
|
||||||
srgb_to_linear(f32((stroke_color & 0x0000ff00u) >> 8u) / 255.0),
|
|
||||||
srgb_to_linear(f32(stroke_color & 0x000000ffu) / 255.0),
|
|
||||||
f32((stroke_color & 0xff000000u) >> 24u) / 255.0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
default: {}
|
default: {}
|
||||||
}
|
}
|
||||||
|
@ -126,54 +108,20 @@ fn vs_main(in_vert: VertexInput) -> VertexOutput {
|
||||||
vert_output.content_type = content_type;
|
vert_output.content_type = content_type;
|
||||||
|
|
||||||
vert_output.uv = vec2<f32>(uv) / vec2<f32>(dim);
|
vert_output.uv = vec2<f32>(uv) / vec2<f32>(dim);
|
||||||
vert_output.stroke_size = in_vert.stroke_size;
|
|
||||||
|
|
||||||
return vert_output;
|
return vert_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in_frag: VertexOutput) -> @location(0) vec4<f32> {
|
fn fs_main(in_frag: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
let dims = vec2<f32>(textureDimensions(mask_atlas_texture));
|
|
||||||
var bit: u32 = 1;
|
|
||||||
|
|
||||||
let current = textureSample(mask_atlas_texture, atlas_sampler, dims);
|
|
||||||
var closest_dist = distance(vec2<f32>(in_frag.position.xy), vec2<f32>(current.xy));
|
|
||||||
var result = current;
|
|
||||||
|
|
||||||
for (var step: u32 = 0; step <= 32; step++) {
|
|
||||||
bit = 1u << step;
|
|
||||||
for (var dy = -1; dy <= 1; dy++) {
|
|
||||||
for (var dx = -1; dx <= 1; dx++) {
|
|
||||||
if (dx == 0 && dy == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let neighbour_coord = in_frag.position.xy + vec2<f32>(f32(dx * bit), f32(dy * bit));
|
|
||||||
let neighbour = textureSample(mask_atlas_texture, atlas_sampler, neighbour_coord / dims);
|
|
||||||
let dist = distance(vec2<f32>(in_frag.position.xy), vec2<f32>(neighbour.xy));
|
|
||||||
|
|
||||||
if (dist < closest_dist) {
|
|
||||||
closest_dist = dist;
|
|
||||||
result = vec4<f32>(in_frag.stroke_color.rgb, in_frag.stroke_color.a * textureSampleLevel(mask_atlas_texture, atlas_sampler, neighbour.xy, 0.0).x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch in_frag.content_type {
|
switch in_frag.content_type {
|
||||||
case 0u: {
|
case 0u: {
|
||||||
return textureSampleLevel(color_atlas_texture, atlas_sampler, in_frag.uv, 0.0);
|
return textureSampleLevel(color_atlas_texture, atlas_sampler, in_frag.uv, 0.0);
|
||||||
}
|
}
|
||||||
case 1u: {
|
case 1u: {
|
||||||
if in_frag.stroke_size > 0.0 {
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
return vec4<f32>(in_frag.color.rgb, in_frag.color.a * textureSampleLevel(mask_atlas_texture, atlas_sampler, in_frag.uv, 0.0).x);
|
return vec4<f32>(in_frag.color.rgb, in_frag.color.a * textureSampleLevel(mask_atlas_texture, atlas_sampler, in_frag.uv, 0.0).x);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// return result;
|
|
||||||
return vec4<f32>(0.0);
|
return vec4<f32>(0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/stroke_shader.wgsl
Normal file
15
src/stroke_shader.wgsl
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
@group(0) @binding(0) var glyph_tex: texture_2d<f32>;
|
||||||
|
@group(0) @binding(1) var glyph_sampler: sampler;
|
||||||
|
@group(0) @binding(2) var<uniform> stroke_color: vec4<f32>;
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) position: vec4<f32>,
|
||||||
|
@location(0) tex_coords: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
let distance = textureSample(glyph_tex, glyph_sampler, in.tex_coords).r;
|
||||||
|
let alpha = smoothstep(0.5 - 0.02, 0.5 + 0.02, distance); // Optional anti-alias
|
||||||
|
return vec4<f32>(stroke_color.rgb, alpha * stroke_color.a);
|
||||||
|
}
|
|
@ -244,6 +244,7 @@ pub enum ColorMode {
|
||||||
pub struct TextAtlas {
|
pub struct TextAtlas {
|
||||||
cache: Cache,
|
cache: Cache,
|
||||||
pub(crate) bind_group: BindGroup,
|
pub(crate) bind_group: BindGroup,
|
||||||
|
pub(crate) stroke_bind_group: BindGroup,
|
||||||
pub(crate) color_atlas: InnerAtlas,
|
pub(crate) color_atlas: InnerAtlas,
|
||||||
pub(crate) mask_atlas: InnerAtlas,
|
pub(crate) mask_atlas: InnerAtlas,
|
||||||
pub(crate) format: TextureFormat,
|
pub(crate) format: TextureFormat,
|
||||||
|
@ -282,9 +283,34 @@ impl TextAtlas {
|
||||||
&mask_atlas.texture_view,
|
&mask_atlas.texture_view,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// stroke color buffer
|
||||||
|
let stroke_color_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: Some("Stroke Color Buffer"),
|
||||||
|
|
||||||
|
size: 16,
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// stroke width buffer
|
||||||
|
let stroke_width_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: Some("Stroke Width Buffer"),
|
||||||
|
size: 4,
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let stroke_bind_group = cache.create_stroke_bind_group(
|
||||||
|
device,
|
||||||
|
&mask_atlas.texture_view,
|
||||||
|
&stroke_color_buffer,
|
||||||
|
&stroke_width_buffer,
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
cache: cache.clone(),
|
cache: cache.clone(),
|
||||||
bind_group,
|
bind_group,
|
||||||
|
stroke_bind_group,
|
||||||
color_atlas,
|
color_atlas,
|
||||||
mask_atlas,
|
mask_atlas,
|
||||||
format,
|
format,
|
||||||
|
@ -334,6 +360,16 @@ impl TextAtlas {
|
||||||
.get_or_create_pipeline(device, self.format, multisample, depth_stencil)
|
.get_or_create_pipeline(device, self.format, multisample, depth_stencil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_or_create_stroke_pipeline(
|
||||||
|
&self,
|
||||||
|
device: &Device,
|
||||||
|
multisample: MultisampleState,
|
||||||
|
depth_stencil: Option<DepthStencilState>,
|
||||||
|
) -> RenderPipeline {
|
||||||
|
self.cache
|
||||||
|
.get_or_create_stroke_pipeline(device, self.format, multisample, depth_stencil)
|
||||||
|
}
|
||||||
|
|
||||||
fn rebind(&mut self, device: &wgpu::Device) {
|
fn rebind(&mut self, device: &wgpu::Device) {
|
||||||
self.bind_group = self.cache.create_atlas_bind_group(
|
self.bind_group = self.cache.create_atlas_bind_group(
|
||||||
device,
|
device,
|
||||||
|
|
|
@ -19,6 +19,8 @@ pub struct TextRenderer {
|
||||||
pipeline: RenderPipeline,
|
pipeline: RenderPipeline,
|
||||||
glyph_vertices: Vec<GlyphToRender>,
|
glyph_vertices: Vec<GlyphToRender>,
|
||||||
glyphs_to_render: u32,
|
glyphs_to_render: u32,
|
||||||
|
stroke_pipeline: RenderPipeline,
|
||||||
|
stroke: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextRenderer {
|
impl TextRenderer {
|
||||||
|
@ -37,7 +39,9 @@ impl TextRenderer {
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let pipeline = atlas.get_or_create_pipeline(device, multisample, depth_stencil);
|
let pipeline = atlas.get_or_create_pipeline(device, multisample, depth_stencil.clone());
|
||||||
|
let stroke_pipeline =
|
||||||
|
atlas.get_or_create_stroke_pipeline(device, multisample, depth_stencil);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
staging_belt: StagingBelt::new(vertex_buffer_size),
|
staging_belt: StagingBelt::new(vertex_buffer_size),
|
||||||
|
@ -46,6 +50,8 @@ impl TextRenderer {
|
||||||
pipeline,
|
pipeline,
|
||||||
glyph_vertices: Vec::new(),
|
glyph_vertices: Vec::new(),
|
||||||
glyphs_to_render: 0,
|
glyphs_to_render: 0,
|
||||||
|
stroke_pipeline,
|
||||||
|
stroke: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +70,7 @@ impl TextRenderer {
|
||||||
) -> Result<(), PrepareError> {
|
) -> Result<(), PrepareError> {
|
||||||
self.staging_belt.recall();
|
self.staging_belt.recall();
|
||||||
self.glyph_vertices.clear();
|
self.glyph_vertices.clear();
|
||||||
|
atlas.
|
||||||
|
|
||||||
let resolution = viewport.resolution();
|
let resolution = viewport.resolution();
|
||||||
|
|
||||||
|
@ -89,6 +96,7 @@ impl TextRenderer {
|
||||||
|
|
||||||
for run in layout_runs {
|
for run in layout_runs {
|
||||||
if text_area.stroke_size > 0.0 {
|
if text_area.stroke_size > 0.0 {
|
||||||
|
self.stroke = true;
|
||||||
for i in 0..2 {
|
for i in 0..2 {
|
||||||
self.prepare_glyphs(
|
self.prepare_glyphs(
|
||||||
&run,
|
&run,
|
||||||
|
@ -208,6 +216,14 @@ impl TextRenderer {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.stroke {
|
||||||
|
pass.set_pipeline(&self.stroke_pipeline);
|
||||||
|
pass.set_bind_group(0, &atlas.bind_group, &[]);
|
||||||
|
pass.set_bind_group(2, &atlas.stroke_bind_group, &[]);
|
||||||
|
pass.set_bind_group(1, &viewport.bind_group, &[]);
|
||||||
|
pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
||||||
|
pass.draw(0..4, 0..self.glyphs_to_render);
|
||||||
|
}
|
||||||
pass.set_pipeline(&self.pipeline);
|
pass.set_pipeline(&self.pipeline);
|
||||||
pass.set_bind_group(0, &atlas.bind_group, &[]);
|
pass.set_bind_group(0, &atlas.bind_group, &[]);
|
||||||
pass.set_bind_group(1, &viewport.bind_group, &[]);
|
pass.set_bind_group(1, &viewport.bind_group, &[]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue