Skip to content

Commit

Permalink
implement cosmic_text as the text renderer and editor
Browse files Browse the repository at this point in the history
  • Loading branch information
msparkles committed Sep 10, 2024
1 parent 136f88d commit 4ed97ee
Show file tree
Hide file tree
Showing 42 changed files with 1,590 additions and 828 deletions.
1 change: 1 addition & 0 deletions crates/bootstrap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ profile = ["profiling/profile-with-tracy", "tracy-client"]
[dependencies]
yakui = { path = "../yakui" }
yakui-app = { path = "../yakui-app" }
yakui-widgets = { path = "../yakui-widgets" }
yakui-wgpu = { path = "../yakui-wgpu" }
yakui-winit = { path = "../yakui-winit" }

Expand Down
427 changes: 427 additions & 0 deletions crates/bootstrap/assets/OpenMoji-LICENSE.txt

Large diffs are not rendered by default.

Binary file not shown.
22 changes: 14 additions & 8 deletions crates/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod custom_texture;

use std::fmt::Write;
use std::sync::Arc;
use std::time::Instant;

use winit::{
Expand All @@ -10,10 +11,13 @@ use winit::{
};

use winit::window::{Window, WindowAttributes, WindowId};
use yakui::font::{Font, FontSettings, Fonts};
use yakui::font::Fonts;
use yakui::paint::{Texture, TextureFilter, TextureFormat};
use yakui::{ManagedTextureId, Rect, TextureId, UVec2, Vec2, Yakui};
use yakui_app::Graphics;
use yakui_widgets::cosmic_text::fontdb;

pub const OPENMOJI: &[u8] = include_bytes!("../assets/OpenMoji-color-glyf_colr_0.ttf");

const MONKEY_PNG: &[u8] = include_bytes!("../assets/monkey.png");
const MONKEY_BLURRED_PNG: &[u8] = include_bytes!("../assets/monkey-blurred.png");
Expand Down Expand Up @@ -61,7 +65,11 @@ impl<T: ExampleBody> ApplicationHandler for App<T> {

let sample_count = get_sample_count();

let mut app = pollster::block_on(yakui_app::Graphics::new(&window, sample_count));
let mut app = pollster::block_on(yakui_app::Graphics::new(
&mut self.yak,
&window,
sample_count,
));

// By default, yakui_winit will measure the system's scale factor and pass
// it to yakui.
Expand Down Expand Up @@ -232,13 +240,11 @@ fn run(body: impl ExampleBody) {

// Add a custom font for some of the examples.
let fonts = yak.dom().get_global_or_init(Fonts::default);
let font = Font::from_bytes(
include_bytes!("../assets/Hack-Regular.ttf").as_slice(),
FontSettings::default(),
)
.unwrap();

fonts.add(font, Some("monospace"));
static HACK_REGULAR: &[u8] = include_bytes!("../assets/Hack-Regular.ttf");

fonts.load_font_source(fontdb::Source::Binary(Arc::from(&HACK_REGULAR)));
fonts.set_monospace_family("Hack");

// Set up some default state that we'll modify later.
let mut app = App {
Expand Down
2 changes: 1 addition & 1 deletion crates/demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn app() {

async fn run(event_loop: EventLoop<()>, window: Window) {
let mut yak = Yakui::new();
let mut graphics = Graphics::new(&window, 4).await;
let mut graphics = Graphics::new(&mut yak, &window, 4).await;

event_loop.set_control_flow(ControlFlow::Poll);
event_loop
Expand Down
4 changes: 2 additions & 2 deletions crates/yakui-app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub struct Graphics {
}

impl Graphics {
pub async fn new(window: &Window, sample_count: u32) -> Self {
pub async fn new(state: &mut yakui_core::Yakui, window: &Window, sample_count: u32) -> Self {
let mut size = window.inner_size();

// FIXME: On web, we're receiving (0, 0) as the initial size of the
Expand Down Expand Up @@ -85,7 +85,7 @@ impl Graphics {

// yakui_wgpu takes paint output from yakui and renders it for us using
// wgpu.
let renderer = yakui_wgpu::YakuiWgpu::new(&device, &queue);
let renderer = yakui_wgpu::YakuiWgpu::new(state, &device, &queue);

// yakui_winit processes winit events and applies them to our yakui
// state.
Expand Down
2 changes: 1 addition & 1 deletion crates/yakui-core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub enum WidgetEvent {
},

/// Text was sent to the widget.
TextInput(char),
TextInput(char, Modifiers),

/// The widget was focused or unfocused.
FocusChanged(bool),
Expand Down
2 changes: 1 addition & 1 deletion crates/yakui-core/src/input/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ impl InputState {
// Panic safety: if this node is in the layout DOM, it must be
// in the DOM.
let mut node = dom.get_mut(id).unwrap();
let event = WidgetEvent::TextInput(c);
let event = WidgetEvent::TextInput(c, self.modifiers.get());
return self.fire_event(dom, layout, id, &mut node, &event);
}
}
Expand Down
24 changes: 24 additions & 0 deletions crates/yakui-core/src/paint/paint_dom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ use super::layers::PaintLayers;
use super::primitives::{PaintMesh, Vertex};
use super::texture::{Texture, TextureChange};

#[derive(Debug, Clone, Copy, Default)]
/// Contains all information about the limits of the paint device.
pub struct PaintLimits {
/// Maximum texture size of a 1D texture.
pub max_texture_size_1d: u32,
/// Maximum texture size of a 2D texture.
pub max_texture_size_2d: u32,
/// Maximum texture size of a 3D texture.
pub max_texture_size_3d: u32,
}

/// Contains all information about how to paint the current set of widgets.
#[derive(Debug)]
pub struct PaintDom {
Expand All @@ -22,6 +33,7 @@ pub struct PaintDom {
surface_size: Vec2,
unscaled_viewport: Rect,
scale_factor: f32,
limits: PaintLimits,

layers: PaintLayers,
clip_stack: Vec<Rect>,
Expand All @@ -36,11 +48,23 @@ impl PaintDom {
surface_size: Vec2::ONE,
unscaled_viewport: Rect::ONE,
scale_factor: 1.0,
limits: PaintLimits::default(),

layers: PaintLayers::new(),
clip_stack: Vec::new(),
}
}

/// Gets the paint limits.
pub fn limits(&self) -> PaintLimits {
self.limits
}

/// Sets the paint limits, should be called once by rendering backends.
pub fn set_limit(&mut self, limits: PaintLimits) {
self.limits = limits
}

/// Prepares the PaintDom to be updated for the frame.
pub fn start(&mut self) {
self.texture_edits.clear();
Expand Down
4 changes: 4 additions & 0 deletions crates/yakui-core/src/paint/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ pub enum TextureFormat {
/// color channels are sRGB-encoded.
Rgba8Srgb,

/// Red, green, blue, and alpha channels, each represented as a `u8`. The
/// color channels are sRGB-encoded and premultiplied by the alpha.
Rgba8SrgbPremultiplied,

/// A single color channel represented as a `u8`.
R8,
}
Expand Down
7 changes: 6 additions & 1 deletion crates/yakui-core/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::geometry::{Rect, Vec2};
use crate::id::ManagedTextureId;
use crate::input::InputState;
use crate::layout::LayoutDom;
use crate::paint::{PaintDom, Texture};
use crate::paint::{PaintDom, PaintLimits, Texture};

/// The entrypoint for yakui.
#[derive(Debug)]
Expand Down Expand Up @@ -120,4 +120,9 @@ impl Yakui {
pub fn layout_dom(&self) -> &LayoutDom {
&self.layout
}

/// Sets the paint limits, should be called once by rendering backends.
pub fn set_paint_limit(&mut self, limits: PaintLimits) {
self.paint.set_limit(limits)
}
}
2 changes: 1 addition & 1 deletion crates/yakui-core/tests/regression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl Widget for KeyboardWidget {
}

fn event(&mut self, _ctx: EventContext<'_>, event: &WidgetEvent) -> EventResponse {
if let WidgetEvent::TextInput(_) = event {
if let WidgetEvent::TextInput(..) = event {
self.count.fetch_add(1, Ordering::SeqCst);
}

Expand Down
2 changes: 1 addition & 1 deletion crates/yakui-to-image/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ pub fn paint_and_save_to<P: AsRef<Path>>(state: &mut yakui_core::Yakui, path: P)

pub fn paint(state: &mut yakui_core::Yakui) -> RgbaImage {
let graphics = pollster::block_on(Graphics::new());
let mut renderer = yakui_wgpu::YakuiWgpu::new(&graphics.device, &graphics.queue);
let mut renderer = yakui_wgpu::YakuiWgpu::new(state, &graphics.device, &graphics.queue);
graphics.paint(state, &mut renderer)
}
8 changes: 7 additions & 1 deletion crates/yakui-vulkan/examples/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ fn main() {
&vulkan_test.device,
vulkan_test.present_queue,
vulkan_test.device_memory_properties,
vulkan_test.device_properties,
);
let mut options = yakui_vulkan::Options::default();
options.render_pass = vulkan_test.render_pass;
let mut yakui_vulkan = YakuiVulkan::new(&vulkan_context, options);
let mut yakui_vulkan = YakuiVulkan::new(&mut yak, &vulkan_context, options);
// Prepare for one frame in flight
yakui_vulkan.transfers_submitted();
let gui_state = GuiState {
Expand Down Expand Up @@ -93,6 +94,7 @@ fn main() {
&vulkan_test.device,
vulkan_test.present_queue,
vulkan_test.device_memory_properties,
vulkan_test.device_properties,
);

yak.start();
Expand Down Expand Up @@ -232,6 +234,7 @@ struct VulkanTest {
instance: ash::Instance,
surface_loader: ash::khr::surface::Instance,
device_memory_properties: vk::PhysicalDeviceMemoryProperties,
device_properties: vk::PhysicalDeviceProperties,

present_queue: vk::Queue,

Expand Down Expand Up @@ -511,6 +514,8 @@ impl VulkanTest {
let device_memory_properties =
unsafe { instance.get_physical_device_memory_properties(physical_device) };

let device_properties = unsafe { instance.get_physical_device_properties(physical_device) };

Self {
device,
physical_device,
Expand All @@ -520,6 +525,7 @@ impl VulkanTest {
surface_loader,
swapchain_info,
device_memory_properties,
device_properties,
surface,
swapchain,
present_image_views,
Expand Down
13 changes: 10 additions & 3 deletions crates/yakui-vulkan/shaders/main.frag
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@ void main() {
}

if (workflow == WORKFLOW_TEXT) {
float coverage = texture(textures[texture_id], in_uv).r;
out_color = in_color * coverage;
vec4 coverage = texture(textures[texture_id], in_uv);

if (in_color.a > 0.0) {
float alpha = max(max(coverage.r, coverage.g), coverage.b) * in_color.a * coverage.a;

out_color = vec4(in_color.rgb * alpha, alpha);
} else {
out_color = coverage;
}
} else {
vec4 user_texture = texture(textures[texture_id], in_uv);
out_color = in_color * user_texture;
}
}
}
Binary file modified crates/yakui-vulkan/shaders/main.frag.spv
Binary file not shown.
13 changes: 12 additions & 1 deletion crates/yakui-vulkan/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub use vulkan_context::VulkanContext;
use vulkan_texture::{UploadQueue, NO_TEXTURE_ID};
pub use vulkan_texture::{VulkanTexture, VulkanTextureCreateInfo};
use yakui::geometry::UVec2;
use yakui::paint::PaintLimits;
use yakui::{paint::Vertex as YakuiVertex, ManagedTextureId};

/// A struct wrapping everything needed to render yakui on Vulkan. This will be your main entry point.
Expand Down Expand Up @@ -151,7 +152,17 @@ impl YakuiVulkan {
/// ## Safety
/// - `vulkan_context` must have valid members
/// - the members of `render_surface` must have been created with the same [`ash::Device`] as `vulkan_context`.
pub fn new(vulkan_context: &VulkanContext, options: Options) -> Self {
pub fn new(
state: &mut yakui_core::Yakui,
vulkan_context: &VulkanContext,
options: Options,
) -> Self {
state.set_paint_limit(PaintLimits {
max_texture_size_1d: vulkan_context.properties.limits.max_image_dimension1_d,
max_texture_size_2d: vulkan_context.properties.limits.max_image_dimension2_d,
max_texture_size_3d: vulkan_context.properties.limits.max_image_dimension3_d,
});

let device = vulkan_context.device;
let descriptors = Descriptors::new(vulkan_context);

Expand Down
4 changes: 4 additions & 0 deletions crates/yakui-vulkan/src/vulkan_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub struct VulkanContext<'a> {
pub queue: vk::Queue,
/// Memory properties used for [`crate::YakuiVulkan`]'s allocation commands
pub memory_properties: vk::PhysicalDeviceMemoryProperties,
/// Device properties used for setting paint limits
pub properties: vk::PhysicalDeviceProperties,
}

impl<'a> VulkanContext<'a> {
Expand All @@ -26,11 +28,13 @@ impl<'a> VulkanContext<'a> {
device: &'a ash::Device,
queue: vk::Queue,
memory_properties: vk::PhysicalDeviceMemoryProperties,
properties: vk::PhysicalDeviceProperties,
) -> Self {
Self {
device,
queue,
memory_properties,
properties,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/yakui-vulkan/src/vulkan_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ impl VulkanTexture {
fn get_format(yakui_format: yakui::paint::TextureFormat) -> vk::Format {
match yakui_format {
yakui::paint::TextureFormat::Rgba8Srgb => vk::Format::R8G8B8A8_SRGB,
yakui::paint::TextureFormat::Rgba8SrgbPremultiplied => vk::Format::R8G8B8A8_SRGB,
yakui::paint::TextureFormat::R8 => vk::Format::R8_UNORM,
_ => panic!("Unsupported texture format: {yakui_format:?}"),
}
Expand Down
11 changes: 8 additions & 3 deletions crates/yakui-wgpu/shaders/text.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ fn vs_main(

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let coverage = textureSample(coverage_texture, coverage_sampler, in.texcoord).r;
let alpha = coverage * in.color.a;
let coverage = textureSample(coverage_texture, coverage_sampler, in.texcoord);

return vec4(in.color.rgb * alpha, alpha);
if in.color.a > 0.0 {
let alpha = max(max(coverage.r, coverage.g), coverage.b) * in.color.a * coverage.a;

return vec4(in.color.rgb * alpha, alpha);
} else {
return coverage;
}
}
10 changes: 8 additions & 2 deletions crates/yakui-wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use bytemuck::{Pod, Zeroable};
use glam::UVec2;
use thunderdome::{Arena, Index};
use yakui_core::geometry::{Rect, Vec2, Vec4};
use yakui_core::paint::{PaintDom, Pipeline, Texture, TextureChange, TextureFormat};
use yakui_core::paint::{PaintDom, PaintLimits, Pipeline, Texture, TextureChange, TextureFormat};
use yakui_core::{ManagedTextureId, TextureId};

use self::bindgroup_cache::TextureBindgroupCache;
Expand Down Expand Up @@ -67,7 +67,13 @@ impl Vertex {
}

impl YakuiWgpu {
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> Self {
pub fn new(state: &mut yakui_core::Yakui, device: &wgpu::Device, queue: &wgpu::Queue) -> Self {
state.set_paint_limit(PaintLimits {
max_texture_size_1d: device.limits().max_texture_dimension_1d,
max_texture_size_2d: device.limits().max_texture_dimension_2d,
max_texture_size_3d: device.limits().max_texture_dimension_3d,
});

let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("yakui Bind Group Layout"),
entries: &[
Expand Down
7 changes: 7 additions & 0 deletions crates/yakui-wgpu/src/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ fn data_layout(format: TextureFormat, size: UVec2) -> wgpu::ImageDataLayout {
bytes_per_row: Some(4 * size.x),
rows_per_image: Some(size.y),
},
TextureFormat::Rgba8SrgbPremultiplied => wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(4 * size.x),
rows_per_image: Some(size.y),
},
TextureFormat::R8 => wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(size.x),
Expand All @@ -121,6 +126,7 @@ fn data_layout(format: TextureFormat, size: UVec2) -> wgpu::ImageDataLayout {
fn wgpu_format(format: TextureFormat) -> wgpu::TextureFormat {
match format {
TextureFormat::Rgba8Srgb => wgpu::TextureFormat::Rgba8UnormSrgb,
TextureFormat::Rgba8SrgbPremultiplied => wgpu::TextureFormat::Rgba8UnormSrgb,
TextureFormat::R8 => wgpu::TextureFormat::R8Unorm,
_ => panic!("Unsupported texture format {format:?}"),
}
Expand Down Expand Up @@ -157,6 +163,7 @@ fn premultiply_alpha(texture: &Texture) -> Cow<'_, Texture> {

Cow::Owned(texture)
}
TextureFormat::Rgba8SrgbPremultiplied => Cow::Borrowed(texture),
TextureFormat::R8 => Cow::Borrowed(texture),
_ => Cow::Borrowed(texture),
}
Expand Down
Loading

0 comments on commit 4ed97ee

Please sign in to comment.