diff --git a/examples/multi_context.rs b/examples/multi_context.rs new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/render_target.rs b/examples/render_target.rs index 3df1195c9eee8d323b89fb00f5ce26e58d1452bb..32ffe6814625e1c25e7ff59269edc67903db15d6 100644 --- a/examples/render_target.rs +++ b/examples/render_target.rs @@ -59,14 +59,20 @@ fn startup( rsx! { <KayakAppBundle styles={KStyle { - padding: Edge::all(Units::Stretch(1.0)).into(), + padding: Edge::new( + Units::Stretch(1.0), + Units::Stretch(0.0), + Units::Stretch(1.0), + Units::Stretch(0.0), + ).into(), ..Default::default() }} > <TextWidgetBundle text={TextProps { size: 150.0, - content: "Hello World".into(), + content: "Hello Cube!".into(), + alignment: Alignment::Middle, ..Default::default() }} /> @@ -123,6 +129,23 @@ fn startup( .looking_at(Vec3::default(), Vec3::Y), ..default() }); + + // Spawn another UI in 2D space! + let mut widget_context = KayakRootContext::new(); + widget_context.add_plugin(KayakWidgetsContextPlugin); + let parent_id = None; + rsx! { + <KayakAppBundle> + <TextWidgetBundle + text={TextProps { + size: 100.0, + content: "Hello World!".into(), + ..Default::default() + }} + /> + </KayakAppBundle> + } + commands.spawn(UICameraBundle::new(widget_context)); } /// Rotates the outer cube (main pass) diff --git a/src/calculate_nodes.rs b/src/calculate_nodes.rs index 569ebfe9d9fa696ac1b3da50d8cc03deaff9da2a..1a6257e85e29379719e0d037548199e0b47c8184 100644 --- a/src/calculate_nodes.rs +++ b/src/calculate_nodes.rs @@ -24,19 +24,12 @@ pub fn calculate_nodes( node_query: Query<(Entity, &Node)>, ) -> KayakRootContext { let mut new_nodes = HashMap::<Entity, (Node, bool)>::default(); - // This is the maximum recursion depth for this method. - // Recursion involves recalculating layout which should be done sparingly. - // const MAX_RECURSION_DEPTH: usize = 2; context.current_z = 0.0; let initial_styles = KStyle::initial(); let default_styles = KStyle::new_default(); - // Jump out early. - // if query.is_empty() { - // return; - // } if let Ok(tree) = context.tree.clone().try_read() { if tree.root_node.is_none() { return context; diff --git a/src/context.rs b/src/context.rs index cada0317ff75036aef4234015460b3ca8353601a..ce07ef4cb898475b977e643cbe077e197592654f 100644 --- a/src/context.rs +++ b/src/context.rs @@ -468,7 +468,7 @@ fn update_widgets_sys(world: &mut World) { world, ); - for (entity, mut context) in context_data.drain(..) { + for (camera_entity, mut context) in context_data.drain(..) { for system_id in context.uninitilized_systems.drain() { if let Some(system) = context.systems.get_mut(&system_id) { system.0.initialize(world); @@ -501,6 +501,7 @@ fn update_widgets_sys(world: &mut World) { // dbg!("Updating widgets!"); update_widgets( + camera_entity, world, &context.tree, &context.layout_cache, @@ -548,11 +549,12 @@ fn update_widgets_sys(world: &mut World) { indices.clear(); } - world.entity_mut(entity).insert(context); + world.entity_mut(camera_entity).insert(context); } } fn update_widgets( + camera_entity: Entity, world: &mut World, tree: &Arc<RwLock<Tree>>, layout_cache: &Arc<RwLock<LayoutCache>>, @@ -577,6 +579,7 @@ fn update_widgets( widget_state.clone(), order_tree.clone(), index.clone(), + Some(camera_entity), ); widget_context.copy_from_point(tree, *entity); let children_before = widget_context.get_children(entity.0); @@ -674,6 +677,7 @@ fn update_widgets( vec![] }; update_widgets( + camera_entity, world, tree, layout_cache, diff --git a/src/event_dispatcher.rs b/src/event_dispatcher.rs index 92679cd085a2a4a6b5cc6f390a2a69da34b603bd..064c71cddc792c7b270ec0dfa6df644a4ff26c6c 100644 --- a/src/event_dispatcher.rs +++ b/src/event_dispatcher.rs @@ -245,6 +245,7 @@ impl EventDispatcher { context.widget_state.clone(), context.order_tree.clone(), context.index.clone(), + None, ); node_event.run_on_change(world, widget_context); } diff --git a/src/render/extract.rs b/src/render/extract.rs index 5f85576dd4d3185db07de440cca2782d4c5419d5..858c3aee097056dfab6c5421849e10334c68f688 100644 --- a/src/render/extract.rs +++ b/src/render/extract.rs @@ -5,7 +5,7 @@ use crate::{ styles::Corner, }; use bevy::{ - prelude::{Assets, Camera, Color, Commands, Image, Plugin, Query, Rect, Res, Vec2}, + prelude::{Assets, Camera, Color, Commands, Image, Plugin, Query, Rect, Res, Vec2, Entity}, render::{Extract, RenderApp, RenderStage}, window::Windows, }; @@ -31,7 +31,7 @@ impl Plugin for BevyKayakUIExtractPlugin { pub fn extract( mut commands: Commands, - context_query: Extract<Query<(&KayakRootContext, &Camera)>>, + context_query: Extract<Query<(Entity, &KayakRootContext, &Camera)>>, fonts: Extract<Res<Assets<KayakFont>>>, font_mapping: Extract<Res<FontMapping>>, node_query: Extract<Query<&Node>>, @@ -40,7 +40,7 @@ pub fn extract( windows: Extract<Res<Windows>>, ) { let mut render_primitives = Vec::new(); - for (context, camera) in context_query.iter() { + for (entity, context, camera) in context_query.iter() { let dpi = match &camera.target { bevy::render::camera::RenderTarget::Window(window_id) => { if let Some(window) = windows.get(*window_id) { @@ -52,37 +52,38 @@ pub fn extract( _ => 1.0, }; let mut new_render_primitives = context.build_render_primitives(&node_query, &widget_names); - render_primitives.extend(new_render_primitives.drain(..).map(|r| (dpi, r))); + render_primitives.extend(new_render_primitives.drain(..).map(|r| (entity, dpi, r))); } let mut extracted_quads = Vec::new(); - for (dpi, render_primitive) in render_primitives { + for (camera_entity, dpi, render_primitive) in render_primitives { match render_primitive { RenderPrimitive::Text { .. } => { - let text_quads = font::extract_texts(&render_primitive, &fonts, &font_mapping, dpi); + let text_quads = font::extract_texts(camera_entity, &render_primitive, &fonts, &font_mapping, dpi); extracted_quads.extend(text_quads); } RenderPrimitive::Image { .. } => { - let image_quads = image::extract_images(&render_primitive, dpi); + let image_quads = image::extract_images(camera_entity, &render_primitive, dpi); extracted_quads.extend(image_quads); } RenderPrimitive::Quad { .. } => { - let quad_quads = super::quad::extract_quads(&render_primitive, 1.0); + let quad_quads = super::quad::extract_quads(camera_entity, &render_primitive, 1.0); extracted_quads.extend(quad_quads); } RenderPrimitive::NinePatch { .. } => { let nine_patch_quads = - nine_patch::extract_nine_patch(&render_primitive, &images, dpi); + nine_patch::extract_nine_patch(camera_entity, &render_primitive, &images, dpi); extracted_quads.extend(nine_patch_quads); } RenderPrimitive::TextureAtlas { .. } => { let texture_atlas_quads = - texture_atlas::extract_texture_atlas(&render_primitive, &images, dpi); + texture_atlas::extract_texture_atlas(camera_entity, &render_primitive, &images, dpi); extracted_quads.extend(texture_atlas_quads); } RenderPrimitive::Clip { layout } => { extracted_quads.push(ExtractQuadBundle { extracted_quad: ExtractedQuad { + camera_entity, rect: Rect { min: Vec2::new(layout.posx, layout.posy) * dpi, max: Vec2::new(layout.posx + layout.width, layout.posy + layout.height) diff --git a/src/render/font/extract.rs b/src/render/font/extract.rs index ffbd8ea3391773c302f16a74b8940127a959acac..fc8251bb13eda4ef9807901ad50ff29200863b53 100644 --- a/src/render/font/extract.rs +++ b/src/render/font/extract.rs @@ -1,6 +1,6 @@ use bevy::{ math::Vec2, - prelude::{Assets, Rect, Res}, + prelude::{Assets, Rect, Res, Entity}, }; use kayak_font::KayakFont; @@ -13,6 +13,7 @@ use crate::{ use super::font_mapping::FontMapping; pub fn extract_texts( + camera_entity: Entity, render_primitive: &RenderPrimitive, fonts: &Res<Assets<KayakFont>>, font_mapping: &Res<FontMapping>, @@ -49,6 +50,7 @@ pub fn extract_texts( extracted_texts.push(ExtractQuadBundle { extracted_quad: ExtractedQuad { + camera_entity, font_handle: Some(font_handle.clone()), rect: Rect { min: position, diff --git a/src/render/image/extract.rs b/src/render/image/extract.rs index 0af91427e23d714a9c3d4fc74bf11c4714d61d0a..4b0bbdc00552d184f3f07c07c251452422d0830a 100644 --- a/src/render/image/extract.rs +++ b/src/render/image/extract.rs @@ -3,9 +3,13 @@ use crate::{ render_primitive::RenderPrimitive, styles::Corner, }; -use bevy::{math::Vec2, prelude::Rect, render::color::Color}; +use bevy::{math::Vec2, prelude::{Rect, Entity}, render::color::Color}; -pub fn extract_images(render_command: &RenderPrimitive, _dpi: f32) -> Vec<ExtractQuadBundle> { +pub fn extract_images( + camera_entity: Entity, + render_command: &RenderPrimitive, + _dpi: f32, +) -> Vec<ExtractQuadBundle> { let (border_radius, layout, handle) = match render_command { RenderPrimitive::Image { border_radius, @@ -17,6 +21,7 @@ pub fn extract_images(render_command: &RenderPrimitive, _dpi: f32) -> Vec<Extrac vec![ExtractQuadBundle { extracted_quad: ExtractedQuad { + camera_entity, rect: Rect { min: Vec2::new(layout.posx, layout.posy), max: Vec2::new(layout.posx + layout.width, layout.posy + layout.height), diff --git a/src/render/mod.rs b/src/render/mod.rs index 001531bf9a14511a8d1b17fe5542f1eadd583997..57ed35388d656f8391b330ec1c8805fdd14bf232 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,5 +1,5 @@ use bevy::{ - prelude::{App, Commands, Entity, Plugin, Query, With}, + prelude::{App, Commands, Entity, Plugin, Query, With, Camera}, render::{ render_graph::{RenderGraph, RunGraphOnViewNode, SlotInfo, SlotType}, render_phase::{DrawFunctions, RenderPhase}, @@ -167,11 +167,13 @@ fn get_ui_graph(render_app: &mut App) -> RenderGraph { pub fn extract_core_pipeline_camera_phases( mut commands: Commands, - active_camera: Extract<Query<Entity, With<CameraUIKayak>>>, + active_cameras: Extract<Query<(Entity, &Camera), With<CameraUIKayak>>>, ) { - if let Ok(entity) = active_camera.get_single() { - commands - .get_or_spawn(entity) - .insert(RenderPhase::<TransparentUI>::default()); + for (entity, camera) in &active_cameras { + if camera.is_active { + commands + .get_or_spawn(entity) + .insert(RenderPhase::<TransparentUI>::default()); + } } } diff --git a/src/render/nine_patch/extract.rs b/src/render/nine_patch/extract.rs index a4d0b6356f3050ab963d8beb7a4fdb3927fb9a30..ac361e8cf04ca45cb61fea1aacfc48fa657d2b0f 100644 --- a/src/render/nine_patch/extract.rs +++ b/src/render/nine_patch/extract.rs @@ -5,11 +5,12 @@ use crate::{ }; use bevy::{ math::Vec2, - prelude::{Assets, Rect, Res}, + prelude::{Assets, Rect, Res, Entity}, render::{color::Color, texture::Image}, }; pub fn extract_nine_patch( + camera_entity: Entity, render_primitive: &RenderPrimitive, images: &Res<Assets<Image>>, dpi: f32, @@ -42,6 +43,7 @@ pub fn extract_nine_patch( * dpi; let extracted_quad_template = ExtractedQuad { + camera_entity, rect: Rect { min: Vec2::ZERO, max: Vec2::ZERO, diff --git a/src/render/quad/extract.rs b/src/render/quad/extract.rs index 9f5f6228383bfd064a6bb7b8b3a916466b205d9e..ebe984867764005d73714ac30026eab07ff5347d 100644 --- a/src/render/quad/extract.rs +++ b/src/render/quad/extract.rs @@ -3,9 +3,13 @@ use crate::{ render_primitive::RenderPrimitive, styles::Corner, }; -use bevy::{math::Vec2, prelude::Rect}; +use bevy::{math::Vec2, prelude::{Rect, Entity}}; -pub fn extract_quads(render_primitive: &RenderPrimitive, dpi: f32) -> Vec<ExtractQuadBundle> { +pub fn extract_quads( + camera_entity: Entity, + render_primitive: &RenderPrimitive, + dpi: f32, +) -> Vec<ExtractQuadBundle> { let (background_color, border_color, layout, border_radius, mut border) = match render_primitive { RenderPrimitive::Quad { @@ -30,6 +34,7 @@ pub fn extract_quads(render_primitive: &RenderPrimitive, dpi: f32) -> Vec<Extrac // Border ExtractQuadBundle { extracted_quad: ExtractedQuad { + camera_entity, rect: Rect { min: Vec2::new(layout.posx, layout.posy), max: Vec2::new( @@ -57,6 +62,7 @@ pub fn extract_quads(render_primitive: &RenderPrimitive, dpi: f32) -> Vec<Extrac }, ExtractQuadBundle { extracted_quad: ExtractedQuad { + camera_entity, rect: Rect { min: Vec2::new(layout.posx + border.left, layout.posy + border.top), max: Vec2::new( diff --git a/src/render/texture_atlas/extract.rs b/src/render/texture_atlas/extract.rs index ebc669285be5f95ad787bce98a289e91c95d9d5c..336ad115c3f1d8b4b487d1bbaada7703a2251427 100644 --- a/src/render/texture_atlas/extract.rs +++ b/src/render/texture_atlas/extract.rs @@ -5,11 +5,12 @@ use crate::{ }; use bevy::{ math::Vec2, - prelude::{Assets, Rect, Res}, + prelude::{Assets, Rect, Res, Entity}, render::{color::Color, texture::Image}, }; pub fn extract_texture_atlas( + camera_entity: Entity, render_primitive: &RenderPrimitive, images: &Res<Assets<Image>>, dpi: f32, @@ -44,6 +45,7 @@ pub fn extract_texture_atlas( let quad = ExtractQuadBundle { extracted_quad: ExtractedQuad { + camera_entity, rect: Rect { min: Vec2::new(layout.posx, layout.posy), max: Vec2::new(layout.posx + layout.width, layout.posy + layout.height), diff --git a/src/render/unified/pipeline.rs b/src/render/unified/pipeline.rs index e1b8ff444900ae3c442ddfcc2c7ae382abc34666..4c4cd040d4ab9a94721da70f236a0d8bee25f860 100644 --- a/src/render/unified/pipeline.rs +++ b/src/render/unified/pipeline.rs @@ -339,6 +339,7 @@ pub enum UIQuadType { #[derive(Debug, Component, Clone)] pub struct ExtractedQuad { + pub camera_entity: Entity, pub rect: Rect, pub color: Color, pub vertex_index: usize, @@ -525,7 +526,7 @@ pub fn queue_quads( mut pipelines: ResMut<SpecializedRenderPipelines<UnifiedPipeline>>, mut pipeline_cache: ResMut<PipelineCache>, mut extracted_sprites: Query<(Entity, &ExtractedQuad)>, - mut views: Query<&mut RenderPhase<TransparentUI>>, + mut views: Query<(Entity, &mut RenderPhase<TransparentUI>)>, mut image_bind_groups: ResMut<ImageBindGroups>, unified_pipeline: Res<UnifiedPipeline>, gpu_images: Res<RenderAssets<Image>>, @@ -557,8 +558,11 @@ pub fn queue_quads( let spec_pipeline = pipelines.specialize(&mut pipeline_cache, &quad_pipeline, key); let draw_quad = draw_functions.read().get_id::<DrawUI>().unwrap(); - for mut transparent_phase in views.iter_mut() { + for (camera_entity, mut transparent_phase) in views.iter_mut() { for (entity, quad) in extracted_sprites.iter_mut() { + if quad.camera_entity != camera_entity { + continue; + } if let Some(image_handle) = quad.image.as_ref() { if let Some(gpu_image) = gpu_images.get(image_handle) { image_bind_groups diff --git a/src/widget_context.rs b/src/widget_context.rs index 588e1ccd41c2abfa7179a281a02f2d98590a50f6..c6e64c770389ec4737fb9c45fd6fd9ada62f9f69 100644 --- a/src/widget_context.rs +++ b/src/widget_context.rs @@ -26,6 +26,7 @@ pub struct KayakWidgetContext { pub(crate) index: Arc<RwLock<HashMap<Entity, usize>>>, widget_state: WidgetState, order_tree: Arc<RwLock<Tree>>, + pub camera_entity: Option<Entity>, } impl KayakWidgetContext { @@ -36,6 +37,7 @@ impl KayakWidgetContext { widget_state: WidgetState, order_tree: Arc<RwLock<Tree>>, index: Arc<RwLock<HashMap<Entity, usize>>>, + camera_entity: Option<Entity>, ) -> Self { Self { old_tree, @@ -45,6 +47,7 @@ impl KayakWidgetContext { index, widget_state, order_tree, + camera_entity, } } diff --git a/src/widgets/app.rs b/src/widgets/app.rs index 4626c2a6377cae135c3adb5815587007b4571100..9d371177800e0a1acfc94a5745c6f84952d1026a 100644 --- a/src/widgets/app.rs +++ b/src/widgets/app.rs @@ -69,10 +69,12 @@ pub fn app_render( ) -> bool { let (mut width, mut height) = (0.0, 0.0); - if let Ok(camera) = camera.get_single() { - if let Some(size) = camera.logical_viewport_size() { - width = size.x; - height = size.y; + if let Some(camera_entity) = widget_context.camera_entity { + if let Ok(camera) = camera.get(camera_entity) { + if let Some(size) = camera.logical_viewport_size() { + width = size.x; + height = size.y; + } } }