Text paragraphs, styling, fontconfig
This commit is contained in:
@@ -22,6 +22,7 @@ struct Vertex {
|
||||
struct TextVertex {
|
||||
position: [f32; 2],
|
||||
uv: [f32; 2],
|
||||
color: [f32; 4],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -53,6 +54,7 @@ struct GlyphBitmap {
|
||||
struct PreparedGlyphBitmap {
|
||||
rect: PixelRect,
|
||||
cache_key: CacheKey,
|
||||
color: Color,
|
||||
}
|
||||
|
||||
struct RasterizedText {
|
||||
@@ -124,13 +126,14 @@ struct TextTextureGlyph {
|
||||
local_x_bits: u32,
|
||||
local_y_bits: u32,
|
||||
advance_bits: u32,
|
||||
color: (u8, u8, u8, u8),
|
||||
cache_key: Option<CacheKey>,
|
||||
}
|
||||
|
||||
const VERTEX_ATTRIBUTES: [wgpu::VertexAttribute; 2] =
|
||||
wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x4];
|
||||
const TEXT_VERTEX_ATTRIBUTES: [wgpu::VertexAttribute; 2] =
|
||||
wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2];
|
||||
const TEXT_VERTEX_ATTRIBUTES: [wgpu::VertexAttribute; 3] =
|
||||
wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2, 2 => Float32x4];
|
||||
|
||||
impl Vertex {
|
||||
const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout {
|
||||
@@ -258,11 +261,13 @@ fn fs_main(input: VertexOut) -> @location(0) vec4<f32> {
|
||||
struct VertexIn {
|
||||
@location(0) position: vec2<f32>,
|
||||
@location(1) uv: vec2<f32>,
|
||||
@location(2) color: vec4<f32>,
|
||||
};
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) position: vec4<f32>,
|
||||
@location(0) uv: vec2<f32>,
|
||||
@location(1) color: vec4<f32>,
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var text_texture: texture_2d<f32>;
|
||||
@@ -273,12 +278,13 @@ fn vs_main(input: VertexIn) -> VertexOut {
|
||||
var out: VertexOut;
|
||||
out.position = vec4(input.position, 0.0, 1.0);
|
||||
out.uv = input.uv;
|
||||
out.color = input.color;
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(input: VertexOut) -> @location(0) vec4<f32> {
|
||||
return textureSample(text_texture, text_sampler, input.uv);
|
||||
return textureSample(text_texture, text_sampler, input.uv) * input.color;
|
||||
}
|
||||
"#
|
||||
.into(),
|
||||
@@ -561,7 +567,7 @@ fn fs_main(input: VertexOut) -> @location(0) vec4<f32> {
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
blit_cached_image(&mut pixels, clip, glyph.rect, image, text.color);
|
||||
blit_cached_image(&mut pixels, clip, glyph.rect, image, glyph.color);
|
||||
}
|
||||
|
||||
Some(RasterizedText {
|
||||
@@ -600,6 +606,7 @@ fn fs_main(input: VertexOut) -> @location(0) vec4<f32> {
|
||||
bottom: local_y - image.placement.top + height,
|
||||
},
|
||||
cache_key,
|
||||
color: glyph.color,
|
||||
});
|
||||
}
|
||||
glyphs
|
||||
@@ -670,7 +677,7 @@ fn fs_main(input: VertexOut) -> @location(0) vec4<f32> {
|
||||
let Some(cache_key) = glyph.cache_key else {
|
||||
continue;
|
||||
};
|
||||
let Some(atlas_glyph) = self.ensure_atlas_glyph(cache_key, text.color) else {
|
||||
let Some(atlas_glyph) = self.ensure_atlas_glyph(cache_key, glyph.color) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -689,6 +696,7 @@ fn fs_main(input: VertexOut) -> @location(0) vec4<f32> {
|
||||
atlas_glyph.atlas_rect,
|
||||
clip_rect,
|
||||
scene.logical_size,
|
||||
glyph.color,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1190,31 +1198,38 @@ fn build_text_vertices(origin: Point, size: UiSize, logical_size: UiSize) -> [Te
|
||||
let right = to_ndc_x(origin.x + size.width, logical_size.width.max(1.0));
|
||||
let top = to_ndc_y(origin.y, logical_size.height.max(1.0));
|
||||
let bottom = to_ndc_y(origin.y + size.height, logical_size.height.max(1.0));
|
||||
let color = [1.0, 1.0, 1.0, 1.0];
|
||||
|
||||
[
|
||||
TextVertex {
|
||||
position: [left, top],
|
||||
uv: [0.0, 0.0],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [left, bottom],
|
||||
uv: [0.0, 1.0],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [right, top],
|
||||
uv: [1.0, 0.0],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [right, top],
|
||||
uv: [1.0, 0.0],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [left, bottom],
|
||||
uv: [0.0, 1.0],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [right, bottom],
|
||||
uv: [1.0, 1.0],
|
||||
color,
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -1225,6 +1240,7 @@ fn push_glyph_vertices(
|
||||
atlas_rect: AtlasRect,
|
||||
clip_rect: Option<PixelRect>,
|
||||
logical_size: UiSize,
|
||||
color: Color,
|
||||
) {
|
||||
let Some((dest_rect, uv_rect)) = clipped_glyph_quad(glyph_rect, atlas_rect, clip_rect) else {
|
||||
return;
|
||||
@@ -1235,34 +1251,50 @@ fn push_glyph_vertices(
|
||||
let top = to_ndc_y(dest_rect.top as f32, logical_size.height.max(1.0));
|
||||
let bottom = to_ndc_y(dest_rect.bottom as f32, logical_size.height.max(1.0));
|
||||
|
||||
let color = color_to_f32(color);
|
||||
vertices.extend_from_slice(&[
|
||||
TextVertex {
|
||||
position: [left, top],
|
||||
uv: [uv_rect.0, uv_rect.1],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [left, bottom],
|
||||
uv: [uv_rect.0, uv_rect.3],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [right, top],
|
||||
uv: [uv_rect.2, uv_rect.1],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [right, top],
|
||||
uv: [uv_rect.2, uv_rect.1],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [left, bottom],
|
||||
uv: [uv_rect.0, uv_rect.3],
|
||||
color,
|
||||
},
|
||||
TextVertex {
|
||||
position: [right, bottom],
|
||||
uv: [uv_rect.2, uv_rect.3],
|
||||
color,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
fn color_to_f32(color: Color) -> [f32; 4] {
|
||||
[
|
||||
color.r as f32 / 255.0,
|
||||
color.g as f32 / 255.0,
|
||||
color.b as f32 / 255.0,
|
||||
color.a as f32 / 255.0,
|
||||
]
|
||||
}
|
||||
|
||||
fn build_vertices(scene: &SceneSnapshot) -> Vec<Vertex> {
|
||||
let width = scene.logical_size.width.max(1.0);
|
||||
let height = scene.logical_size.height.max(1.0);
|
||||
@@ -1385,6 +1417,7 @@ fn text_texture_key(text: &PreparedText) -> TextTextureKey {
|
||||
local_x_bits: (glyph.position.x - text.origin.x).to_bits(),
|
||||
local_y_bits: (glyph.position.y - text.origin.y).to_bits(),
|
||||
advance_bits: glyph.advance.to_bits(),
|
||||
color: (glyph.color.r, glyph.color.g, glyph.color.b, glyph.color.a),
|
||||
cache_key: glyph.cache_key,
|
||||
})
|
||||
.collect(),
|
||||
@@ -1443,6 +1476,7 @@ mod tests {
|
||||
glyph: "c".into(),
|
||||
position: Point::new(24.0, 44.0),
|
||||
advance: 8.0,
|
||||
color: Color::rgb(0xEE, 0xEE, 0xEE),
|
||||
cache_key: None,
|
||||
}],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user