mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-24 17:28:40 +00:00
WIP: Start on squiggly underlines
This commit is contained in:
parent
a890787923
commit
52594fe250
4 changed files with 141 additions and 3 deletions
|
@ -26,6 +26,7 @@ pub struct Renderer {
|
|||
sprite_pipeline_state: metal::RenderPipelineState,
|
||||
image_pipeline_state: metal::RenderPipelineState,
|
||||
path_atlas_pipeline_state: metal::RenderPipelineState,
|
||||
underline_pipeline_state: metal::RenderPipelineState,
|
||||
unit_vertices: metal::Buffer,
|
||||
instances: metal::Buffer,
|
||||
}
|
||||
|
@ -109,6 +110,14 @@ impl Renderer {
|
|||
"path_atlas_fragment",
|
||||
MTLPixelFormat::R16Float,
|
||||
);
|
||||
let underline_pipeline_state = build_pipeline_state(
|
||||
&device,
|
||||
&library,
|
||||
"underline",
|
||||
"underline_vertex",
|
||||
"underline_fragment",
|
||||
pixel_format,
|
||||
);
|
||||
Self {
|
||||
sprite_cache,
|
||||
image_cache,
|
||||
|
@ -118,6 +127,7 @@ impl Renderer {
|
|||
sprite_pipeline_state,
|
||||
image_pipeline_state,
|
||||
path_atlas_pipeline_state,
|
||||
underline_pipeline_state,
|
||||
unit_vertices,
|
||||
instances,
|
||||
}
|
||||
|
@ -339,7 +349,7 @@ impl Renderer {
|
|||
drawable_size,
|
||||
command_encoder,
|
||||
);
|
||||
self.render_quads(
|
||||
self.render_underlines(
|
||||
layer.underlines(),
|
||||
scale_factor,
|
||||
offset,
|
||||
|
@ -821,6 +831,73 @@ impl Renderer {
|
|||
);
|
||||
*offset = next_offset;
|
||||
}
|
||||
|
||||
fn render_underlines(
|
||||
&mut self,
|
||||
underlines: &[Quad],
|
||||
scale_factor: f32,
|
||||
offset: &mut usize,
|
||||
drawable_size: Vector2F,
|
||||
command_encoder: &metal::RenderCommandEncoderRef,
|
||||
) {
|
||||
if underlines.is_empty() {
|
||||
return;
|
||||
}
|
||||
align_offset(offset);
|
||||
let next_offset = *offset + underlines.len() * mem::size_of::<shaders::GPUIUnderline>();
|
||||
assert!(
|
||||
next_offset <= INSTANCE_BUFFER_SIZE,
|
||||
"instance buffer exhausted"
|
||||
);
|
||||
|
||||
command_encoder.set_render_pipeline_state(&self.underline_pipeline_state);
|
||||
command_encoder.set_vertex_buffer(
|
||||
shaders::GPUIUnderlineInputIndex_GPUIUnderlineInputIndexVertices as u64,
|
||||
Some(&self.unit_vertices),
|
||||
0,
|
||||
);
|
||||
command_encoder.set_vertex_buffer(
|
||||
shaders::GPUIUnderlineInputIndex_GPUIUnderlineInputIndexUnderlines as u64,
|
||||
Some(&self.instances),
|
||||
*offset as u64,
|
||||
);
|
||||
command_encoder.set_vertex_bytes(
|
||||
shaders::GPUIUnderlineInputIndex_GPUIUnderlineInputIndexUniforms as u64,
|
||||
mem::size_of::<shaders::GPUIUniforms>() as u64,
|
||||
[shaders::GPUIUniforms {
|
||||
viewport_size: drawable_size.to_float2(),
|
||||
}]
|
||||
.as_ptr() as *const c_void,
|
||||
);
|
||||
|
||||
let buffer_contents = unsafe {
|
||||
(self.instances.contents() as *mut u8).offset(*offset as isize)
|
||||
as *mut shaders::GPUIUnderline
|
||||
};
|
||||
for (ix, quad) in underlines.iter().enumerate() {
|
||||
let bounds = quad.bounds * scale_factor;
|
||||
let shader_quad = shaders::GPUIUnderline {
|
||||
origin: bounds.origin().round().to_float2(),
|
||||
size: bounds.size().round().to_float2(),
|
||||
thickness: 1. * scale_factor,
|
||||
color: quad
|
||||
.background
|
||||
.unwrap_or(Color::transparent_black())
|
||||
.to_uchar4(),
|
||||
};
|
||||
unsafe {
|
||||
*(buffer_contents.offset(ix as isize)) = shader_quad;
|
||||
}
|
||||
}
|
||||
|
||||
command_encoder.draw_primitives_instanced(
|
||||
metal::MTLPrimitiveType::Triangle,
|
||||
0,
|
||||
6,
|
||||
underlines.len() as u64,
|
||||
);
|
||||
*offset = next_offset;
|
||||
}
|
||||
}
|
||||
|
||||
fn build_path_atlas_texture_descriptor() -> metal::TextureDescriptor {
|
||||
|
|
|
@ -104,3 +104,18 @@ typedef struct
|
|||
vector_uchar4 border_color;
|
||||
float corner_radius;
|
||||
} GPUIImage;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GPUIUnderlineInputIndexVertices = 0,
|
||||
GPUIUnderlineInputIndexUnderlines = 1,
|
||||
GPUIUnderlineInputIndexUniforms = 2,
|
||||
} GPUIUnderlineInputIndex;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vector_float2 origin;
|
||||
vector_float2 size;
|
||||
float thickness;
|
||||
vector_uchar4 color;
|
||||
} GPUIUnderline;
|
||||
|
|
|
@ -304,3 +304,49 @@ fragment float4 path_atlas_fragment(
|
|||
float alpha = saturate(0.5 - distance);
|
||||
return float4(alpha, 0., 0., 1.);
|
||||
}
|
||||
|
||||
struct UnderlineFragmentInput {
|
||||
float4 position [[position]];
|
||||
float2 origin;
|
||||
float2 size;
|
||||
float thickness;
|
||||
float4 color;
|
||||
};
|
||||
|
||||
vertex UnderlineFragmentInput underline_vertex(
|
||||
uint unit_vertex_id [[vertex_id]],
|
||||
uint underline_id [[instance_id]],
|
||||
constant float2 *unit_vertices [[buffer(GPUIUnderlineInputIndexVertices)]],
|
||||
constant GPUIUnderline *underlines [[buffer(GPUIUnderlineInputIndexUnderlines)]],
|
||||
constant GPUIUniforms *uniforms [[buffer(GPUIUnderlineInputIndexUniforms)]]
|
||||
) {
|
||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||
GPUIUnderline underline = underlines[underline_id];
|
||||
float2 position = unit_vertex * underline.size + underline.origin;
|
||||
float4 device_position = to_device_position(position, uniforms->viewport_size);
|
||||
|
||||
return UnderlineFragmentInput {
|
||||
device_position,
|
||||
underline.origin,
|
||||
underline.size,
|
||||
underline.thickness,
|
||||
coloru_to_colorf(underline.color),
|
||||
};
|
||||
}
|
||||
|
||||
fragment float4 underline_fragment(
|
||||
UnderlineFragmentInput input [[stage_in]]
|
||||
) {
|
||||
float half_thickness = input.thickness * 0.5;
|
||||
float2 st = ((input.position.xy - input.origin) / input.size.y) - float2(0., 0.5);
|
||||
float frequency = M_PI_F * 0.75;
|
||||
float amplitude = 0.3;
|
||||
float sine = sin(st.x * frequency) * amplitude;
|
||||
float dSine = cos(st.x * frequency) * amplitude * frequency;
|
||||
float distance = (st.y - sine) / sqrt(1. + dSine * dSine);
|
||||
float distance_in_pixels = distance * input.size.y;
|
||||
float distance_from_top_border = distance_in_pixels - half_thickness;
|
||||
float distance_from_bottom_border = distance_in_pixels + half_thickness;
|
||||
float alpha = saturate(0.5 - max(-distance_from_bottom_border, distance_from_top_border));
|
||||
return input.color * float4(1., 1., 1., alpha);
|
||||
}
|
||||
|
|
|
@ -290,7 +290,7 @@ impl Line {
|
|||
|
||||
if let Some((underline_origin, underline_color)) = finished_underline {
|
||||
cx.scene.push_underline(scene::Quad {
|
||||
bounds: RectF::from_points(underline_origin, glyph_origin + vec2f(0., 1.)),
|
||||
bounds: RectF::from_points(underline_origin, glyph_origin + vec2f(0., 3.)),
|
||||
background: Some(underline_color),
|
||||
border: Default::default(),
|
||||
corner_radius: 0.,
|
||||
|
@ -311,7 +311,7 @@ impl Line {
|
|||
let line_end = origin + baseline_offset + vec2f(self.layout.width, 0.);
|
||||
|
||||
cx.scene.push_underline(scene::Quad {
|
||||
bounds: RectF::from_points(underline_start, line_end + vec2f(0., 1.)),
|
||||
bounds: RectF::from_points(underline_start, line_end + vec2f(0., 3.)),
|
||||
background: Some(underline_color),
|
||||
border: Default::default(),
|
||||
corner_radius: 0.,
|
||||
|
|
Loading…
Reference in a new issue