Unnamed repository; edit this file 'description' to name the repository.
checkpoint
Blaž Hrastnik 2022-05-01
parent 8dc9ad7 · commit fa4dfba
-rw-r--r--Cargo.lock109
-rw-r--r--Cargo.toml3
-rw-r--r--helix-ui/Cargo.toml3
-rw-r--r--helix-ui/src/main.rs181
-rw-r--r--helix-ui/src/shader.wgsl24
5 files changed, 292 insertions, 28 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 366d5994..adbe8301 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -54,6 +54,12 @@ checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f"
[[package]]
name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
+[[package]]
+name = "arrayvec"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
@@ -136,9 +142,23 @@ checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
[[package]]
name = "bytemuck"
-version = "1.8.0"
+version = "1.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead"
+checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
[[package]]
name = "byteorder"
@@ -596,6 +616,15 @@ dependencies = [
]
[[package]]
+name = "euclid"
+version = "0.22.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b52c2ef4a78da0ba68fbe1fd920627411096d2ac478f7f4c9f3a54ba6705bade"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
name = "fern"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -605,6 +634,15 @@ dependencies = [
]
[[package]]
+name = "float_next_after"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fc612c5837986b7104a87a0df74a5460931f1c5274be12f8d0f40aa2f30d632"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1033,6 +1071,7 @@ dependencies = [
name = "helix-ui"
version = "0.1.0"
dependencies = [
+ "bytemuck",
"console_error_panic_hook",
"env_logger",
"glam",
@@ -1040,6 +1079,7 @@ dependencies = [
"helix-view",
"image",
"instant",
+ "lyon",
"pollster",
"resource",
"swash",
@@ -1297,6 +1337,56 @@ dependencies = [
]
[[package]]
+name = "lyon"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf0510ed5e3e2fb80f3db2061ef5ca92d87bfda1a624bb1eacf3bd50226e4cbb"
+dependencies = [
+ "lyon_algorithms",
+ "lyon_tessellation",
+]
+
+[[package]]
+name = "lyon_algorithms"
+version = "0.17.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8037f716541ba0d84d3de05c0069f8068baf73990d55980558b84d944c8a244a"
+dependencies = [
+ "lyon_path",
+ "sid",
+]
+
+[[package]]
+name = "lyon_geom"
+version = "0.17.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce99ce77c22bfd8f39a95b9c749dffbfc3e2491ea30c874764c801a8b1485489"
+dependencies = [
+ "arrayvec 0.5.2",
+ "euclid",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_path"
+version = "0.17.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0a59fdf767ca0d887aa61d1b48d4bbf6a124c1a45503593f7d38ab945bfbc0"
+dependencies = [
+ "lyon_geom",
+]
+
+[[package]]
+name = "lyon_tessellation"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7230e08dd0638048e46f387f255dbe7a7344a3e6705beab53242b5af25635760"
+dependencies = [
+ "float_next_after",
+ "lyon_path",
+]
+
+[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1936,6 +2026,15 @@ dependencies = [
]
[[package]]
+name = "sid"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd5ac56c121948b4879bba9e519852c211bcdd8f014efff766441deff0b91bdb"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
name = "signal-hook"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2476,7 +2575,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97cd781ff044d6d697b632a2e212032c2e957d1afaa21dbf58069cbb8f78567"
dependencies = [
- "arrayvec",
+ "arrayvec 0.7.2",
"js-sys",
"log",
"naga",
@@ -2497,7 +2596,7 @@ version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4688c000eb841ca55f7b35db659b78d6e1cd77d7caf8fb929f4e181f754047d"
dependencies = [
- "arrayvec",
+ "arrayvec 0.7.2",
"bitflags",
"cfg_aliases",
"codespan-reporting",
@@ -2520,7 +2619,7 @@ version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93b1a9400e8d7f32dd4dd909bb9a391015d70633d639775ddd3f14d1104bc970"
dependencies = [
- "arrayvec",
+ "arrayvec 0.7.2",
"ash",
"bit-set",
"bitflags",
diff --git a/Cargo.toml b/Cargo.toml
index 14ef3072..c577f6ca 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,8 @@ members = [
]
default-members = [
- "helix-term"
+ "helix-term",
+ "helix-ui"
]
resolver = "2"
diff --git a/helix-ui/Cargo.toml b/helix-ui/Cargo.toml
index f101c87c..3bdcfb42 100644
--- a/helix-ui/Cargo.toml
+++ b/helix-ui/Cargo.toml
@@ -20,9 +20,10 @@ instant = "0.1.12"
swash = { git = "https://github.com/dfrg/swash" }
# parley = { git = "https://github.com/dfrg/parley" }
-# lyon = "0.17.10"
+lyon = "0.17.10"
wgpu = "0.12"
pollster = "0.2"
glam = "0.20"
env_logger = "0.6"
+bytemuck = { version = "1.9.1", features = ["derive"] }
diff --git a/helix-ui/src/main.rs b/helix-ui/src/main.rs
index d5037613..61d4ebda 100644
--- a/helix-ui/src/main.rs
+++ b/helix-ui/src/main.rs
@@ -5,6 +5,8 @@ use winit::{
window::Window,
};
+use wgpu::util::DeviceExt;
+
// new femto-like framework:
// wgpu renderer
// kurbo, (alternative is euclid + lyon)
@@ -25,6 +27,28 @@ use swash::{
Attributes, CacheKey, Charmap, FontRef,
};
+use lyon::{
+ math::{point, Transform},
+ path::{builder::*, Path},
+ tessellation::{BuffersBuilder, FillOptions, FillTessellator, FillVertex, VertexBuffers},
+};
+
+use bytemuck::{Pod, Zeroable};
+
+// Vertex for lines drawn by lyon
+#[repr(C)]
+#[derive(Clone, Copy, Debug, Pod, Zeroable)]
+struct Vertex {
+ position: [f32; 2],
+ // color: [f32; 4], // Use this when I want more colors
+}
+
+#[repr(C)]
+#[derive(Clone, Copy, Debug, Pod, Zeroable)]
+struct View {
+ size: [f32; 2],
+}
+
pub struct Font {
// Full content of the font file
data: Vec<u8>,
@@ -71,7 +95,8 @@ impl Font {
}
}
}
-fn font() {
+
+fn font() -> VertexBuffers<Vertex, u16> {
let font = Font::from_file("assets/fonts/Inter Variable/Inter.ttf", 0).unwrap();
let font = font.as_ref();
@@ -114,6 +139,8 @@ fn font() {
// c.glyphs
});
+ // -- Scaling
+
let mut context = ScaleContext::new();
let mut scaler = context
.builder(font)
@@ -124,33 +151,79 @@ fn font() {
let glyph_id = font.charmap().map('Q');
let outline = scaler.scale_outline(glyph_id).unwrap();
- append_outline((), outline.verbs(), outline.points());
+ // -- Tesselation
- // -- Scaling
+ // let mut encoder = Path::builder().transformed(Transform::new(
+ // 0.01, 0., //
+ // 0., 0.01, //
+ // 0., 0.,
+ // ));
+
+ let mut encoder = Path::builder();
+
+ append_outline(&mut encoder, outline.verbs(), outline.points());
+
+ let path = encoder.build();
+
+ let mut geometry: VertexBuffers<Vertex, u16> = VertexBuffers::new();
+
+ let mut tessellator = FillTessellator::new();
+ {
+ // Compute the tessellation.
+ tessellator
+ .tessellate_path(
+ &path,
+ &FillOptions::default(),
+ &mut BuffersBuilder::new(&mut geometry, |vertex: FillVertex| Vertex {
+ position: vertex.position().to_array(),
+ }),
+ )
+ .unwrap();
+ }
+
+ println!("{:?}", geometry);
+ geometry
}
-fn append_outline(_encoder: (), verbs: &[Verb], points: &[Vector]) {
+fn append_outline<T: lyon::path::builder::PathBuilder>(
+ encoder: &mut T,
+ verbs: &[Verb],
+ points: &[Vector],
+) {
+ let mut i = 0;
for verb in verbs {
- println!("{:?}", verb);
match verb {
Verb::MoveTo => {
- //
+ let p = points[i];
+ // TODO: can MoveTo appear halfway through?
+ encoder.begin(point(p.x, p.y));
+ i += 1;
}
Verb::LineTo => {
- //
+ let p = points[i];
+ encoder.line_to(point(p.x, p.y));
+ i += 1;
}
Verb::QuadTo => {
- //
+ let p1 = points[i];
+ let p2 = points[i + 1];
+ encoder.quadratic_bezier_to(point(p1.x, p1.y), point(p2.x, p2.y));
+ i += 2;
}
Verb::CurveTo => {
- //
+ let p1 = points[i];
+ let p2 = points[i + 1];
+ let p3 = points[i + 2];
+ encoder.cubic_bezier_to(point(p1.x, p1.y), point(p2.x, p2.y), point(p3.x, p3.y));
+ i += 3;
}
Verb::Close => {
- //
+ encoder.close();
}
}
}
}
+
async fn run(event_loop: EventLoop<()>, window: Window) {
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::Backends::all());
@@ -186,10 +259,62 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
});
+ // ---
+
+ let geometry = font();
+
+ let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+ label: Some("Vertex Buffer"),
+ contents: bytemuck::cast_slice(&geometry.vertices),
+ usage: wgpu::BufferUsages::VERTEX,
+ });
+
+ let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+ label: Some("Index Buffer"),
+ contents: bytemuck::cast_slice(&geometry.indices),
+ usage: wgpu::BufferUsages::INDEX,
+ });
+
+ //
+
+ let data = View { size: [0.0, 0.0] };
+
+ let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+ label: Some("Uniform Buffer"),
+ contents: bytemuck::cast_slice(&[data]),
+ usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
+ });
+
+ let uniform_bind_group_layout =
+ device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
+ entries: &[wgpu::BindGroupLayoutEntry {
+ binding: 0,
+ visibility: wgpu::ShaderStages::VERTEX,
+ ty: wgpu::BindingType::Buffer {
+ ty: wgpu::BufferBindingType::Uniform,
+ has_dynamic_offset: false,
+ min_binding_size: None,
+ },
+ count: None,
+ }],
+ label: Some("uniform_bind_group_layout"),
+ });
+
+ let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+ layout: &uniform_bind_group_layout,
+ entries: &[wgpu::BindGroupEntry {
+ binding: 0,
+ resource: uniform_buffer.as_entire_binding(),
+ }],
+ label: Some("uniform_bind_group"),
+ });
+
+ //
+
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
- bind_group_layouts: &[],
- push_constant_ranges: &[],
+ bind_group_layouts: &[&uniform_bind_group_layout], // &texture_bind_group_layout
+ push_constant_ranges: &[], // TODO: could use push constants for uniforms but that's not available on web
});
let swapchain_format = surface.get_preferred_format(&adapter).unwrap();
@@ -200,7 +325,11 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
- buffers: &[],
+ buffers: &[wgpu::VertexBufferLayout {
+ array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
+ step_mode: wgpu::VertexStepMode::Vertex,
+ attributes: &wgpu::vertex_attr_array![0 => Float32x2],
+ }],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
@@ -223,7 +352,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
surface.configure(&device, &config);
- font();
+ //
event_loop.run(move |event, _, control_flow| {
// Have the closure take ownership of the resources.
@@ -253,6 +382,20 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
+
+ // TODO: need to use queue.write_buffer or staging_belt to write to it
+
+ // Pass the current window size in
+ let dpi_factor = window.scale_factor();
+ let size = window.inner_size();
+ let winit::dpi::LogicalSize { width, height } = size.to_logical::<f32>(dpi_factor);
+
+ let data = View {
+ size: [width, height],
+ };
+
+ queue.write_buffer(&uniform_buffer, 0, bytemuck::cast_slice(&[data]));
+
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
@@ -260,14 +403,20 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
- load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
+ load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: true,
},
}],
depth_stencil_attachment: None,
});
+
+ // rpass.set_viewport();
+
rpass.set_pipeline(&render_pipeline);
- rpass.draw(0..3, 0..1);
+ rpass.set_bind_group(0, &uniform_bind_group, &[]);
+ rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint16);
+ rpass.set_vertex_buffer(0, vertex_buffer.slice(..));
+ rpass.draw_indexed(0..(geometry.indices.len() as u32), 0, 0..1);
}
queue.submit(Some(encoder.finish()));
diff --git a/helix-ui/src/shader.wgsl b/helix-ui/src/shader.wgsl
index a1ef447d..f8d654d7 100644
--- a/helix-ui/src/shader.wgsl
+++ b/helix-ui/src/shader.wgsl
@@ -1,11 +1,25 @@
+
+// struct Vertex {
+// [[location(0)]] position: vec2<f32>;
+// };
+
+struct View {
+ size: vec2<f32>;
+};
+
+[[group(0), binding(0)]]
+var<uniform> view: View;
+
[[stage(vertex)]]
-fn vs_main([[builtin(vertex_index)]] in_vertex_index: u32) -> [[builtin(position)]] vec4<f32> {
- let x = f32(i32(in_vertex_index) - 1);
- let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
- return vec4<f32>(x, y, 0.0, 1.0);
+fn vs_main([[location(0)]] input: vec2<f32>) -> [[builtin(position)]] vec4<f32> {
+ // TODO: scale by hidpi factor?
+ return vec4<f32>(
+ input.xy / view.size.xy * 2.0 * 1.5,
+ 0.0, 1.0
+ );
}
[[stage(fragment)]]
fn fs_main() -> [[location(0)]] vec4<f32> {
- return vec4<f32>(1.0, 0.0, 0.0, 1.0);
+ return vec4<f32>(1.0, 1.0, 1.0, 1.0);
}