From b8172906b4f2377c1b7f47bfd87769636d9f2578 Mon Sep 17 00:00:00 2001 From: StarArawn <toasterthegamer@gmail.com> Date: Wed, 24 Nov 2021 15:00:13 -0500 Subject: [PATCH] Delete old renderer. --- bevy_kayak_ui/src/render/quad/mod.rs | 43 --- bevy_kayak_ui/src/render/quad/pipeline.rs | 344 ----------------- bevy_kayak_ui/src/render/quad/shader.wgsl | 30 -- bevy_kayak_ui/src/render/text/font.rs | 8 - bevy_kayak_ui/src/render/text/font_mapping.rs | 40 -- .../src/render/text/font_texture_cache.rs | 201 ---------- bevy_kayak_ui/src/render/text/mod.rs | 141 ------- bevy_kayak_ui/src/render/text/pipeline.rs | 360 ------------------ bevy_kayak_ui/src/render/text/shader.wgsl | 45 --- 9 files changed, 1212 deletions(-) delete mode 100644 bevy_kayak_ui/src/render/quad/mod.rs delete mode 100644 bevy_kayak_ui/src/render/quad/pipeline.rs delete mode 100644 bevy_kayak_ui/src/render/quad/shader.wgsl delete mode 100644 bevy_kayak_ui/src/render/text/font.rs delete mode 100644 bevy_kayak_ui/src/render/text/font_mapping.rs delete mode 100644 bevy_kayak_ui/src/render/text/font_texture_cache.rs delete mode 100644 bevy_kayak_ui/src/render/text/mod.rs delete mode 100644 bevy_kayak_ui/src/render/text/pipeline.rs delete mode 100644 bevy_kayak_ui/src/render/text/shader.wgsl diff --git a/bevy_kayak_ui/src/render/quad/mod.rs b/bevy_kayak_ui/src/render/quad/mod.rs deleted file mode 100644 index 222f983..0000000 --- a/bevy_kayak_ui/src/render/quad/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -use bevy::{ - prelude::{Assets, HandleUntyped, Plugin}, - reflect::TypeUuid, - render2::{render_phase::DrawFunctions, render_resource::Shader, RenderApp, RenderStage}, -}; - -use crate::render::{ - quad::pipeline::{DrawQuad, QuadMeta, QuadPipeline}, - ui_pass::TransparentUI, -}; - -mod pipeline; - -pub const QUAD_SHADER_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 7604018236855288450); - -#[derive(Default)] -pub struct QuadRendererPlugin; - -impl Plugin for QuadRendererPlugin { - fn build(&self, app: &mut bevy::prelude::App) { - let mut shaders = app.world.get_resource_mut::<Assets<Shader>>().unwrap(); - let quad_shader = Shader::from_wgsl(include_str!("shader.wgsl")); - shaders.set_untracked(QUAD_SHADER_HANDLE, quad_shader); - - let render_app = app.sub_app(RenderApp); - render_app - .init_resource::<QuadPipeline>() - .init_resource::<QuadMeta>() - .add_system_to_stage(RenderStage::Extract, pipeline::extract_quads) - .add_system_to_stage(RenderStage::Prepare, pipeline::prepare_quads) - .add_system_to_stage(RenderStage::Queue, pipeline::queue_quads); - - let draw_quad = DrawQuad::new(&mut render_app.world); - - render_app - .world - .get_resource::<DrawFunctions<TransparentUI>>() - .unwrap() - .write() - .add(draw_quad); - } -} diff --git a/bevy_kayak_ui/src/render/quad/pipeline.rs b/bevy_kayak_ui/src/render/quad/pipeline.rs deleted file mode 100644 index 8c5d857..0000000 --- a/bevy_kayak_ui/src/render/quad/pipeline.rs +++ /dev/null @@ -1,344 +0,0 @@ -use bevy::{ - core::FloatOrd, - ecs::system::{ - lifetimeless::{Read, SQuery, SRes}, - SystemState, - }, - math::{const_vec3, Mat4, Quat, Vec2, Vec3}, - prelude::{Bundle, Color, Commands, Entity, FromWorld, Query, Res, ResMut, World}, - render2::{ - render_phase::{Draw, DrawFunctions, RenderPhase, TrackedRenderPass}, - render_resource::{ - BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, - BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendComponent, - BlendFactor, BlendOperation, BlendState, BufferBindingType, BufferSize, BufferUsages, - BufferVec, CachedPipelineId, ColorTargetState, ColorWrites, CompareFunction, - DepthBiasState, DepthStencilState, FragmentState, FrontFace, MultisampleState, - PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipelineCache, - RenderPipelineDescriptor, Shader, ShaderStages, StencilFaceState, StencilState, - TextureFormat, VertexAttribute, VertexBufferLayout, VertexFormat, VertexState, - VertexStepMode, - }, - renderer::{RenderDevice, RenderQueue}, - texture::BevyDefault, - view::{ViewUniformOffset, ViewUniforms}, - }, - sprite2::Rect, -}; -use bytemuck::{Pod, Zeroable}; -use kayak_core::render_primitive::RenderPrimitive; - -use crate::{ - render::{quad::QUAD_SHADER_HANDLE, ui_pass::TransparentUI}, - to_bevy_color, BevyContext, -}; - -pub struct QuadPipeline { - view_layout: BindGroupLayout, - pipeline: CachedPipelineId, -} - -const QUAD_VERTEX_POSITIONS: &[Vec3] = &[ - const_vec3!([0.0, 0.0, 0.0]), - const_vec3!([1.0, 1.0, 0.0]), - const_vec3!([0.0, 1.0, 0.0]), - const_vec3!([0.0, 0.0, 0.0]), - const_vec3!([1.0, 0.0, 0.0]), - const_vec3!([1.0, 1.0, 0.0]), -]; - -impl FromWorld for QuadPipeline { - fn from_world(world: &mut World) -> Self { - let world = world.cell(); - let render_device = world.get_resource::<RenderDevice>().unwrap(); - let mut pipeline_cache = world.get_resource_mut::<RenderPipelineCache>().unwrap(); - - let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - // TODO: change this to ViewUniform::std140_size_static once crevice fixes this! - // Context: https://github.com/LPGhatguy/crevice/issues/29 - min_binding_size: BufferSize::new(144), - }, - count: None, - }], - label: Some("quad_view_layout"), - }); - - let vertex_buffer_layout = VertexBufferLayout { - array_stride: 28, - step_mode: VertexStepMode::Vertex, - attributes: vec![ - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 0, - }, - VertexAttribute { - format: VertexFormat::Float32x4, - offset: 12, - shader_location: 1, - }, - ], - }; - - let pipeline_desc = RenderPipelineDescriptor { - vertex: VertexState { - shader: QUAD_SHADER_HANDLE.typed::<Shader>(), - entry_point: "vertex".into(), - shader_defs: vec![], - buffers: vec![vertex_buffer_layout], - }, - fragment: Some(FragmentState { - shader: QUAD_SHADER_HANDLE.typed::<Shader>(), - shader_defs: vec![], - entry_point: "fragment".into(), - targets: vec![ColorTargetState { - format: TextureFormat::bevy_default(), - blend: Some(BlendState { - color: BlendComponent { - src_factor: BlendFactor::SrcAlpha, - dst_factor: BlendFactor::OneMinusSrcAlpha, - operation: BlendOperation::Add, - }, - alpha: BlendComponent { - src_factor: BlendFactor::One, - dst_factor: BlendFactor::One, - operation: BlendOperation::Add, - }, - }), - write_mask: ColorWrites::ALL, - }], - }), - layout: Some(vec![view_layout.clone()]), - primitive: PrimitiveState { - front_face: FrontFace::Ccw, - cull_mode: None, - polygon_mode: PolygonMode::Fill, - clamp_depth: false, - conservative: false, - topology: PrimitiveTopology::TriangleList, - strip_index_format: None, - }, - depth_stencil: Some(DepthStencilState { - format: TextureFormat::Depth32Float, - depth_write_enabled: true, - depth_compare: CompareFunction::Greater, - stencil: StencilState { - front: StencilFaceState::IGNORE, - back: StencilFaceState::IGNORE, - read_mask: 0, - write_mask: 0, - }, - bias: DepthBiasState { - constant: 0, - slope_scale: 0.0, - clamp: 0.0, - }, - }), - multisample: MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - label: Some("quad_pipeline".into()), - }; - - QuadPipeline { - pipeline: pipeline_cache.queue(pipeline_desc), - view_layout, - } - } -} - -#[derive(Bundle)] -pub struct ExtractQuadBundle { - extracted_quad: ExtractedQuad, -} - -pub struct ExtractedQuad { - rect: Rect, - background_color: Color, - vertex_index: usize, -} - -pub fn extract_quads(mut commands: Commands, context: Res<BevyContext>) { - let render_commands = if let Ok(context) = context.kayak_context.read() { - context.widget_manager.build_render_primitives() - } else { - vec![] - }; - - let quad_commands: Vec<&RenderPrimitive> = render_commands - .iter() - .filter(|command| matches!(command, RenderPrimitive::Quad { .. })) - .collect::<Vec<_>>(); - - let mut extracted_quads = Vec::new(); - for render_primitive in quad_commands { - let (background_color, layout) = match render_primitive { - RenderPrimitive::Quad { - background_color, - layout, - } => (background_color, layout), - _ => panic!(""), - }; - - extracted_quads.push(ExtractQuadBundle { - extracted_quad: ExtractedQuad { - rect: Rect { - min: Vec2::new(layout.posx, layout.posy), - max: Vec2::new(layout.width, layout.height), - }, - background_color: to_bevy_color(background_color), - vertex_index: 0, - }, - }); - } - commands.spawn_batch(extracted_quads); -} - -#[repr(C)] -#[derive(Copy, Clone, Pod, Zeroable)] -struct QuadVertex { - pub position: [f32; 3], - pub color: [f32; 4], -} - -pub struct QuadMeta { - vertices: BufferVec<QuadVertex>, - view_bind_group: Option<BindGroup>, -} - -impl Default for QuadMeta { - fn default() -> Self { - Self { - vertices: BufferVec::new(BufferUsages::VERTEX), - view_bind_group: None, - } - } -} - -pub fn prepare_quads( - render_device: Res<RenderDevice>, - render_queue: Res<RenderQueue>, - mut sprite_meta: ResMut<QuadMeta>, - mut extracted_sprites: Query<&mut ExtractedQuad>, -) { - let extracted_sprite_len = extracted_sprites.iter_mut().len(); - // dont create buffers when there are no quads - if extracted_sprite_len == 0 { - return; - } - - sprite_meta.vertices.clear(); - sprite_meta.vertices.reserve( - extracted_sprite_len * QUAD_VERTEX_POSITIONS.len(), - &render_device, - ); - - for (i, mut extracted_sprite) in extracted_sprites.iter_mut().enumerate() { - let sprite_rect = extracted_sprite.rect; - let color = extracted_sprite.background_color.as_linear_rgba_f32(); - - extracted_sprite.vertex_index = i; - for vertex_position in QUAD_VERTEX_POSITIONS.iter() { - let world = Mat4::from_scale_rotation_translation( - sprite_rect.size().extend(1.0), - Quat::default(), - sprite_rect.min.extend(0.0), - ); - let final_position = (world * Vec3::from(*vertex_position).extend(1.0)).truncate(); - sprite_meta.vertices.push(QuadVertex { - position: final_position.into(), - color, - }); - } - } - sprite_meta - .vertices - .write_buffer(&render_device, &render_queue); -} - -pub fn queue_quads( - draw_functions: Res<DrawFunctions<TransparentUI>>, - render_device: Res<RenderDevice>, - mut sprite_meta: ResMut<QuadMeta>, - view_uniforms: Res<ViewUniforms>, - quad_pipeline: Res<QuadPipeline>, - mut extracted_sprites: Query<(Entity, &ExtractedQuad)>, - mut views: Query<&mut RenderPhase<TransparentUI>>, -) { - if let Some(view_binding) = view_uniforms.uniforms.binding() { - sprite_meta.view_bind_group = Some(render_device.create_bind_group(&BindGroupDescriptor { - entries: &[BindGroupEntry { - binding: 0, - resource: view_binding, - }], - label: Some("quad_view_bind_group"), - layout: &quad_pipeline.view_layout, - })); - let draw_quad = draw_functions.read().get_id::<DrawQuad>().unwrap(); - for mut transparent_phase in views.iter_mut() { - for (entity, quad) in extracted_sprites.iter_mut() { - transparent_phase.add(TransparentUI { - draw_function: draw_quad, - pipeline: quad_pipeline.pipeline, - entity, - sort_key: FloatOrd(0.0), - }); - } - } - } -} - -pub struct DrawQuad { - params: SystemState<( - SRes<QuadMeta>, - SRes<RenderPipelineCache>, - SQuery<Read<ViewUniformOffset>>, - SQuery<Read<ExtractedQuad>>, - )>, -} - -impl DrawQuad { - pub fn new(world: &mut World) -> Self { - Self { - params: SystemState::new(world), - } - } -} - -impl Draw<TransparentUI> for DrawQuad { - fn draw<'w>( - &mut self, - world: &'w World, - pass: &mut TrackedRenderPass<'w>, - view: Entity, - item: &TransparentUI, - ) { - let (quad_meta, pipelines, views, quads) = self.params.get(world); - let view_uniform = views.get(view).unwrap(); - let quad_meta = quad_meta.into_inner(); - let extracted_quad = quads.get(item.entity).unwrap(); - if let Some(pipeline) = pipelines.into_inner().get(item.pipeline) { - pass.set_render_pipeline(pipeline); - pass.set_vertex_buffer(0, quad_meta.vertices.buffer().unwrap().slice(..)); - pass.set_bind_group( - 0, - quad_meta.view_bind_group.as_ref().unwrap(), - &[view_uniform.offset], - ); - - pass.draw( - (extracted_quad.vertex_index * QUAD_VERTEX_POSITIONS.len()) as u32 - ..((extracted_quad.vertex_index + 1) * QUAD_VERTEX_POSITIONS.len()) as u32, - 0..1, - ); - } - } -} diff --git a/bevy_kayak_ui/src/render/quad/shader.wgsl b/bevy_kayak_ui/src/render/quad/shader.wgsl deleted file mode 100644 index df4e649..0000000 --- a/bevy_kayak_ui/src/render/quad/shader.wgsl +++ /dev/null @@ -1,30 +0,0 @@ -[[block]] -struct View { - view_proj: mat4x4<f32>; - world_position: vec3<f32>; -}; -[[group(0), binding(0)]] -var<uniform> view: View; - -struct VertexOutput { - [[builtin(position)]] position: vec4<f32>; - [[location(0)]] color: vec4<f32>; - [[location(1)]] uv: vec3<f32>; -}; - -[[stage(vertex)]] -fn vertex( - [[location(0)]] vertex_position: vec3<f32>, - [[location(1)]] vertex_color: vec4<f32>, - [[location(2)]] vertex_uv: vec3<f32>; -) -> VertexOutput { - var out: VertexOutput; - out.color = vertex_color; - out.position = view.view_proj * vec4<f32>(vertex_position, 1.0); - return out; -} - -[[stage(fragment)]] -fn fragment(in: VertexOutput) -> [[location(0)]] vec4<f32> { - return in.color; -} \ No newline at end of file diff --git a/bevy_kayak_ui/src/render/text/font.rs b/bevy_kayak_ui/src/render/text/font.rs deleted file mode 100644 index 7a4424c..0000000 --- a/bevy_kayak_ui/src/render/text/font.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bevy::reflect::TypeUuid; -use kayak_font::Font; - -#[derive(Debug, Clone, TypeUuid)] -#[uuid = "4fe4732c-6731-49bb-bafc-4690d636b848"] -pub struct KayakFont { - pub font: Font, -} diff --git a/bevy_kayak_ui/src/render/text/font_mapping.rs b/bevy_kayak_ui/src/render/text/font_mapping.rs deleted file mode 100644 index eeb405a..0000000 --- a/bevy_kayak_ui/src/render/text/font_mapping.rs +++ /dev/null @@ -1,40 +0,0 @@ -use bevy::{prelude::Handle, utils::HashMap}; - -use super::font::KayakFont; - -pub struct FontMapping { - count: u16, - font_ids: HashMap<Handle<KayakFont>, u16>, - font_handles: HashMap<u16, Handle<KayakFont>>, -} - -impl Default for FontMapping { - fn default() -> Self { - Self { - count: 0, - font_ids: HashMap::default(), - font_handles: HashMap::default(), - } - } -} - -impl FontMapping { - pub(crate) fn add(&mut self, handle: Handle<KayakFont>) -> u16 { - if !self.font_ids.contains_key(&handle) { - let id = self.count; - self.font_ids.insert(handle.clone(), id); - self.font_handles.insert(id, handle); - self.count += 1; - - id - } else { - *self.font_ids.get(&handle).unwrap() - } - } - - pub(crate) fn get_handle(&self, id: u16) -> Option<Handle<KayakFont>> { - self.font_handles - .get(&id) - .and_then(|item| Some(item.clone())) - } -} diff --git a/bevy_kayak_ui/src/render/text/font_texture_cache.rs b/bevy_kayak_ui/src/render/text/font_texture_cache.rs deleted file mode 100644 index a15bb07..0000000 --- a/bevy_kayak_ui/src/render/text/font_texture_cache.rs +++ /dev/null @@ -1,201 +0,0 @@ -use bevy::{ - prelude::Handle, - render2::{ - render_resource::{ - AddressMode, BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, Extent3d, - FilterMode, ImageCopyTexture, ImageDataLayout, Origin3d, SamplerDescriptor, - TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, - TextureViewDescriptor, TextureViewDimension, - }, - renderer::{RenderDevice, RenderQueue}, - texture::{GpuImage, TextureFormatPixelInfo}, - }, - utils::HashMap, -}; - -use super::{font::KayakFont, pipeline::TextPipeline}; - -pub const MAX_CHARACTERS: u32 = 100; - -pub struct FontTextureCache { - images: HashMap<Handle<KayakFont>, GpuImage>, - pub(crate) bind_groups: HashMap<Handle<KayakFont>, BindGroup>, - fonts: HashMap<Handle<KayakFont>, KayakFont>, - new_fonts: Vec<Handle<KayakFont>>, - updated_fonts: Vec<Handle<KayakFont>>, -} - -impl Default for FontTextureCache { - fn default() -> Self { - Self::new() - } -} - -impl FontTextureCache { - pub fn new() -> Self { - Self { - images: HashMap::default(), - bind_groups: HashMap::default(), - fonts: HashMap::default(), - new_fonts: Vec::new(), - updated_fonts: Vec::new(), - } - } - - pub fn add(&mut self, kayak_font_handle: Handle<KayakFont>, font: KayakFont) { - if !self.fonts.contains_key(&kayak_font_handle) { - self.fonts.insert(kayak_font_handle.clone(), font); - self.new_fonts.push(kayak_font_handle); - } else { - if let Some(old_font) = self.fonts.get_mut(&kayak_font_handle) { - *old_font = font; - self.updated_fonts.push(kayak_font_handle); - } - } - } - - pub fn process_new(&mut self, device: &RenderDevice, pipeline: &TextPipeline) { - let new_fonts = self.new_fonts.drain(..); - for kayak_font_handle in new_fonts { - if let Some(font) = self.fonts.get(&kayak_font_handle) { - Self::create_texture( - &mut self.images, - kayak_font_handle.clone_weak(), - font, - device, - ); - - let gpu_image = self.images.get(&kayak_font_handle).unwrap(); - - // create bind group - let binding = device.create_bind_group(&BindGroupDescriptor { - label: Some("text_image_bind_group"), - entries: &[ - BindGroupEntry { - binding: 0, - resource: BindingResource::TextureView(&gpu_image.texture_view), - }, - BindGroupEntry { - binding: 1, - resource: BindingResource::Sampler(&gpu_image.sampler), - }, - ], - layout: &pipeline.image_layout, - }); - - self.bind_groups.insert(kayak_font_handle, binding); - } - } - } - - pub fn process_updated(&mut self, queue: &RenderQueue) { - let updated_fonts = self.updated_fonts.drain(..); - for kayak_font_handle in updated_fonts { - if let Some(font) = self.fonts.get_mut(&kayak_font_handle) { - Self::process_new_chars_into_texture( - &mut self.images, - kayak_font_handle, - font, - queue, - ); - } - } - } - - fn create_texture( - images: &mut HashMap<Handle<KayakFont>, GpuImage>, - font_handle: Handle<KayakFont>, - font: &KayakFont, - device: &RenderDevice, - ) { - let texture_descriptor = TextureDescriptor { - label: Some("font_texture_array"), - size: Extent3d { - width: font.font.cache.dimensions, - height: font.font.cache.dimensions, - depth_or_array_layers: MAX_CHARACTERS, - }, - mip_level_count: 1, - sample_count: 1, - dimension: TextureDimension::D2, - format: TextureFormat::Rgba32Float, - usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST, - }; - - let sampler_descriptor = SamplerDescriptor { - label: Some("font_texture_array_sampler"), - address_mode_u: AddressMode::ClampToEdge, - address_mode_v: AddressMode::ClampToEdge, - address_mode_w: AddressMode::ClampToEdge, - mag_filter: FilterMode::Linear, - min_filter: FilterMode::Linear, - mipmap_filter: FilterMode::Nearest, - lod_min_clamp: 0.0, - lod_max_clamp: std::f32::MAX, - compare: None, - anisotropy_clamp: None, - border_color: None, - }; - - let texture = device.create_texture(&texture_descriptor); - let sampler = device.create_sampler(&sampler_descriptor); - - let texture_view = texture.create_view(&TextureViewDescriptor { - label: Some("font_texture_array_view"), - format: None, - dimension: Some(TextureViewDimension::D2Array), - aspect: bevy::render2::render_resource::TextureAspect::All, - base_mip_level: 0, - base_array_layer: 0, - mip_level_count: None, - array_layer_count: std::num::NonZeroU32::new(MAX_CHARACTERS), - }); - - let image = GpuImage { - texture, - sampler, - texture_view, - }; - - images.insert(font_handle, image); - } - - pub fn process_new_chars_into_texture( - images: &mut HashMap<Handle<KayakFont>, GpuImage>, - kayak_font_handle: Handle<KayakFont>, - font: &mut KayakFont, - queue: &RenderQueue, - ) { - let size = font.font.cache.dimensions; - if let Some(gpu_image) = images.get_mut(&kayak_font_handle) { - for (_, id, pixels) in font.font.get_data_to_process() { - let format_size = TextureFormat::Rgba32Float.pixel_size(); - queue.write_texture( - ImageCopyTexture { - texture: &gpu_image.texture, - mip_level: 0, - origin: Origin3d { - x: 0, - y: 0, - z: id as u32, - }, - aspect: TextureAspect::All, - }, - &pixels, - ImageDataLayout { - offset: 0, - bytes_per_row: Some( - std::num::NonZeroU32::new(size * format_size as u32).unwrap(), - ), - rows_per_image: None, - }, - Extent3d { - width: size, - height: size, - depth_or_array_layers: 1, - }, - ); - } - } - } -} diff --git a/bevy_kayak_ui/src/render/text/mod.rs b/bevy_kayak_ui/src/render/text/mod.rs deleted file mode 100644 index bfe4381..0000000 --- a/bevy_kayak_ui/src/render/text/mod.rs +++ /dev/null @@ -1,141 +0,0 @@ -use bevy::{ - prelude::{ - AddAsset, AssetEvent, Assets, Commands, EventReader, Handle, HandleUntyped, Plugin, Res, - ResMut, - }, - reflect::TypeUuid, - render2::{ - render_phase::DrawFunctions, - render_resource::Shader, - renderer::{RenderDevice, RenderQueue}, - RenderApp, RenderStage, - }, - utils::HashSet, -}; - -use crate::render::{ - text::{ - font_mapping::FontMapping, - pipeline::{DrawText, TextMeta, TextPipeline}, - }, - ui_pass::TransparentUI, -}; - -use self::{font::KayakFont, font_texture_cache::FontTextureCache}; - -mod font; -mod font_mapping; -mod font_texture_cache; -mod pipeline; - -pub const TEXT_SHADER_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 1561765330850392701); - -#[derive(Default)] -pub struct TextRendererPlugin; - -impl Plugin for TextRendererPlugin { - fn build(&self, app: &mut bevy::prelude::App) { - let mut shaders = app.world.get_resource_mut::<Assets<Shader>>().unwrap(); - let text_shader = Shader::from_wgsl(include_str!("shader.wgsl")); - shaders.set_untracked(TEXT_SHADER_HANDLE, text_shader); - - let render_app = app.sub_app(RenderApp); - render_app - .init_resource::<TextPipeline>() - .init_resource::<TextMeta>() - .add_system_to_stage(RenderStage::Extract, pipeline::extract_texts) - .add_system_to_stage(RenderStage::Prepare, pipeline::prepare_texts) - .add_system_to_stage(RenderStage::Queue, pipeline::queue_texts); - - let draw_text = DrawText::new(&mut render_app.world); - - render_app - .world - .get_resource::<DrawFunctions<TransparentUI>>() - .unwrap() - .write() - .add(draw_text); - - render_app - .init_resource::<FontTextureCache>() - .init_resource::<ExtractedFonts>() - .add_system_to_stage(RenderStage::Extract, extract_fonts) - .add_system_to_stage(RenderStage::Prepare, prepare_fonts) - .add_system_to_stage(RenderStage::Queue, create_and_update_font_cache_texture); - - app.add_asset::<KayakFont>() - .init_resource::<FontMapping>() - .add_startup_system(load_fonts); - } -} - -#[derive(Default)] -pub struct ExtractedFonts { - pub fonts: Vec<(Handle<KayakFont>, KayakFont)>, -} - -fn load_fonts(mut font_assets: ResMut<Assets<KayakFont>>, mut font_mapping: ResMut<FontMapping>) { - let font_bytes = include_bytes!("../../../../resources/Roboto-Regular.ttf"); - let font = kayak_font::Font::new(font_bytes, 128); - - let handle = font_assets.add(KayakFont { font }); - font_mapping.add(handle); - - dbg!("Loaded base font!"); -} - -fn extract_fonts( - mut commands: Commands, - font_assets: Res<Assets<KayakFont>>, - mut events: EventReader<AssetEvent<KayakFont>>, -) { - let mut extracted_fonts = ExtractedFonts { fonts: Vec::new() }; - let mut changed_assets = HashSet::default(); - let mut removed = Vec::new(); - for event in events.iter() { - match event { - AssetEvent::Created { handle } => { - changed_assets.insert(handle); - dbg!("New font added!"); - } - AssetEvent::Modified { handle } => { - changed_assets.insert(handle); - dbg!("Font changed!"); - } - AssetEvent::Removed { handle } => { - if !changed_assets.remove(handle) { - removed.push(handle.clone_weak()); - } - } - } - } - - for handle in changed_assets { - let font_asset = font_assets.get(handle).unwrap(); - let font = font_asset.clone(); - - extracted_fonts.fonts.push((handle.clone_weak(), font)); - } - - commands.insert_resource(extracted_fonts); -} - -fn prepare_fonts( - mut extracted_fonts: ResMut<ExtractedFonts>, - mut font_texture_cache: ResMut<FontTextureCache>, -) { - for (handle, font) in extracted_fonts.fonts.drain(..) { - font_texture_cache.add(handle, font); - } -} - -fn create_and_update_font_cache_texture( - device: Res<RenderDevice>, - queue: Res<RenderQueue>, - pipeline: Res<TextPipeline>, - mut font_texture_cache: ResMut<FontTextureCache>, -) { - font_texture_cache.process_new(&device, &pipeline); - font_texture_cache.process_updated(&queue); -} diff --git a/bevy_kayak_ui/src/render/text/pipeline.rs b/bevy_kayak_ui/src/render/text/pipeline.rs deleted file mode 100644 index 6b2691e..0000000 --- a/bevy_kayak_ui/src/render/text/pipeline.rs +++ /dev/null @@ -1,360 +0,0 @@ -use bevy::{ - core::FloatOrd, - ecs::system::{ - lifetimeless::{Read, SQuery, SRes}, - SystemState, - }, - math::{const_vec3, Mat4, Quat, Vec2, Vec3}, - prelude::{ - Assets, Bundle, Color, Commands, Entity, FromWorld, Handle, Query, Res, ResMut, World, - }, - render2::{ - render_phase::{Draw, DrawFunctions, RenderPhase, TrackedRenderPass}, - render_resource::{ - BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, - BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendComponent, - BlendFactor, BlendOperation, BlendState, BufferBindingType, BufferSize, BufferUsages, - BufferVec, CachedPipelineId, ColorTargetState, ColorWrites, CompareFunction, - DepthBiasState, DepthStencilState, FragmentState, FrontFace, MultisampleState, - PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipelineCache, - RenderPipelineDescriptor, Shader, ShaderStages, StencilFaceState, StencilState, - TextureFormat, TextureSampleType, TextureViewDimension, VertexAttribute, - VertexBufferLayout, VertexFormat, VertexState, VertexStepMode, - }, - renderer::{RenderDevice, RenderQueue}, - texture::BevyDefault, - view::{ViewUniformOffset, ViewUniforms}, - }, - sprite2::Rect, -}; -use bytemuck::{Pod, Zeroable}; -use kayak_core::render_primitive::RenderPrimitive; - -use crate::{ - render::{text::TEXT_SHADER_HANDLE, ui_pass::TransparentUI}, - to_bevy_color, BevyContext, -}; - -use super::{font::KayakFont, font_mapping::FontMapping, font_texture_cache::FontTextureCache}; - -pub struct TextPipeline { - view_layout: BindGroupLayout, - pub(crate) image_layout: BindGroupLayout, - pipeline: CachedPipelineId, -} - -const QUAD_VERTEX_POSITIONS: &[Vec3] = &[ - const_vec3!([0.0, 0.0, 0.0]), - const_vec3!([1.0, 1.0, 0.0]), - const_vec3!([0.0, 1.0, 0.0]), - const_vec3!([0.0, 0.0, 0.0]), - const_vec3!([1.0, 0.0, 0.0]), - const_vec3!([1.0, 1.0, 0.0]), -]; - -impl FromWorld for TextPipeline { - fn from_world(world: &mut World) -> Self { - let world = world.cell(); - let render_device = world.get_resource::<RenderDevice>().unwrap(); - let mut pipeline_cache = world.get_resource_mut::<RenderPipelineCache>().unwrap(); - - let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - // TODO: change this to ViewUniform::std140_size_static once crevice fixes this! - // Context: https://github.com/LPGhatguy/crevice/issues/29 - min_binding_size: BufferSize::new(144), - }, - count: None, - }], - label: Some("text_view_layout"), - }); - - let image_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - multisampled: false, - sample_type: TextureSampleType::Float { filterable: false }, - view_dimension: TextureViewDimension::D2Array, - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler { - comparison: false, - filtering: true, - }, - count: None, - }, - ], - label: Some("text_image_layout"), - }); - - let vertex_buffer_layout = VertexBufferLayout { - array_stride: 40, - step_mode: VertexStepMode::Vertex, - attributes: vec![ - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 0, - }, - VertexAttribute { - format: VertexFormat::Float32x4, - offset: 12, - shader_location: 1, - }, - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 28, - shader_location: 2, - }, - ], - }; - - let pipeline_desc = RenderPipelineDescriptor { - vertex: VertexState { - shader: TEXT_SHADER_HANDLE.typed::<Shader>(), - entry_point: "vertex".into(), - shader_defs: vec![], - buffers: vec![vertex_buffer_layout], - }, - fragment: Some(FragmentState { - shader: TEXT_SHADER_HANDLE.typed::<Shader>(), - shader_defs: vec![], - entry_point: "fragment".into(), - targets: vec![ColorTargetState { - format: TextureFormat::bevy_default(), - blend: Some(BlendState { - color: BlendComponent { - src_factor: BlendFactor::SrcAlpha, - dst_factor: BlendFactor::OneMinusSrcAlpha, - operation: BlendOperation::Add, - }, - alpha: BlendComponent { - src_factor: BlendFactor::One, - dst_factor: BlendFactor::One, - operation: BlendOperation::Add, - }, - }), - write_mask: ColorWrites::ALL, - }], - }), - layout: Some(vec![view_layout.clone(), image_layout.clone()]), - primitive: PrimitiveState { - front_face: FrontFace::Ccw, - cull_mode: None, - polygon_mode: PolygonMode::Fill, - clamp_depth: false, - conservative: false, - topology: PrimitiveTopology::TriangleList, - strip_index_format: None, - }, - depth_stencil: Some(DepthStencilState { - format: TextureFormat::Depth32Float, - depth_write_enabled: false, - depth_compare: CompareFunction::Greater, - stencil: StencilState { - front: StencilFaceState::IGNORE, - back: StencilFaceState::IGNORE, - read_mask: 0, - write_mask: 0, - }, - bias: DepthBiasState { - constant: 0, - slope_scale: 0.0, - clamp: 0.0, - }, - }), - multisample: MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - label: Some("text_pipeline".into()), - }; - - TextPipeline { - pipeline: pipeline_cache.queue(pipeline_desc), - view_layout, - image_layout, - } - } -} - - - -#[repr(C)] -#[derive(Copy, Clone, Pod, Zeroable)] -struct TextVertex { - pub position: [f32; 3], - pub color: [f32; 4], - pub uv: [f32; 3], -} - -pub struct TextMeta { - vertices: BufferVec<TextVertex>, - view_bind_group: Option<BindGroup>, -} - -impl Default for TextMeta { - fn default() -> Self { - Self { - vertices: BufferVec::new(BufferUsages::VERTEX), - view_bind_group: None, - } - } -} - -pub fn prepare_texts( - render_device: Res<RenderDevice>, - render_queue: Res<RenderQueue>, - mut sprite_meta: ResMut<TextMeta>, - mut extracted_sprites: Query<&mut ExtractedText>, -) { - let extracted_sprite_len = extracted_sprites.iter_mut().len(); - // dont create buffers when there are no texts - if extracted_sprite_len == 0 { - return; - } - - sprite_meta.vertices.clear(); - sprite_meta.vertices.reserve( - extracted_sprite_len * QUAD_VERTEX_POSITIONS.len(), - &render_device, - ); - - for (i, mut extracted_sprite) in extracted_sprites.iter_mut().enumerate() { - let sprite_rect = extracted_sprite.rect; - let color = extracted_sprite.background_color.as_linear_rgba_f32(); - - let bottom_left = Vec3::new(0.0, 1.0, extracted_sprite.char_id as f32); - let top_left = Vec3::new(0.0, 0.0, extracted_sprite.char_id as f32); - let top_right = Vec3::new(1.0, 0.0, extracted_sprite.char_id as f32); - let bottom_right = Vec3::new(1.0, 1.0, extracted_sprite.char_id as f32); - - let uvs: [[f32; 3]; 6] = [ - bottom_left.into(), - top_right.into(), - top_left.into(), - bottom_left.into(), - bottom_right.into(), - top_right.into(), - ]; - - extracted_sprite.vertex_index = i; - for (index, vertex_position) in QUAD_VERTEX_POSITIONS.iter().enumerate() { - let world = Mat4::from_scale_rotation_translation( - sprite_rect.size().extend(1.0), - Quat::default(), - sprite_rect.min.extend(extracted_sprite.z_index), - ); - let final_position = (world * Vec3::from(*vertex_position).extend(1.0)).truncate(); - sprite_meta.vertices.push(TextVertex { - position: final_position.into(), - color, - uv: uvs[index], - }); - } - } - sprite_meta - .vertices - .write_buffer(&render_device, &render_queue); -} - -pub fn queue_texts( - draw_functions: Res<DrawFunctions<TransparentUI>>, - render_device: Res<RenderDevice>, - mut sprite_meta: ResMut<TextMeta>, - view_uniforms: Res<ViewUniforms>, - text_pipeline: Res<TextPipeline>, - mut extracted_sprites: Query<(Entity, &ExtractedText)>, - mut views: Query<&mut RenderPhase<TransparentUI>>, -) { - if let Some(view_binding) = view_uniforms.uniforms.binding() { - sprite_meta.view_bind_group = Some(render_device.create_bind_group(&BindGroupDescriptor { - entries: &[BindGroupEntry { - binding: 0, - resource: view_binding, - }], - label: Some("text_view_bind_group"), - layout: &text_pipeline.view_layout, - })); - let draw_text = draw_functions.read().get_id::<DrawText>().unwrap(); - for mut transparent_phase in views.iter_mut() { - for (entity, _) in extracted_sprites.iter_mut() { - transparent_phase.add(TransparentUI { - draw_function: draw_text, - pipeline: text_pipeline.pipeline, - entity, - sort_key: FloatOrd(0.0), - }); - } - } - } -} - -pub struct DrawText { - params: SystemState<( - SRes<TextMeta>, - SRes<RenderPipelineCache>, - SRes<FontTextureCache>, - SQuery<Read<ViewUniformOffset>>, - SQuery<Read<ExtractedText>>, - )>, -} - -impl DrawText { - pub fn new(world: &mut World) -> Self { - Self { - params: SystemState::new(world), - } - } -} - -impl Draw<TransparentUI> for DrawText { - fn draw<'w>( - &mut self, - world: &'w World, - pass: &mut TrackedRenderPass<'w>, - view: Entity, - item: &TransparentUI, - ) { - let (text_meta, pipelines, font_texture_cache, views, texts) = self.params.get(world); - let view_uniform = views.get(view).unwrap(); - let text_meta = text_meta.into_inner(); - let extracted_text = texts.get(item.entity).unwrap(); - if let Some(pipeline) = pipelines.into_inner().get(item.pipeline) { - pass.set_render_pipeline(pipeline); - pass.set_vertex_buffer(0, text_meta.vertices.buffer().unwrap().slice(..)); - pass.set_bind_group( - 0, - text_meta.view_bind_group.as_ref().unwrap(), - &[view_uniform.offset], - ); - - if let Some(image_bindings) = font_texture_cache - .into_inner() - .bind_groups - .get(&extracted_text.font_handle) - { - pass.set_bind_group(1, image_bindings, &[]); - - pass.draw( - (extracted_text.vertex_index * QUAD_VERTEX_POSITIONS.len()) as u32 - ..((extracted_text.vertex_index + 1) * QUAD_VERTEX_POSITIONS.len()) as u32, - 0..1, - ); - } - } - } -} diff --git a/bevy_kayak_ui/src/render/text/shader.wgsl b/bevy_kayak_ui/src/render/text/shader.wgsl deleted file mode 100644 index 5a2b1ec..0000000 --- a/bevy_kayak_ui/src/render/text/shader.wgsl +++ /dev/null @@ -1,45 +0,0 @@ -[[block]] -struct View { - view_proj: mat4x4<f32>; - world_position: vec3<f32>; -}; -[[group(0), binding(0)]] -var<uniform> view: View; - -struct VertexOutput { - [[builtin(position)]] position: vec4<f32>; - [[location(0)]] color: vec4<f32>; - [[location(1)]] uv: vec3<f32>; -}; - -[[stage(vertex)]] -fn vertex( - [[location(0)]] vertex_position: vec3<f32>, - [[location(1)]] vertex_color: vec4<f32>, - [[location(2)]] vertex_uv: vec3<f32>, -) -> VertexOutput { - var out: VertexOutput; - out.color = vertex_color; - out.uv = vertex_uv; - out.position = view.view_proj * vec4<f32>(vertex_position, 1.0); - return out; -} - -[[group(1), binding(0)]] -var sprite_texture: texture_2d_array<f32>; -[[group(1), binding(1)]] -var sprite_sampler: sampler; - -let RADIUS: f32 = 0.5; - -[[stage(fragment)]] -fn fragment(in: VertexOutput) -> [[location(0)]] vec4<f32> { - var x = textureSample(sprite_texture, sprite_sampler, in.uv.xy, i32(in.uv.z)); - var v = max(min(x.r, x.g), min(max(x.r, x.g), x.b)); - var c = v; //remap(v); - - var v2 = c / fwidth( c ); - var a = v2 + RADIUS; //clamp( v2 + RADIUS, 0.0, 1.0 ); - - return vec4<f32>(in.color.rgb, a); -} \ No newline at end of file -- GitLab