From 983f892895c19a07b037bd164f57ee676f74e015 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Fri, 18 Nov 2022 23:39:00 +0100 Subject: [PATCH] First attempt at GPU-generated text --- Cargo.lock | 227 +++++++++++++++++++++++++++++ Cargo.toml | 1 + src/canvas.rs | 8 +- src/main.rs | 42 +++--- src/renderer.rs | 11 +- src/sprite/shaders/text.wgsl | 38 +++++ src/sprite/shaders/texture.wgsl | 2 +- src/sprite/text_sprite.rs | 245 +++++++++++++++++++++++++++++++- src/sprite/texture_sprite.rs | 2 +- 9 files changed, 547 insertions(+), 29 deletions(-) create mode 100644 src/sprite/shaders/text.wgsl diff --git a/Cargo.lock b/Cargo.lock index 8c6b8a7..c168926 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,6 +147,7 @@ dependencies = [ "cgmath", "chrono", "fern", + "font-kit", "image", "log", "pollster", @@ -206,6 +207,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "cmake" +version = "0.1.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" +dependencies = [ + "cc", +] + [[package]] name = "cocoa" version = "0.24.1" @@ -264,6 +274,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "const-cstr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" + [[package]] name = "copyless" version = "0.1.5" @@ -339,6 +355,18 @@ dependencies = [ "libc", ] +[[package]] +name = "core-text" +version = "19.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +dependencies = [ + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "foreign-types", + "libc", +] + [[package]] name = "core-video-sys" version = "0.1.4" @@ -457,6 +485,27 @@ dependencies = [ "syn", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -478,6 +527,18 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dwrote" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "fern" version = "0.6.1" @@ -498,12 +559,43 @@ dependencies = [ "miniz_oxide 0.5.4", ] +[[package]] +name = "float-ord" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "font-kit" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21fe28504d371085fae9ac7a3450f0b289ab71e07c8e57baa3fb68b9e57d6ce5" +dependencies = [ + "bitflags", + "byteorder", + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "core-text", + "dirs-next", + "dwrote", + "float-ord", + "freetype", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "walkdir", + "winapi", + "yeslogic-fontconfig-sys", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -519,6 +611,27 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "freetype" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6" +dependencies = [ + "freetype-sys", + "libc", +] + +[[package]] +name = "freetype-sys" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" +dependencies = [ + "cmake", + "libc", + "pkg-config", +] + [[package]] name = "fxhash" version = "0.2.1" @@ -1084,12 +1197,41 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39fe46acc5503595e5949c17b818714d26fdf9b4920eacf3b2947f0199f4a6ff" +dependencies = [ + "rustc_version", +] + [[package]] name = "percent-encoding" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pest" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" +dependencies = [ + "thiserror", + "ucd-trie", +] + [[package]] name = "pkg-config" version = "0.3.26" @@ -1173,6 +1315,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + [[package]] name = "renderdoc-sys" version = "0.7.1" @@ -1185,6 +1338,24 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1203,6 +1374,24 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.147" @@ -1319,6 +1508,12 @@ dependencies = [ "serde", ] +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + [[package]] name = "unicode-ident" version = "1.0.5" @@ -1343,6 +1538,17 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -1719,6 +1925,15 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + [[package]] name = "x11-dl" version = "2.20.0" @@ -1744,3 +1959,15 @@ name = "xml-rs" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + +[[package]] +name = "yeslogic-fontconfig-sys" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bbd69036d397ebbff671b1b8e4d918610c181c5a16073b96f984a38d08c386" +dependencies = [ + "const-cstr", + "dlib", + "once_cell", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 9b66401..22396f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ fern = { version = "^0.6.1", features = ["colored"] } bitflags = "^1.3.2" cgmath = { version = "^0.18.0", features = ["bytemuck"] } pollster = "^0.2.5" +font-kit = "^0.11.0" # surface creation winit = "^0.26.1" diff --git a/src/canvas.rs b/src/canvas.rs index 83dd4cc..9da8f89 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -80,8 +80,12 @@ impl Canvas { ) } - pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite { - unimplemented!(); + pub fn create_text_sprite(&mut self, text: &'static str, size: Size) -> TextSprite { + TextSprite::new( + text, + size, + &self.renderer, + ) } pub fn create_shape_sprite(&mut self) -> ShapeSprite { diff --git a/src/main.rs b/src/main.rs index d842145..34f49be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use canvas::{ Application, Canvas, texture::TextureHandle, - sprite::TextureSprite, + sprite::{TextureSprite, TextSprite}, utils::Position, }; @@ -40,6 +40,7 @@ struct ExampleState { pub texture: TextureHandle, pub tex_sprite: TextureSprite, pub sub_sprite: TextureSprite, + pub txt_sprite: TextSprite, pub last_instant: Instant, pub last_offset: u32, pub last_pos: Position, @@ -62,6 +63,8 @@ impl Application for ExampleApp { let mut sub_sprite = canvas.create_texture_sprite(Size {w: 200, h: 200}); sub_sprite.set_texture(texture.clone(), Some(Position {x: 350, y: 0}), 1.0); + let txt_sprite = canvas.create_text_sprite(".", Size {w: 10, h: 10}); + canvas.clear(); canvas.update(); @@ -71,6 +74,7 @@ impl Application for ExampleApp { texture, tex_sprite, sub_sprite, + txt_sprite, last_instant, last_offset: 0, last_pos: Position::origin(), @@ -81,21 +85,21 @@ impl Application for ExampleApp { fn tick(state: &mut ExampleState, canvas: &mut Canvas) -> Result<(), &'static str> { use canvas::sprite::Sprite; - let now = Instant::now(); - let elapsed = now.duration_since(state.last_instant).as_millis(); - state.last_instant = now; - debug!("frame time: {}ms", elapsed); + //let now = Instant::now(); + //let elapsed = now.duration_since(state.last_instant).as_millis(); + //state.last_instant = now; + //debug!("frame time: {}ms", elapsed); - //state.sub_sprite.for_each(|pix| unsafe {pix.flat = pix.flat.wrapping_add(1);}); + ////state.sub_sprite.for_each(|pix| unsafe {pix.flat = pix.flat.wrapping_add(1);}); - state.last_offset += 1; - state.last_pos.y += 1; - state.last_rot += 1.0; - state.tex_sprite.set_texture(state.texture.clone(), None, state.last_rot/100.0); - state.sub_sprite.set_texture(state.texture.clone(), - Some(Position {x: state.last_offset, y: 0}), 1.0); - state.sub_sprite.set_position(state.last_pos); - state.sub_sprite.set_rotation(state.last_rot); + //state.last_offset += 1; + //state.last_pos.y += 1; + //state.last_rot += 1.0; + //state.tex_sprite.set_texture(state.texture.clone(), None, state.last_rot/100.0); + //state.sub_sprite.set_texture(state.texture.clone(), + // Some(Position {x: state.last_offset, y: 0}), 1.0); + //state.sub_sprite.set_position(state.last_pos); + //state.sub_sprite.set_rotation(state.last_rot); //state.sub_sprite.set_scale(state.last_rot/1000.0); @@ -142,7 +146,7 @@ impl Application for ExampleApp { //canvas.draw(&pix_sprite); //// floating text - //let mut txt_sprite = canvas.create_text_sprite(Size {w: 10, h: 10}, 5.0); + //let mut txt_sprite = canvas.create_text_sprite(".", Size {w: 10, h: 10}); //txt_sprite.set_text("text"); //txt_sprite.set_color(Color::BLACK); @@ -154,8 +158,10 @@ impl Application for ExampleApp { //canvas.draw(&txt_sprite); - canvas.draw(&mut state.tex_sprite); - canvas.draw(&mut state.sub_sprite); + //canvas.draw(&mut state.tex_sprite); + //canvas.draw(&mut state.sub_sprite); + canvas.clear(); + canvas.draw(&mut state.txt_sprite); canvas.update(); Ok(()) @@ -167,6 +173,6 @@ fn main() -> Result<(), &'static str> { setup_logger() .map_err(|_| "Failed to setup logger")?; - canvas::run_canvas("vk_example", Size {w: 1280, h: 720}, ExampleApp {}); + canvas::run_canvas("vk_example", Size {w: 1920, h: 1080}, ExampleApp {}); } diff --git a/src/renderer.rs b/src/renderer.rs index c29662a..f63e39d 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -64,11 +64,18 @@ impl WgpuRenderer { None, // Trace path ).await.unwrap(); + debug!("formats: {:#?}", surface.get_supported_formats(&adapter)); + let format = *surface.get_supported_formats(&adapter) + .into_iter() + .filter(|f| f == &wgpu::TextureFormat::Rgba8UnormSrgb) + .collect::>() + .first() + .ok_or_else(|| "Current adapter incompatible with required surface format")?; + let config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, //first format in the list is preferred - format: *surface.get_supported_formats(&adapter).first() - .ok_or_else(|| { "Surface is incompatible with current adapter" })?, + format, width: size.w, height: size.h, present_mode: wgpu::PresentMode::Fifo, diff --git a/src/sprite/shaders/text.wgsl b/src/sprite/shaders/text.wgsl new file mode 100644 index 0000000..8099f7c --- /dev/null +++ b/src/sprite/shaders/text.wgsl @@ -0,0 +1,38 @@ +// Vertex shader + +struct VertexInput { + @location(0) position: vec2, + @location(1) tex_coords: vec2, +} + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) tex_coords: vec2, +} + +@group(0)@binding(0) + var model_matrix: mat3x3; + +@vertex +fn vs_main(model: VertexInput) -> VertexOutput { + + var out: VertexOutput; + out.tex_coords = model.tex_coords; + out.clip_position + = vec4(model_matrix * vec3(model.position, 1.0), 1.0); + return out; +} + +// Fragment shader + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4 { + + var pos = in.tex_coords; + if abs(pos.x * pos.x - pos.y) < 0.8 { + return vec4(0.0, 1.0, 0.0, 1.0); + } else { + return vec4(1.0, 0.0, 0.0, 1.0); + } +} + diff --git a/src/sprite/shaders/texture.wgsl b/src/sprite/shaders/texture.wgsl index db20088..793838f 100644 --- a/src/sprite/shaders/texture.wgsl +++ b/src/sprite/shaders/texture.wgsl @@ -18,7 +18,7 @@ fn vs_main(model: VertexInput) -> VertexOutput { var out: VertexOutput; out.tex_coords = model.tex_coords; - out.clip_position + out.clip_position = vec4(model_matrix * vec3(model.position, 1.0), 1.0); return out; } diff --git a/src/sprite/text_sprite.rs b/src/sprite/text_sprite.rs index 1b30bc1..65dcaf8 100644 --- a/src/sprite/text_sprite.rs +++ b/src/sprite/text_sprite.rs @@ -4,25 +4,141 @@ use log::{debug, error, info, trace, warn}; //--Internal imports-------------------------------------------------------------------------------- use crate::{ - renderer::WgpuRenderer, + renderer::{ + utils::Mesh, + WgpuRenderer, ModelMatrix + }, sprite::Sprite, utils::{Pixel, Position, Size}, }; //--External imports-------------------------------------------------------------------------------- -use cgmath::Matrix4; +use wgpu; +use std::cell::RefCell; + + +thread_local!(static PIPELINE : RefCell> = RefCell::new(None)); //--TextSprite struct------------------------------------------------------------------------------- #[allow(dead_code)] pub struct TextSprite { - matrix: Matrix4, + matrix: ModelMatrix, + + mesh: Mesh, + size: Size, text: &'static str, //TODO: temporary } impl TextSprite { + pub fn new(text: &'static str, size: Size, renderer: &WgpuRenderer) -> Self { + use font_kit::{ + family_name::FamilyName, + source::SystemSource, + properties::Properties, + outline::{OutlineBuilder, Outline}, + }; + + // initialize pipeline if needed + PIPELINE.with(|cell| { + if cell.borrow().is_none() { + cell.replace(Some(initialize_pipeline(renderer))); + } + }); + + let font = SystemSource::new() + .select_best_match(&[FamilyName::SansSerif], &Properties::new()) + .unwrap() + .load() + .unwrap(); + + let mut outline_builder = OutlineBuilder::new(); + + let outlines : Vec = text.chars().map(|char| { + use font_kit::hinting::HintingOptions; + + let glyph = font.glyph_for_char(char).unwrap(); + let _ = font.outline(glyph, HintingOptions::None, &mut outline_builder).unwrap(); + + outline_builder.take_outline() + }).collect(); + + //TODO improve that + let mut mesh = Vec::::new(); + for outline in &outlines { + for contour in &outline.contours { + for i in 0..(contour.positions.len() - 1) { + use font_kit::outline::PointFlags; + + match contour.flags[i] { + PointFlags::CONTROL_POINT_0 => (), + _ => { + + mesh.push(TextVertex { + position: [ + contour.positions[i].x(), + contour.positions[i].y(), + ], + tex_coords: [0.0, 0.5], + }); + + match contour.flags[i+1] { + PointFlags::CONTROL_POINT_0 => { + mesh.push(TextVertex { + position: [ + contour.positions[i+1].x(), + contour.positions[i+1].y(), + ], + tex_coords: [0.0, 1.0], + }); + mesh.push(TextVertex { + position: [ + contour.positions[i+2].x(), + contour.positions[i+2].y(), + ], + tex_coords: [1.0, 1.0], + }); + }, + _ => { + mesh.push(TextVertex { + position: [ + contour.positions[i].x(), + contour.positions[i].y(), + ], + tex_coords: [0.0, 1.0], + }); + mesh.push(TextVertex { + position: [ + contour.positions[i+1].x(), + contour.positions[i+1].y(), + ], + tex_coords: [1.0, 1.0], + }); + }, + }; + }, + } + } + } + } + + debug!("outlines: {:#?}", outlines); + debug!("mesh: {:#?}", mesh); + + let mut sprite = Self { + matrix: ModelMatrix::default(renderer), + mesh: Mesh::new(&renderer.device), + size, + text, + }; + + sprite.mesh.set_vertices(renderer, &mesh[..]); + + sprite + } + pub fn set_text(&mut self, _text: &'static str) { todo!(); } @@ -50,8 +166,127 @@ impl Sprite for TextSprite { todo!(); } - fn render(&mut self, _renderer: &mut WgpuRenderer) { - todo!(); + fn render(&mut self, renderer: &mut WgpuRenderer) { + + // create command encoder + let mut encoder = renderer.device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render Encoder"), + }); + + PIPELINE.with(|pipeline| { + let pipeline = pipeline.borrow(); + + let view = renderer.create_texture_view(); + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, store: true, }, + })], + depth_stencil_attachment: None, + }); + + render_pass.set_pipeline(pipeline.as_ref().unwrap()); + render_pass.set_vertex_buffer(0, self.mesh.get_vertex_buffer_slice()); + //render_pass.set_index_buffer(self.mesh.get_index_buffer_slice(), + // wgpu::IndexFormat::Uint16); + render_pass.set_bind_group(0, + self.matrix.get_uniform().get_bind_group(&renderer.queue), + &[]); + render_pass.draw(0..100, 0..1); + //render_pass.draw_indexed(0..6, 0, 0..1); + + drop(render_pass); + }); + + renderer.queue.submit(std::iter::once(encoder.finish())); + + } +} + +//--Pipeline initialization------------------------------------------------------------------------- +fn initialize_pipeline(renderer: &WgpuRenderer) -> wgpu::RenderPipeline { + + let shader = renderer.device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("text shader"), + source: wgpu::ShaderSource::Wgsl(include_str!("shaders/text.wgsl").into()), + }); + + let render_pipeline_layout = + renderer.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("texture render pipeline layout"), + bind_group_layouts: &[ + &renderer.matrix_layout, + ], + push_constant_ranges: &[], + }); + + renderer.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("texture render pipeline"), + layout: Some(&render_pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[ + TextVertex::layout(), + ], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: renderer.config.format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None,//Some(wgpu::Face::Back), + // Setting this to anything other than Fill requires + // Features::NON_FILL_POLYGON_MODE + polygon_mode: wgpu::PolygonMode::Fill, + // Requires Features::DEPTH_CLIP_CONTROL + unclipped_depth: false, + // Requires Features::CONSERVATIVE_RASTERIZATION + conservative: false, + }, + depth_stencil: None, + // multisampling, we don't need it + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + }) +} + +//--TextVertex struct------------------------------------------------------------------------------- + +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +pub struct TextVertex { + pub position: [f32; 2], + pub tex_coords: [f32; 2], +} + +impl TextVertex { + + const ATTRIBS: [wgpu::VertexAttribute; 2] = + wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2]; + + pub fn layout<'a>() -> wgpu::VertexBufferLayout<'a> { + wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &Self::ATTRIBS, + } } } diff --git a/src/sprite/texture_sprite.rs b/src/sprite/texture_sprite.rs index 110ca7e..1fcc56e 100644 --- a/src/sprite/texture_sprite.rs +++ b/src/sprite/texture_sprite.rs @@ -275,7 +275,7 @@ pub struct TextureVertex { impl TextureVertex { const ATTRIBS: [wgpu::VertexAttribute; 2] = - wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2]; + wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2]; pub fn layout<'a>() -> wgpu::VertexBufferLayout<'a> { wgpu::VertexBufferLayout {