mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-07 17:26:56 +00:00
WIP
This commit is contained in:
parent
92bda1231e
commit
2e056e9b0b
8 changed files with 366 additions and 11 deletions
|
@ -52,6 +52,8 @@ fn generate_shader_bindings() -> PathBuf {
|
||||||
"AtlasTile".into(),
|
"AtlasTile".into(),
|
||||||
"QuadInputIndex".into(),
|
"QuadInputIndex".into(),
|
||||||
"Quad".into(),
|
"Quad".into(),
|
||||||
|
"ShadowInputIndex".into(),
|
||||||
|
"Shadow".into(),
|
||||||
"SpriteInputIndex".into(),
|
"SpriteInputIndex".into(),
|
||||||
"MonochromeSprite".into(),
|
"MonochromeSprite".into(),
|
||||||
"PolychromeSprite".into(),
|
"PolychromeSprite".into(),
|
||||||
|
|
|
@ -469,6 +469,17 @@ impl Edges<AbsoluteLength> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Edges<Pixels> {
|
||||||
|
pub fn scale(&self, factor: f32) -> Edges<ScaledPixels> {
|
||||||
|
Edges {
|
||||||
|
top: self.top.scale(factor),
|
||||||
|
right: self.right.scale(factor),
|
||||||
|
bottom: self.bottom.scale(factor),
|
||||||
|
left: self.left.scale(factor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
|
#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
|
||||||
#[refineable(debug)]
|
#[refineable(debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -480,8 +491,8 @@ pub struct Corners<T: Clone + Debug> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Corners<AbsoluteLength> {
|
impl Corners<AbsoluteLength> {
|
||||||
pub fn to_pixels(&self, bounds: Bounds<Pixels>, rem_size: Pixels) -> Corners<Pixels> {
|
pub fn to_pixels(&self, size: Size<Pixels>, rem_size: Pixels) -> Corners<Pixels> {
|
||||||
let max = bounds.size.width.max(bounds.size.height) / 2.;
|
let max = size.width.max(size.height) / 2.;
|
||||||
Corners {
|
Corners {
|
||||||
top_left: self.top_left.to_pixels(rem_size).min(max),
|
top_left: self.top_left.to_pixels(rem_size).min(max),
|
||||||
top_right: self.top_right.to_pixels(rem_size).min(max),
|
top_right: self.top_right.to_pixels(rem_size).min(max),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite,
|
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite,
|
||||||
Quad, Scene, Size,
|
Quad, Scene, Shadow, Size,
|
||||||
};
|
};
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
base::{NO, YES},
|
base::{NO, YES},
|
||||||
|
@ -18,6 +18,7 @@ pub struct MetalRenderer {
|
||||||
layer: metal::MetalLayer,
|
layer: metal::MetalLayer,
|
||||||
command_queue: CommandQueue,
|
command_queue: CommandQueue,
|
||||||
quads_pipeline_state: metal::RenderPipelineState,
|
quads_pipeline_state: metal::RenderPipelineState,
|
||||||
|
shadows_pipeline_state: metal::RenderPipelineState,
|
||||||
monochrome_sprites_pipeline_state: metal::RenderPipelineState,
|
monochrome_sprites_pipeline_state: metal::RenderPipelineState,
|
||||||
polychrome_sprites_pipeline_state: metal::RenderPipelineState,
|
polychrome_sprites_pipeline_state: metal::RenderPipelineState,
|
||||||
unit_vertices: metal::Buffer,
|
unit_vertices: metal::Buffer,
|
||||||
|
@ -90,6 +91,14 @@ impl MetalRenderer {
|
||||||
"quad_fragment",
|
"quad_fragment",
|
||||||
PIXEL_FORMAT,
|
PIXEL_FORMAT,
|
||||||
);
|
);
|
||||||
|
let shadows_pipeline_state = build_pipeline_state(
|
||||||
|
&device,
|
||||||
|
&library,
|
||||||
|
"shadows",
|
||||||
|
"shadow_vertex",
|
||||||
|
"shadow_fragment",
|
||||||
|
PIXEL_FORMAT,
|
||||||
|
);
|
||||||
let monochrome_sprites_pipeline_state = build_pipeline_state(
|
let monochrome_sprites_pipeline_state = build_pipeline_state(
|
||||||
&device,
|
&device,
|
||||||
&library,
|
&library,
|
||||||
|
@ -114,6 +123,7 @@ impl MetalRenderer {
|
||||||
layer,
|
layer,
|
||||||
command_queue,
|
command_queue,
|
||||||
quads_pipeline_state,
|
quads_pipeline_state,
|
||||||
|
shadows_pipeline_state,
|
||||||
monochrome_sprites_pipeline_state,
|
monochrome_sprites_pipeline_state,
|
||||||
polychrome_sprites_pipeline_state,
|
polychrome_sprites_pipeline_state,
|
||||||
unit_vertices,
|
unit_vertices,
|
||||||
|
@ -183,6 +193,14 @@ impl MetalRenderer {
|
||||||
command_encoder,
|
command_encoder,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
crate::PrimitiveBatch::Shadows(shadows) => {
|
||||||
|
self.draw_shadows(
|
||||||
|
shadows,
|
||||||
|
&mut instance_offset,
|
||||||
|
viewport_size,
|
||||||
|
command_encoder,
|
||||||
|
);
|
||||||
|
}
|
||||||
crate::PrimitiveBatch::MonochromeSprites {
|
crate::PrimitiveBatch::MonochromeSprites {
|
||||||
texture_id,
|
texture_id,
|
||||||
sprites,
|
sprites,
|
||||||
|
@ -279,6 +297,66 @@ impl MetalRenderer {
|
||||||
*offset = next_offset;
|
*offset = next_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_shadows(
|
||||||
|
&mut self,
|
||||||
|
shadows: &[Shadow],
|
||||||
|
offset: &mut usize,
|
||||||
|
viewport_size: Size<DevicePixels>,
|
||||||
|
command_encoder: &metal::RenderCommandEncoderRef,
|
||||||
|
) {
|
||||||
|
if shadows.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
align_offset(offset);
|
||||||
|
|
||||||
|
command_encoder.set_render_pipeline_state(&self.shadows_pipeline_state);
|
||||||
|
command_encoder.set_vertex_buffer(
|
||||||
|
ShadowInputIndex::Vertices as u64,
|
||||||
|
Some(&self.unit_vertices),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
command_encoder.set_vertex_buffer(
|
||||||
|
ShadowInputIndex::Shadows as u64,
|
||||||
|
Some(&self.instances),
|
||||||
|
*offset as u64,
|
||||||
|
);
|
||||||
|
command_encoder.set_fragment_buffer(
|
||||||
|
ShadowInputIndex::Shadows as u64,
|
||||||
|
Some(&self.instances),
|
||||||
|
*offset as u64,
|
||||||
|
);
|
||||||
|
|
||||||
|
command_encoder.set_vertex_bytes(
|
||||||
|
ShadowInputIndex::ViewportSize as u64,
|
||||||
|
mem::size_of_val(&viewport_size) as u64,
|
||||||
|
&viewport_size as *const Size<DevicePixels> as *const _,
|
||||||
|
);
|
||||||
|
|
||||||
|
let shadow_bytes_len = mem::size_of::<Shadow>() * shadows.len();
|
||||||
|
let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) };
|
||||||
|
unsafe {
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
shadows.as_ptr() as *const u8,
|
||||||
|
buffer_contents,
|
||||||
|
shadow_bytes_len,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let next_offset = *offset + shadow_bytes_len;
|
||||||
|
assert!(
|
||||||
|
next_offset <= INSTANCE_BUFFER_SIZE,
|
||||||
|
"instance buffer exhausted"
|
||||||
|
);
|
||||||
|
|
||||||
|
command_encoder.draw_primitives_instanced(
|
||||||
|
metal::MTLPrimitiveType::Triangle,
|
||||||
|
0,
|
||||||
|
6,
|
||||||
|
shadows.len() as u64,
|
||||||
|
);
|
||||||
|
*offset = next_offset;
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_monochrome_sprites(
|
fn draw_monochrome_sprites(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture_id: AtlasTextureId,
|
texture_id: AtlasTextureId,
|
||||||
|
@ -469,6 +547,13 @@ enum QuadInputIndex {
|
||||||
ViewportSize = 2,
|
ViewportSize = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
enum ShadowInputIndex {
|
||||||
|
Vertices = 0,
|
||||||
|
Shadows = 1,
|
||||||
|
ViewportSize = 2,
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
enum SpriteInputIndex {
|
enum SpriteInputIndex {
|
||||||
Vertices = 0,
|
Vertices = 0,
|
||||||
|
|
|
@ -11,6 +11,9 @@ float2 to_tile_position(float2 unit_vertex, AtlasTile tile,
|
||||||
constant Size_DevicePixels *atlas_size);
|
constant Size_DevicePixels *atlas_size);
|
||||||
float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
|
float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
|
||||||
Corners_ScaledPixels corner_radii);
|
Corners_ScaledPixels corner_radii);
|
||||||
|
float gaussian(float x, float sigma);
|
||||||
|
float2 erf(float2 x);
|
||||||
|
float blur_along_x(float x, float y, float sigma, float corner, float2 half_size);
|
||||||
|
|
||||||
struct QuadVertexOutput {
|
struct QuadVertexOutput {
|
||||||
float4 position [[position]];
|
float4 position [[position]];
|
||||||
|
@ -110,6 +113,91 @@ fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]],
|
||||||
return color * float4(1., 1., 1., saturate(0.5 - distance));
|
return color * float4(1., 1., 1., saturate(0.5 - distance));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ShadowVertexOutput {
|
||||||
|
float4 position [[position]];
|
||||||
|
float4 color [[flat]];
|
||||||
|
uint shadow_id [[flat]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex ShadowVertexOutput shadow_vertex(
|
||||||
|
uint unit_vertex_id [[vertex_id]],
|
||||||
|
uint shadow_id [[instance_id]],
|
||||||
|
constant float2 *unit_vertices [[buffer(ShadowInputIndex_Vertices)]],
|
||||||
|
constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]],
|
||||||
|
constant Size_DevicePixels *viewport_size [[buffer(ShadowInputIndex_ViewportSize)]]
|
||||||
|
) {
|
||||||
|
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||||
|
Shadow shadow = shadows[shadow_id];
|
||||||
|
|
||||||
|
float margin = (3. * shadow.blur_radius) + shadow.spread_radius;
|
||||||
|
// Set the bounds of the shadow and adjust its size based on the shadow's spread radius
|
||||||
|
// to achieve the spreading effect
|
||||||
|
Bounds_ScaledPixels bounds = shadow.bounds;
|
||||||
|
bounds.origin.x -= margin;
|
||||||
|
bounds.origin.y -= margin;
|
||||||
|
bounds.size.width += 2. * margin;
|
||||||
|
bounds.size.height += 2. * margin;
|
||||||
|
|
||||||
|
float4 device_position = to_device_position(unit_vertex, bounds, bounds, viewport_size);
|
||||||
|
float4 color = hsla_to_rgba(shadow.color);
|
||||||
|
|
||||||
|
return ShadowVertexOutput {
|
||||||
|
device_position,
|
||||||
|
color,
|
||||||
|
shadow_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 shadow_fragment(
|
||||||
|
ShadowVertexOutput input [[stage_in]],
|
||||||
|
constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]]
|
||||||
|
) {
|
||||||
|
Shadow shadow = shadows[input.shadow_id];
|
||||||
|
|
||||||
|
float2 origin = float2(
|
||||||
|
shadow.bounds.origin.x - shadow.spread_radius,
|
||||||
|
shadow.bounds.origin.y - shadow.spread_radius
|
||||||
|
);
|
||||||
|
float2 size = float2(
|
||||||
|
shadow.bounds.size.width + shadow.spread_radius * 2.,
|
||||||
|
shadow.bounds.size.height + shadow.spread_radius * 2.
|
||||||
|
);
|
||||||
|
float2 half_size = size / 2.;
|
||||||
|
float2 center = origin + half_size;
|
||||||
|
float2 point = input.position.xy - center;
|
||||||
|
float corner_radius;
|
||||||
|
if (point.x < 0.) {
|
||||||
|
if (point.y < 0.) {
|
||||||
|
corner_radius = shadow.corner_radii.top_left;
|
||||||
|
} else {
|
||||||
|
corner_radius = shadow.corner_radii.bottom_left;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (point.y < 0.) {
|
||||||
|
corner_radius = shadow.corner_radii.top_right;
|
||||||
|
} else {
|
||||||
|
corner_radius = shadow.corner_radii.bottom_right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The signal is only non-zero in a limited range, so don't waste samples
|
||||||
|
float low = point.y - half_size.y;
|
||||||
|
float high = point.y + half_size.y;
|
||||||
|
float start = clamp(-3. * shadow.blur_radius, low, high);
|
||||||
|
float end = clamp(3. * shadow.blur_radius, low, high);
|
||||||
|
|
||||||
|
// Accumulate samples (we can get away with surprisingly few samples)
|
||||||
|
float step = (end - start) / 4.;
|
||||||
|
float y = start + step * 0.5;
|
||||||
|
float alpha = 0.;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
alpha += blur_along_x(point.x, point.y - y, shadow.blur_radius, corner_radius, half_size) * gaussian(y, shadow.blur_radius) * step;
|
||||||
|
y += step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.color * float4(1., 1., 1., alpha);
|
||||||
|
}
|
||||||
|
|
||||||
struct MonochromeSpriteVertexOutput {
|
struct MonochromeSpriteVertexOutput {
|
||||||
float4 position [[position]];
|
float4 position [[position]];
|
||||||
float2 tile_position;
|
float2 tile_position;
|
||||||
|
@ -308,3 +396,24 @@ float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
|
||||||
|
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A standard gaussian function, used for weighting samples
|
||||||
|
float gaussian(float x, float sigma) {
|
||||||
|
return exp(-(x * x) / (2. * sigma * sigma)) / (sqrt(2. * M_PI_F) * sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This approximates the error function, needed for the gaussian integral
|
||||||
|
float2 erf(float2 x) {
|
||||||
|
float2 s = sign(x);
|
||||||
|
float2 a = abs(x);
|
||||||
|
x = 1. + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
|
||||||
|
x *= x;
|
||||||
|
return s - s / (x * x);
|
||||||
|
}
|
||||||
|
|
||||||
|
float blur_along_x(float x, float y, float sigma, float corner, float2 half_size) {
|
||||||
|
float delta = min(half_size.y - corner - abs(y), 0.);
|
||||||
|
float curved = half_size.x - corner + sqrt(max(0., corner * corner - delta * delta));
|
||||||
|
float2 integral = 0.5 + 0.5 * erf((x + float2(-curved, curved)) * (sqrt(0.5) / sigma));
|
||||||
|
return integral.y - integral.x;
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@ impl Scene {
|
||||||
Primitive::Quad(quad) => {
|
Primitive::Quad(quad) => {
|
||||||
layer.quads.push(quad);
|
layer.quads.push(quad);
|
||||||
}
|
}
|
||||||
|
Primitive::Shadow(shadow) => {
|
||||||
|
layer.shadows.push(shadow);
|
||||||
|
}
|
||||||
Primitive::MonochromeSprite(sprite) => {
|
Primitive::MonochromeSprite(sprite) => {
|
||||||
layer.monochrome_sprites.push(sprite);
|
layer.monochrome_sprites.push(sprite);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +58,7 @@ impl Scene {
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct SceneLayer {
|
pub(crate) struct SceneLayer {
|
||||||
pub quads: Vec<Quad>,
|
pub quads: Vec<Quad>,
|
||||||
|
pub shadows: Vec<Shadow>,
|
||||||
pub monochrome_sprites: Vec<MonochromeSprite>,
|
pub monochrome_sprites: Vec<MonochromeSprite>,
|
||||||
pub polychrome_sprites: Vec<PolychromeSprite>,
|
pub polychrome_sprites: Vec<PolychromeSprite>,
|
||||||
}
|
}
|
||||||
|
@ -68,6 +72,9 @@ impl SceneLayer {
|
||||||
quads: &self.quads,
|
quads: &self.quads,
|
||||||
quads_start: 0,
|
quads_start: 0,
|
||||||
quads_iter: self.quads.iter().peekable(),
|
quads_iter: self.quads.iter().peekable(),
|
||||||
|
shadows: &self.shadows,
|
||||||
|
shadows_start: 0,
|
||||||
|
shadows_iter: self.shadows.iter().peekable(),
|
||||||
monochrome_sprites: &self.monochrome_sprites,
|
monochrome_sprites: &self.monochrome_sprites,
|
||||||
monochrome_sprites_start: 0,
|
monochrome_sprites_start: 0,
|
||||||
monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
|
monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
|
||||||
|
@ -82,6 +89,9 @@ struct BatchIterator<'a> {
|
||||||
quads: &'a [Quad],
|
quads: &'a [Quad],
|
||||||
quads_start: usize,
|
quads_start: usize,
|
||||||
quads_iter: Peekable<slice::Iter<'a, Quad>>,
|
quads_iter: Peekable<slice::Iter<'a, Quad>>,
|
||||||
|
shadows: &'a [Shadow],
|
||||||
|
shadows_start: usize,
|
||||||
|
shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
|
||||||
monochrome_sprites: &'a [MonochromeSprite],
|
monochrome_sprites: &'a [MonochromeSprite],
|
||||||
monochrome_sprites_start: usize,
|
monochrome_sprites_start: usize,
|
||||||
monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
|
monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
|
||||||
|
@ -96,6 +106,10 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let mut kinds_and_orders = [
|
let mut kinds_and_orders = [
|
||||||
(PrimitiveKind::Quad, self.quads_iter.peek().map(|q| q.order)),
|
(PrimitiveKind::Quad, self.quads_iter.peek().map(|q| q.order)),
|
||||||
|
(
|
||||||
|
PrimitiveKind::Shadow,
|
||||||
|
self.shadows_iter.peek().map(|s| s.order),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
PrimitiveKind::MonochromeSprite,
|
PrimitiveKind::MonochromeSprite,
|
||||||
self.monochrome_sprites_iter.peek().map(|s| s.order),
|
self.monochrome_sprites_iter.peek().map(|s| s.order),
|
||||||
|
@ -127,6 +141,19 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||||
self.quads_start = quads_end;
|
self.quads_start = quads_end;
|
||||||
Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
|
Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
|
||||||
}
|
}
|
||||||
|
PrimitiveKind::Shadow => {
|
||||||
|
let shadows_start = self.shadows_start;
|
||||||
|
let shadows_end = shadows_start
|
||||||
|
+ self
|
||||||
|
.shadows_iter
|
||||||
|
.by_ref()
|
||||||
|
.take_while(|shadow| shadow.order <= max_order)
|
||||||
|
.count();
|
||||||
|
self.shadows_start = shadows_end;
|
||||||
|
Some(PrimitiveBatch::Shadows(
|
||||||
|
&self.shadows[shadows_start..shadows_end],
|
||||||
|
))
|
||||||
|
}
|
||||||
PrimitiveKind::MonochromeSprite => {
|
PrimitiveKind::MonochromeSprite => {
|
||||||
let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
|
let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
|
||||||
let sprites_start = self.monochrome_sprites_start;
|
let sprites_start = self.monochrome_sprites_start;
|
||||||
|
@ -168,6 +195,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum PrimitiveKind {
|
pub enum PrimitiveKind {
|
||||||
Quad,
|
Quad,
|
||||||
|
Shadow,
|
||||||
MonochromeSprite,
|
MonochromeSprite,
|
||||||
PolychromeSprite,
|
PolychromeSprite,
|
||||||
}
|
}
|
||||||
|
@ -175,12 +203,15 @@ pub enum PrimitiveKind {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Primitive {
|
pub enum Primitive {
|
||||||
Quad(Quad),
|
Quad(Quad),
|
||||||
|
Shadow(Shadow),
|
||||||
MonochromeSprite(MonochromeSprite),
|
MonochromeSprite(MonochromeSprite),
|
||||||
PolychromeSprite(PolychromeSprite),
|
PolychromeSprite(PolychromeSprite),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) enum PrimitiveBatch<'a> {
|
pub(crate) enum PrimitiveBatch<'a> {
|
||||||
Quads(&'a [Quad]),
|
Quads(&'a [Quad]),
|
||||||
|
Shadows(&'a [Shadow]),
|
||||||
MonochromeSprites {
|
MonochromeSprites {
|
||||||
texture_id: AtlasTextureId,
|
texture_id: AtlasTextureId,
|
||||||
sprites: &'a [MonochromeSprite],
|
sprites: &'a [MonochromeSprite],
|
||||||
|
@ -221,6 +252,36 @@ impl From<Quad> for Primitive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Shadow {
|
||||||
|
pub order: u32,
|
||||||
|
pub bounds: Bounds<ScaledPixels>,
|
||||||
|
pub corner_radii: Corners<ScaledPixels>,
|
||||||
|
pub content_mask: ScaledContentMask,
|
||||||
|
pub color: Hsla,
|
||||||
|
pub blur_radius: ScaledPixels,
|
||||||
|
pub spread_radius: ScaledPixels,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Shadow {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.order.cmp(&other.order)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Shadow {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Shadow> for Primitive {
|
||||||
|
fn from(shadow: Shadow) -> Self {
|
||||||
|
Primitive::Shadow(shadow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct MonochromeSprite {
|
pub struct MonochromeSprite {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners,
|
phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners,
|
||||||
CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle,
|
CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle,
|
||||||
FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle,
|
FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle, Shadow,
|
||||||
SharedString, Size, SizeRefinement, ViewContext, WindowContext,
|
SharedString, Size, SizeRefinement, ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
|
@ -89,10 +89,21 @@ pub struct Style {
|
||||||
#[refineable]
|
#[refineable]
|
||||||
pub corner_radii: Corners<AbsoluteLength>,
|
pub corner_radii: Corners<AbsoluteLength>,
|
||||||
|
|
||||||
|
/// Box Shadow of the element
|
||||||
|
pub box_shadow: Option<BoxShadow>,
|
||||||
|
|
||||||
/// TEXT
|
/// TEXT
|
||||||
pub text: TextStyleRefinement,
|
pub text: TextStyleRefinement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct BoxShadow {
|
||||||
|
pub color: Hsla,
|
||||||
|
pub offset: Point<Pixels>,
|
||||||
|
pub blur_radius: Pixels,
|
||||||
|
pub spread_radius: Pixels,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Refineable, Clone, Debug)]
|
#[derive(Refineable, Clone, Debug)]
|
||||||
#[refineable(debug)]
|
#[refineable(debug)]
|
||||||
pub struct TextStyle {
|
pub struct TextStyle {
|
||||||
|
@ -233,6 +244,28 @@ impl Style {
|
||||||
let rem_size = cx.rem_size();
|
let rem_size = cx.rem_size();
|
||||||
let scale = cx.scale_factor();
|
let scale = cx.scale_factor();
|
||||||
|
|
||||||
|
if let Some(shadow) = self.box_shadow.as_ref() {
|
||||||
|
let layer_id = cx.current_layer_id();
|
||||||
|
let content_mask = cx.content_mask();
|
||||||
|
let mut shadow_bounds = bounds;
|
||||||
|
shadow_bounds.origin += shadow.offset;
|
||||||
|
cx.scene().insert(
|
||||||
|
layer_id,
|
||||||
|
Shadow {
|
||||||
|
order,
|
||||||
|
bounds: shadow_bounds.scale(scale),
|
||||||
|
content_mask: content_mask.scale(scale),
|
||||||
|
corner_radii: self
|
||||||
|
.corner_radii
|
||||||
|
.to_pixels(bounds.size, rem_size)
|
||||||
|
.scale(scale),
|
||||||
|
color: shadow.color,
|
||||||
|
blur_radius: shadow.blur_radius.scale(scale),
|
||||||
|
spread_radius: shadow.spread_radius.scale(scale),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let background_color = self.fill.as_ref().and_then(Fill::color);
|
let background_color = self.fill.as_ref().and_then(Fill::color);
|
||||||
if background_color.is_some() || self.is_border_visible() {
|
if background_color.is_some() || self.is_border_visible() {
|
||||||
let layer_id = cx.current_layer_id();
|
let layer_id = cx.current_layer_id();
|
||||||
|
@ -247,10 +280,9 @@ impl Style {
|
||||||
border_color: self.border_color.unwrap_or_default(),
|
border_color: self.border_color.unwrap_or_default(),
|
||||||
corner_radii: self
|
corner_radii: self
|
||||||
.corner_radii
|
.corner_radii
|
||||||
.map(|length| length.to_pixels(rem_size).scale(scale)),
|
.to_pixels(bounds.size, rem_size)
|
||||||
border_widths: self
|
.scale(scale),
|
||||||
.border_widths
|
border_widths: self.border_widths.to_pixels(rem_size).scale(scale),
|
||||||
.map(|length| length.to_pixels(rem_size).scale(scale)),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -296,6 +328,7 @@ impl Default for Style {
|
||||||
fill: None,
|
fill: None,
|
||||||
border_color: None,
|
border_color: None,
|
||||||
corner_radii: Corners::default(),
|
corner_radii: Corners::default(),
|
||||||
|
box_shadow: None,
|
||||||
text: TextStyleRefinement::default(),
|
text: TextStyleRefinement::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
self as gpui3, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, JustifyContent,
|
self as gpui3, hsla, point, px, relative, rems, AlignItems, BoxShadow, Display, Fill,
|
||||||
Length, Position, SharedString, Style, StyleRefinement, Styled, TextStyleRefinement,
|
FlexDirection, Hsla, JustifyContent, Length, Position, SharedString, Style, StyleRefinement,
|
||||||
|
Styled, TextStyleRefinement,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait StyleHelpers: Styled<Style = Style> {
|
pub trait StyleHelpers: Styled<Style = Style> {
|
||||||
|
@ -213,6 +214,58 @@ pub trait StyleHelpers: Styled<Style = Style> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn shadow(mut self) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shadow_sm(mut self) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.declared_style().box_shadow = Some(BoxShadow {
|
||||||
|
color: hsla(0., 0., 0., 1.),
|
||||||
|
offset: point(px(0.), px(0.)),
|
||||||
|
blur_radius: px(1.),
|
||||||
|
spread_radius: px(0.),
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shadow_md(mut self) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
todo!();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shadow_lg(mut self) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
todo!();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shadow_xl(mut self) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
todo!();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shadow_2xl(mut self) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
todo!();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
|
fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
|
||||||
let style: &mut StyleRefinement = self.declared_style();
|
let style: &mut StyleRefinement = self.declared_style();
|
||||||
&mut style.text
|
&mut style.text
|
||||||
|
|
|
@ -168,7 +168,8 @@ impl CollabPanel {
|
||||||
.uri(avatar_uri)
|
.uri(avatar_uri)
|
||||||
.size_3p5()
|
.size_3p5()
|
||||||
.rounded_full()
|
.rounded_full()
|
||||||
.fill(theme.middle.positive.default.foreground),
|
.fill(theme.middle.positive.default.foreground)
|
||||||
|
.shadow_sm(),
|
||||||
)
|
)
|
||||||
.child(label),
|
.child(label),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue