diff --git a/Cargo.lock b/Cargo.lock index 05a6c75dc9e17f235556d677340fbfa4e7f6b415..f042d6ecd92276a5e56632d11a19afef21563cdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -442,11 +442,24 @@ dependencies = [ "ndk-glue 0.5.0", ] +[[package]] +name = "bevy_kayak_renderer" +version = "0.0.1" +dependencies = [ + "bevy", + "bytemuck", + "kayak_font", + "serde", + "serde_json", + "serde_path_to_error", +] + [[package]] name = "bevy_kayak_ui" version = "0.0.1" dependencies = [ "bevy", + "bevy_kayak_renderer", "bytemuck", "kayak_core", "kayak_font", diff --git a/bevy_kayak_renderer/Cargo.toml b/bevy_kayak_renderer/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..2b3c2215f951f94bf81583a50edfc3cfd35b96e6 --- /dev/null +++ b/bevy_kayak_renderer/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "bevy_kayak_renderer" +version = "0.0.1" +edition = "2021" + +[dependencies] +bytemuck = "1.7.2" +bevy = { version = "0.6.0" } +kayak_font = { path = "../kayak_font" } +serde = "1.0" +serde_json = "1.0" +serde_path_to_error = "0.1" diff --git a/bevy_kayak_ui/src/camera/camera.rs b/bevy_kayak_renderer/src/camera/camera.rs similarity index 100% rename from bevy_kayak_ui/src/camera/camera.rs rename to bevy_kayak_renderer/src/camera/camera.rs diff --git a/bevy_kayak_ui/src/camera/mod.rs b/bevy_kayak_renderer/src/camera/mod.rs similarity index 100% rename from bevy_kayak_ui/src/camera/mod.rs rename to bevy_kayak_renderer/src/camera/mod.rs diff --git a/bevy_kayak_ui/src/camera/ortho.rs b/bevy_kayak_renderer/src/camera/ortho.rs similarity index 100% rename from bevy_kayak_ui/src/camera/ortho.rs rename to bevy_kayak_renderer/src/camera/ortho.rs diff --git a/bevy_kayak_renderer/src/lib.rs b/bevy_kayak_renderer/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..7ce038a702fa719c3518a53dd717e90f8bb8cbd8 --- /dev/null +++ b/bevy_kayak_renderer/src/lib.rs @@ -0,0 +1,59 @@ +use bevy::{ + prelude::*, + window::{WindowCreated, WindowResized}, +}; + +pub mod camera; +pub mod render; + +pub use camera::*; + +#[derive(Default)] +pub struct BevyKayakRendererPlugin; + +impl Plugin for BevyKayakRendererPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + app.add_system(update_window_size) + .init_resource::<WindowSize>() + .add_plugin(render::BevyKayakUIRenderPlugin) + .add_plugin(camera::KayakUICameraPlugin); + } +} + +/// Tracks the bevy window size. +#[derive(Default, Debug, Clone, Copy, PartialEq)] +pub struct WindowSize(pub f32, pub f32); + +fn update_window_size( + mut window_resized_events: EventReader<WindowResized>, + mut window_created_events: EventReader<WindowCreated>, +) { + let mut changed_window_ids = Vec::new(); + // handle resize events. latest events are handled first because we only want to resize each + // window once + for event in window_resized_events.iter().rev() { + if changed_window_ids.contains(&event.id) { + continue; + } + + changed_window_ids.push(event.id); + } + + // handle resize events. latest events are handled first because we only want to resize each + // window once + for event in window_created_events.iter().rev() { + if changed_window_ids.contains(&event.id) { + continue; + } + + changed_window_ids.push(event.id); + } +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct Corner<T> { + pub top_left: T, + pub top_right: T, + pub bottom_left: T, + pub bottom_right: T, +} diff --git a/bevy_kayak_renderer/src/render/mod.rs b/bevy_kayak_renderer/src/render/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..0a3babef1e0b257b28274aed1c8ca039584d9397 --- /dev/null +++ b/bevy_kayak_renderer/src/render/mod.rs @@ -0,0 +1,93 @@ +use bevy::{ + core_pipeline::node::MAIN_PASS_DRIVER, + prelude::{Commands, Plugin, Res}, + render::{ + camera::ActiveCameras, + render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType}, + render_phase::{DrawFunctions, RenderPhase}, + RenderApp, RenderStage, + }, +}; + +use crate::{ + render::{ + ui_pass::MainPassUINode, ui_pass_driver::UIPassDriverNode, unified::UnifiedRenderPlugin, + }, + UICameraBundle, +}; + +use self::ui_pass::TransparentUI; + +mod ui_pass; +mod ui_pass_driver; +pub mod unified; + +pub mod node { + pub const UI_PASS_DEPENDENCIES: &str = "kayak_ui_pass_dependencies"; + pub const UI_PASS_DRIVER: &str = "kayak_ui_pass_driver"; +} + +pub mod draw_ui_graph { + pub const NAME: &str = "kayak_draw_ui"; + pub mod input { + pub const VIEW_ENTITY: &str = "kayak_view_entity"; + } + pub mod node { + pub const MAIN_PASS: &str = "kayak_ui_pass"; + } +} + +pub struct BevyKayakUIRenderPlugin; + +impl Plugin for BevyKayakUIRenderPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + let render_app = app.sub_app_mut(RenderApp); + render_app + .init_resource::<DrawFunctions<TransparentUI>>() + .add_system_to_stage(RenderStage::Extract, extract_core_pipeline_camera_phases); + // .add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<TransparentUI>); + + let pass_node_ui = MainPassUINode::new(&mut render_app.world); + let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap(); + + let mut draw_ui_graph = RenderGraph::default(); + draw_ui_graph.add_node(draw_ui_graph::node::MAIN_PASS, pass_node_ui); + let input_node_id = draw_ui_graph.set_input(vec![SlotInfo::new( + draw_ui_graph::input::VIEW_ENTITY, + SlotType::Entity, + )]); + draw_ui_graph + .add_slot_edge( + input_node_id, + draw_ui_graph::input::VIEW_ENTITY, + draw_ui_graph::node::MAIN_PASS, + MainPassUINode::IN_VIEW, + ) + .unwrap(); + graph.add_sub_graph(draw_ui_graph::NAME, draw_ui_graph); + + graph.add_node(node::UI_PASS_DEPENDENCIES, EmptyNode); + graph.add_node(node::UI_PASS_DRIVER, UIPassDriverNode); + graph + .add_node_edge(node::UI_PASS_DEPENDENCIES, node::UI_PASS_DRIVER) + .unwrap(); + graph + .add_node_edge(MAIN_PASS_DRIVER, node::UI_PASS_DRIVER) + .unwrap(); + + app.add_plugin(UnifiedRenderPlugin); + } +} + +pub fn extract_core_pipeline_camera_phases( + mut commands: Commands, + active_cameras: Res<ActiveCameras>, +) { + if let Some(camera_2d) = active_cameras.get(UICameraBundle::UI_CAMERA) { + if let Some(entity) = camera_2d.entity { + commands + .get_or_spawn(entity) + .insert(RenderPhase::<TransparentUI>::default()); + } + } +} diff --git a/bevy_kayak_ui/src/render/ui_pass.rs b/bevy_kayak_renderer/src/render/ui_pass.rs similarity index 100% rename from bevy_kayak_ui/src/render/ui_pass.rs rename to bevy_kayak_renderer/src/render/ui_pass.rs diff --git a/bevy_kayak_ui/src/render/ui_pass_driver.rs b/bevy_kayak_renderer/src/render/ui_pass_driver.rs similarity index 100% rename from bevy_kayak_ui/src/render/ui_pass_driver.rs rename to bevy_kayak_renderer/src/render/ui_pass_driver.rs diff --git a/bevy_kayak_renderer/src/render/unified/mod.rs b/bevy_kayak_renderer/src/render/unified/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c0333d569dd210db7981b8c93bf74424be37432e --- /dev/null +++ b/bevy_kayak_renderer/src/render/unified/mod.rs @@ -0,0 +1,66 @@ +use bevy::{ + prelude::{Assets, Commands, HandleUntyped, Plugin, Res}, + reflect::TypeUuid, + render::{render_phase::DrawFunctions, render_resource::Shader, RenderApp, RenderStage}, + window::Windows, +}; + +use crate::{ + render::{ + ui_pass::TransparentUI, + unified::pipeline::{DrawUI, QuadMeta, UnifiedPipeline}, + }, + WindowSize, +}; + +use self::pipeline::ImageBindGroups; + +pub mod pipeline; + +pub const UNIFIED_SHADER_HANDLE: HandleUntyped = + HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 7604018236855288450); + +pub struct UnifiedRenderPlugin; + +impl Plugin for UnifiedRenderPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + let mut shaders = app.world.get_resource_mut::<Assets<Shader>>().unwrap(); + let unified_shader = Shader::from_wgsl(include_str!("shader.wgsl")); + shaders.set_untracked(UNIFIED_SHADER_HANDLE, unified_shader); + + let render_app = app.sub_app_mut(RenderApp); + render_app + .init_resource::<ImageBindGroups>() + .init_resource::<UnifiedPipeline>() + .init_resource::<QuadMeta>() + .add_system_to_stage(RenderStage::Extract, extract_baseline) + .add_system_to_stage(RenderStage::Prepare, pipeline::prepare_quads) + .add_system_to_stage(RenderStage::Queue, pipeline::queue_quads); + + let draw_quad = DrawUI::new(&mut render_app.world); + + render_app + .world + .get_resource::<DrawFunctions<TransparentUI>>() + .unwrap() + .write() + .add(draw_quad); + } +} + +pub struct Dpi(f32); + +pub fn extract_baseline( + mut commands: Commands, + windows: Res<Windows>, + window_size: Res<WindowSize>, +) { + let dpi = if let Some(window) = windows.get_primary() { + window.scale_factor() as f32 + } else { + 1.0 + }; + + commands.insert_resource(*window_size); + commands.insert_resource(Dpi(dpi)); +} diff --git a/bevy_kayak_ui/src/render/unified/pipeline.rs b/bevy_kayak_renderer/src/render/unified/pipeline.rs similarity index 99% rename from bevy_kayak_ui/src/render/unified/pipeline.rs rename to bevy_kayak_renderer/src/render/unified/pipeline.rs index fafd3f37e9610ffa2dd04dbc8c3f66512c5a01a8..0706692cc8221596c1d61607cac352bcc35ddda3 100644 --- a/bevy_kayak_ui/src/render/unified/pipeline.rs +++ b/bevy_kayak_renderer/src/render/unified/pipeline.rs @@ -38,8 +38,8 @@ use kayak_font::{ }; use super::{Dpi, UNIFIED_SHADER_HANDLE}; -use crate::{render::ui_pass::TransparentUI, WindowSize}; -use kayak_core::styles::Corner; +use crate::render::ui_pass::TransparentUI; +use crate::{Corner, WindowSize}; pub struct UnifiedPipeline { view_layout: BindGroupLayout, @@ -300,7 +300,7 @@ impl FromWorld for UnifiedPipeline { #[derive(Debug, Bundle)] pub struct ExtractQuadBundle { - pub(crate) extracted_quad: ExtractedQuad, + pub extracted_quad: ExtractedQuad, } #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/bevy_kayak_ui/src/render/unified/shader.wgsl b/bevy_kayak_renderer/src/render/unified/shader.wgsl similarity index 100% rename from bevy_kayak_ui/src/render/unified/shader.wgsl rename to bevy_kayak_renderer/src/render/unified/shader.wgsl diff --git a/bevy_kayak_ui/Cargo.toml b/bevy_kayak_ui/Cargo.toml index b2244c7cfb0f7e4e4a463e55aeceb910f1140838..1ad00aa1c68f4d7b7e3f0451240991652f9fc97a 100644 --- a/bevy_kayak_ui/Cargo.toml +++ b/bevy_kayak_ui/Cargo.toml @@ -8,6 +8,7 @@ bytemuck = "1.7.2" bevy = { version = "0.6.0" } kayak_core = { path = "../kayak_core" } kayak_font = { path = "../kayak_font" } +bevy_kayak_renderer = { path = "../bevy_kayak_renderer" } serde = "1.0" serde_json = "1.0" serde_path_to_error = "0.1" diff --git a/bevy_kayak_ui/src/lib.rs b/bevy_kayak_ui/src/lib.rs index 6d60521206cb8ff559dd743187719b44bc8f5842..9e8852e2126eef7f3970408d4db7c0372e1b9edf 100644 --- a/bevy_kayak_ui/src/lib.rs +++ b/bevy_kayak_ui/src/lib.rs @@ -7,17 +7,16 @@ use bevy::{ }; mod bevy_context; -mod camera; mod cursor; mod key; mod render; use crate::cursor::convert_cursor_icon; pub use bevy_context::BevyContext; -pub use camera::*; +pub use bevy_kayak_renderer::camera::*; use kayak_core::{bind, Binding, InputEvent, MutableBound}; -pub use render::unified::font::FontMapping; -pub use render::unified::image::ImageManager; +pub use render::font::FontMapping; +pub use render::image::ImageManager; #[derive(Default)] pub struct BevyKayakUIPlugin; @@ -25,8 +24,8 @@ pub struct BevyKayakUIPlugin; impl Plugin for BevyKayakUIPlugin { fn build(&self, app: &mut bevy::prelude::App) { app.insert_resource(bind(WindowSize::default())) - .add_plugin(render::BevyKayakUIRenderPlugin) - .add_plugin(camera::KayakUICameraPlugin) + .add_plugin(bevy_kayak_renderer::BevyKayakRendererPlugin) + .add_plugin(render::BevyKayakUIExtractPlugin) .add_system(update_window_size) .add_system(process_events.exclusive_system()) .add_system(update.exclusive_system()); diff --git a/bevy_kayak_ui/src/render/unified/font/extract.rs b/bevy_kayak_ui/src/render/font/extract.rs similarity index 97% rename from bevy_kayak_ui/src/render/unified/font/extract.rs rename to bevy_kayak_ui/src/render/font/extract.rs index 8f0fa133000297bbd3bc9e70ecf21d3ed3336063..23d37fac30c190edc20b912435f91de4f419ffb4 100644 --- a/bevy_kayak_ui/src/render/unified/font/extract.rs +++ b/bevy_kayak_ui/src/render/font/extract.rs @@ -4,12 +4,12 @@ use bevy::{ sprite::Rect, }; use kayak_core::render_primitive::RenderPrimitive; -use kayak_core::styles::Corner; use kayak_font::{Alignment, CoordinateSystem, KayakFont}; -use crate::{ +use crate::to_bevy_color; +use bevy_kayak_renderer::{ render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType}, - to_bevy_color, + Corner, }; use super::font_mapping::FontMapping; diff --git a/bevy_kayak_ui/src/render/unified/font/font_mapping.rs b/bevy_kayak_ui/src/render/font/font_mapping.rs similarity index 100% rename from bevy_kayak_ui/src/render/unified/font/font_mapping.rs rename to bevy_kayak_ui/src/render/font/font_mapping.rs diff --git a/bevy_kayak_ui/src/render/unified/font/mod.rs b/bevy_kayak_ui/src/render/font/mod.rs similarity index 95% rename from bevy_kayak_ui/src/render/unified/font/mod.rs rename to bevy_kayak_ui/src/render/font/mod.rs index 5bbe8e6747d20c9cb02c9fe56a222a6e701d6882..f04a26d7d56ad1db9a9e53731d53f3638a3a1e4c 100644 --- a/bevy_kayak_ui/src/render/unified/font/mod.rs +++ b/bevy_kayak_ui/src/render/font/mod.rs @@ -17,7 +17,7 @@ mod font_mapping; use crate::BevyContext; -use super::pipeline::UnifiedPipeline; +use bevy_kayak_renderer::render::unified::pipeline::UnifiedPipeline; pub use extract::extract_texts; pub use font_mapping::*; diff --git a/bevy_kayak_ui/src/render/unified/image/extract.rs b/bevy_kayak_ui/src/render/image/extract.rs similarity index 79% rename from bevy_kayak_ui/src/render/unified/image/extract.rs rename to bevy_kayak_ui/src/render/image/extract.rs index c6b6e2155581aa07edb8cb0ab792d019d4678ebf..c50af05666affe552b101220e6678e17c1ede0ed 100644 --- a/bevy_kayak_ui/src/render/unified/image/extract.rs +++ b/bevy_kayak_ui/src/render/image/extract.rs @@ -1,9 +1,10 @@ use bevy::{math::Vec2, prelude::Res, render::color::Color, sprite::Rect}; use kayak_core::render_primitive::RenderPrimitive; -use crate::{ +use crate::ImageManager; +use bevy_kayak_renderer::{ render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType}, - ImageManager, + Corner, }; pub fn extract_images( @@ -33,7 +34,12 @@ pub fn extract_images( font_handle: None, quad_type: UIQuadType::Image, type_index: 0, - border_radius, + border_radius: Corner { + top_left: border_radius.top_left, + top_right: border_radius.top_right, + bottom_left: border_radius.bottom_left, + bottom_right: border_radius.bottom_right, + }, image: image_manager .get_handle(handle) .and_then(|a| Some(a.clone_weak())), diff --git a/bevy_kayak_ui/src/render/unified/image/image_manager.rs b/bevy_kayak_ui/src/render/image/image_manager.rs similarity index 100% rename from bevy_kayak_ui/src/render/unified/image/image_manager.rs rename to bevy_kayak_ui/src/render/image/image_manager.rs diff --git a/bevy_kayak_ui/src/render/unified/image/mod.rs b/bevy_kayak_ui/src/render/image/mod.rs similarity index 100% rename from bevy_kayak_ui/src/render/unified/image/mod.rs rename to bevy_kayak_ui/src/render/image/mod.rs diff --git a/bevy_kayak_ui/src/render/mod.rs b/bevy_kayak_ui/src/render/mod.rs index 0a3babef1e0b257b28274aed1c8ca039584d9397..4a60b6e0d9b9f97f4294a511c9f5c3f69c6b82e1 100644 --- a/bevy_kayak_ui/src/render/mod.rs +++ b/bevy_kayak_ui/src/render/mod.rs @@ -1,93 +1,109 @@ +use crate::{BevyContext, FontMapping, ImageManager}; use bevy::{ - core_pipeline::node::MAIN_PASS_DRIVER, - prelude::{Commands, Plugin, Res}, - render::{ - camera::ActiveCameras, - render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType}, - render_phase::{DrawFunctions, RenderPhase}, - RenderApp, RenderStage, - }, + math::Vec2, + prelude::{Assets, Commands, Plugin, Res}, + render::{color::Color, texture::Image, RenderApp, RenderStage}, + sprite::Rect, + window::Windows, }; - -use crate::{ - render::{ - ui_pass::MainPassUINode, ui_pass_driver::UIPassDriverNode, unified::UnifiedRenderPlugin, - }, - UICameraBundle, +use bevy_kayak_renderer::{ + render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType}, + Corner, }; +use kayak_core::render_primitive::RenderPrimitive; +use kayak_font::KayakFont; -use self::ui_pass::TransparentUI; +pub mod font; +pub mod image; +mod nine_patch; +mod quad; -mod ui_pass; -mod ui_pass_driver; -pub mod unified; +pub struct BevyKayakUIExtractPlugin; -pub mod node { - pub const UI_PASS_DEPENDENCIES: &str = "kayak_ui_pass_dependencies"; - pub const UI_PASS_DRIVER: &str = "kayak_ui_pass_driver"; -} +impl Plugin for BevyKayakUIExtractPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + app.add_plugin(font::TextRendererPlugin) + .add_plugin(image::ImageRendererPlugin); -pub mod draw_ui_graph { - pub const NAME: &str = "kayak_draw_ui"; - pub mod input { - pub const VIEW_ENTITY: &str = "kayak_view_entity"; - } - pub mod node { - pub const MAIN_PASS: &str = "kayak_ui_pass"; + let render_app = app.sub_app_mut(RenderApp); + render_app.add_system_to_stage(RenderStage::Extract, extract); } } -pub struct BevyKayakUIRenderPlugin; - -impl Plugin for BevyKayakUIRenderPlugin { - fn build(&self, app: &mut bevy::prelude::App) { - let render_app = app.sub_app_mut(RenderApp); - render_app - .init_resource::<DrawFunctions<TransparentUI>>() - .add_system_to_stage(RenderStage::Extract, extract_core_pipeline_camera_phases); - // .add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<TransparentUI>); +pub fn extract( + mut commands: Commands, + context: Option<Res<BevyContext>>, + fonts: Res<Assets<KayakFont>>, + font_mapping: Res<FontMapping>, + image_manager: Res<ImageManager>, + images: Res<Assets<Image>>, + windows: Res<Windows>, +) { + if context.is_none() { + return; + } - let pass_node_ui = MainPassUINode::new(&mut render_app.world); - let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap(); + let context = context.unwrap(); - let mut draw_ui_graph = RenderGraph::default(); - draw_ui_graph.add_node(draw_ui_graph::node::MAIN_PASS, pass_node_ui); - let input_node_id = draw_ui_graph.set_input(vec![SlotInfo::new( - draw_ui_graph::input::VIEW_ENTITY, - SlotType::Entity, - )]); - draw_ui_graph - .add_slot_edge( - input_node_id, - draw_ui_graph::input::VIEW_ENTITY, - draw_ui_graph::node::MAIN_PASS, - MainPassUINode::IN_VIEW, - ) - .unwrap(); - graph.add_sub_graph(draw_ui_graph::NAME, draw_ui_graph); + let render_primitives = if let Ok(context) = context.kayak_context.read() { + context.widget_manager.build_render_primitives() + } else { + vec![] + }; - graph.add_node(node::UI_PASS_DEPENDENCIES, EmptyNode); - graph.add_node(node::UI_PASS_DRIVER, UIPassDriverNode); - graph - .add_node_edge(node::UI_PASS_DEPENDENCIES, node::UI_PASS_DRIVER) - .unwrap(); - graph - .add_node_edge(MAIN_PASS_DRIVER, node::UI_PASS_DRIVER) - .unwrap(); + // dbg!(&render_primitives); - app.add_plugin(UnifiedRenderPlugin); - } -} + let dpi = if let Some(window) = windows.get_primary() { + window.scale_factor() as f32 + } else { + 1.0 + }; -pub fn extract_core_pipeline_camera_phases( - mut commands: Commands, - active_cameras: Res<ActiveCameras>, -) { - if let Some(camera_2d) = active_cameras.get(UICameraBundle::UI_CAMERA) { - if let Some(entity) = camera_2d.entity { - commands - .get_or_spawn(entity) - .insert(RenderPhase::<TransparentUI>::default()); + let mut extracted_quads = Vec::new(); + for render_primitive in render_primitives { + match render_primitive { + RenderPrimitive::Text { .. } => { + let text_quads = font::extract_texts(&render_primitive, &fonts, &font_mapping, dpi); + extracted_quads.extend(text_quads); + } + RenderPrimitive::Image { .. } => { + let image_quads = image::extract_images(&render_primitive, &image_manager, dpi); + extracted_quads.extend(image_quads); + } + RenderPrimitive::Quad { .. } => { + let quad_quads = quad::extract_quads(&render_primitive, 1.0); + extracted_quads.extend(quad_quads); + } + RenderPrimitive::NinePatch { .. } => { + let nine_patch_quads = + nine_patch::extract_nine_patch(&render_primitive, &image_manager, &images, dpi); + extracted_quads.extend(nine_patch_quads); + } + RenderPrimitive::Clip { layout } => { + extracted_quads.push(ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(layout.posx, layout.posy) * dpi, + max: Vec2::new(layout.posx + layout.width, layout.posy + layout.height) + * dpi, + }, + color: Color::default(), + vertex_index: 0, + char_id: 0, + z_index: layout.z_index, + font_handle: None, + quad_type: UIQuadType::Clip, + type_index: 0, + border_radius: Corner::default(), + image: None, + uv_min: None, + uv_max: None, + }, + }); + } + _ => {} } } + + commands.spawn_batch(extracted_quads); } diff --git a/bevy_kayak_ui/src/render/unified/nine_patch/extract.rs b/bevy_kayak_ui/src/render/nine_patch/extract.rs similarity index 99% rename from bevy_kayak_ui/src/render/unified/nine_patch/extract.rs rename to bevy_kayak_ui/src/render/nine_patch/extract.rs index 239a20d33ccbd326c7899302ba6c8a058dcd39fb..1ed37824c97474f858776d569c0b4b12872af9a6 100644 --- a/bevy_kayak_ui/src/render/unified/nine_patch/extract.rs +++ b/bevy_kayak_ui/src/render/nine_patch/extract.rs @@ -1,16 +1,15 @@ +use crate::ImageManager; use bevy::{ math::Vec2, prelude::{Assets, Res}, render::{color::Color, texture::Image}, sprite::Rect, }; -use kayak_core::render_primitive::RenderPrimitive; -use kayak_core::styles::Corner; - -use crate::{ +use bevy_kayak_renderer::{ render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType}, - ImageManager, + Corner, }; +use kayak_core::render_primitive::RenderPrimitive; pub fn extract_nine_patch( render_primitive: &RenderPrimitive, diff --git a/bevy_kayak_ui/src/render/unified/nine_patch/mod.rs b/bevy_kayak_ui/src/render/nine_patch/mod.rs similarity index 100% rename from bevy_kayak_ui/src/render/unified/nine_patch/mod.rs rename to bevy_kayak_ui/src/render/nine_patch/mod.rs diff --git a/bevy_kayak_ui/src/render/unified/quad/extract.rs b/bevy_kayak_ui/src/render/quad/extract.rs similarity index 78% rename from bevy_kayak_ui/src/render/unified/quad/extract.rs rename to bevy_kayak_ui/src/render/quad/extract.rs index b98c8e90377263e769813eb01256f0077833f7d8..52b2e8a8e34a7983f83eaf527d3ad97db2f486b6 100644 --- a/bevy_kayak_ui/src/render/unified/quad/extract.rs +++ b/bevy_kayak_ui/src/render/quad/extract.rs @@ -1,10 +1,10 @@ +use crate::to_bevy_color; use bevy::{math::Vec2, sprite::Rect}; -use kayak_core::render_primitive::RenderPrimitive; - -use crate::{ +use bevy_kayak_renderer::{ render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType}, - to_bevy_color, + Corner, }; +use kayak_core::render_primitive::RenderPrimitive; pub fn extract_quads(render_primitive: &RenderPrimitive, dpi: f32) -> Vec<ExtractQuadBundle> { let (background_color, border_color, layout, border_radius, mut border) = match render_primitive @@ -45,7 +45,12 @@ pub fn extract_quads(render_primitive: &RenderPrimitive, dpi: f32) -> Vec<Extrac font_handle: None, quad_type: UIQuadType::Quad, type_index: 0, - border_radius, + border_radius: Corner { + top_left: border_radius.top_left, + top_right: border_radius.top_right, + bottom_left: border_radius.bottom_left, + bottom_right: border_radius.bottom_right, + }, image: None, uv_max: None, uv_min: None, @@ -67,7 +72,12 @@ pub fn extract_quads(render_primitive: &RenderPrimitive, dpi: f32) -> Vec<Extrac font_handle: None, quad_type: UIQuadType::Quad, type_index: 0, - border_radius, + border_radius: Corner { + top_left: border_radius.top_left, + top_right: border_radius.top_right, + bottom_left: border_radius.bottom_left, + bottom_right: border_radius.bottom_right, + }, image: None, uv_max: None, uv_min: None, diff --git a/bevy_kayak_ui/src/render/unified/quad/mod.rs b/bevy_kayak_ui/src/render/quad/mod.rs similarity index 100% rename from bevy_kayak_ui/src/render/unified/quad/mod.rs rename to bevy_kayak_ui/src/render/quad/mod.rs diff --git a/bevy_kayak_ui/src/render/unified/mod.rs b/bevy_kayak_ui/src/render/unified/mod.rs deleted file mode 100644 index 1616285e20a918d0e706fdd3f590a51da4c25854..0000000000000000000000000000000000000000 --- a/bevy_kayak_ui/src/render/unified/mod.rs +++ /dev/null @@ -1,146 +0,0 @@ -use bevy::{ - math::Vec2, - prelude::{Assets, Commands, HandleUntyped, Plugin, Res}, - reflect::TypeUuid, - render::{ - color::Color, render_phase::DrawFunctions, render_resource::Shader, texture::Image, - RenderApp, RenderStage, - }, - sprite::Rect, - window::Windows, -}; -use kayak_core::{render_primitive::RenderPrimitive, styles::Corner, Binding, Bound}; -use kayak_font::KayakFont; - -use crate::{ - render::{ - ui_pass::TransparentUI, - unified::pipeline::{DrawUI, QuadMeta, UnifiedPipeline}, - }, - BevyContext, FontMapping, ImageManager, WindowSize, -}; - -use self::pipeline::{ExtractQuadBundle, ExtractedQuad, ImageBindGroups, UIQuadType}; - -pub mod font; -pub mod image; -mod nine_patch; -mod pipeline; -mod quad; - -pub const UNIFIED_SHADER_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 7604018236855288450); - -pub struct UnifiedRenderPlugin; - -impl Plugin for UnifiedRenderPlugin { - fn build(&self, app: &mut bevy::prelude::App) { - let mut shaders = app.world.get_resource_mut::<Assets<Shader>>().unwrap(); - let unified_shader = Shader::from_wgsl(include_str!("shader.wgsl")); - shaders.set_untracked(UNIFIED_SHADER_HANDLE, unified_shader); - - app.add_plugin(font::TextRendererPlugin) - .add_plugin(image::ImageRendererPlugin); - - let render_app = app.sub_app_mut(RenderApp); - render_app - .init_resource::<ImageBindGroups>() - .init_resource::<UnifiedPipeline>() - .init_resource::<QuadMeta>() - .add_system_to_stage(RenderStage::Extract, extract) - .add_system_to_stage(RenderStage::Prepare, pipeline::prepare_quads) - .add_system_to_stage(RenderStage::Queue, pipeline::queue_quads); - - let draw_quad = DrawUI::new(&mut render_app.world); - - render_app - .world - .get_resource::<DrawFunctions<TransparentUI>>() - .unwrap() - .write() - .add(draw_quad); - } -} - -pub struct Dpi(f32); - -pub fn extract( - mut commands: Commands, - context: Option<Res<BevyContext>>, - fonts: Res<Assets<KayakFont>>, - font_mapping: Res<FontMapping>, - image_manager: Res<ImageManager>, - images: Res<Assets<Image>>, - windows: Res<Windows>, - window_size: Res<Binding<WindowSize>>, -) { - if context.is_none() { - return; - } - - let context = context.unwrap(); - - let render_primitives = if let Ok(context) = context.kayak_context.read() { - context.widget_manager.build_render_primitives() - } else { - vec![] - }; - - // dbg!(&render_primitives); - - let dpi = if let Some(window) = windows.get_primary() { - window.scale_factor() as f32 - } else { - 1.0 - }; - - let mut extracted_quads = Vec::new(); - for render_primitive in render_primitives { - match render_primitive { - RenderPrimitive::Text { .. } => { - let text_quads = font::extract_texts(&render_primitive, &fonts, &font_mapping, dpi); - extracted_quads.extend(text_quads); - } - RenderPrimitive::Image { .. } => { - let image_quads = image::extract_images(&render_primitive, &image_manager, dpi); - extracted_quads.extend(image_quads); - } - RenderPrimitive::Quad { .. } => { - let quad_quads = quad::extract_quads(&render_primitive, 1.0); - extracted_quads.extend(quad_quads); - } - RenderPrimitive::NinePatch { .. } => { - let nine_patch_quads = - nine_patch::extract_nine_patch(&render_primitive, &image_manager, &images, dpi); - extracted_quads.extend(nine_patch_quads); - } - RenderPrimitive::Clip { layout } => { - extracted_quads.push(ExtractQuadBundle { - extracted_quad: ExtractedQuad { - rect: Rect { - min: Vec2::new(layout.posx, layout.posy) * dpi, - max: Vec2::new(layout.posx + layout.width, layout.posy + layout.height) - * dpi, - }, - color: Color::default(), - vertex_index: 0, - char_id: 0, - z_index: layout.z_index, - font_handle: None, - quad_type: UIQuadType::Clip, - type_index: 0, - border_radius: Corner::default(), - image: None, - uv_min: None, - uv_max: None, - }, - }); - } - _ => {} - } - } - - commands.insert_resource(window_size.get()); - commands.insert_resource(Dpi(dpi)); - commands.spawn_batch(extracted_quads); -} diff --git a/examples/todo/card.rs b/examples/todo/card.rs index 4b1bca6aa5234adfa6e77be7f43f28556abd4754..52f5b9b3e9ac7029d97743113356808458363f61 100644 --- a/examples/todo/card.rs +++ b/examples/todo/card.rs @@ -1,3 +1,4 @@ +use kayak_core::styles::Edge; use kayak_ui::core::{ rsx, styles::{LayoutType, Style, StyleProp, Units},