From 9502337fb5dbb1366cc1db438eab370591c1de16 Mon Sep 17 00:00:00 2001
From: John Mitchell <startoaster23@gmail.com>
Date: Sun, 13 Nov 2022 22:06:58 -0500
Subject: [PATCH] Working mult-context renderer.

---
 examples/multi_context.rs           |  0
 examples/render_target.rs           | 27 +++++++++++++++++++++++++--
 src/calculate_nodes.rs              |  7 -------
 src/context.rs                      |  8 ++++++--
 src/event_dispatcher.rs             |  1 +
 src/render/extract.rs               | 21 +++++++++++----------
 src/render/font/extract.rs          |  4 +++-
 src/render/image/extract.rs         |  9 +++++++--
 src/render/mod.rs                   | 14 ++++++++------
 src/render/nine_patch/extract.rs    |  4 +++-
 src/render/quad/extract.rs          | 10 ++++++++--
 src/render/texture_atlas/extract.rs |  4 +++-
 src/render/unified/pipeline.rs      |  8 ++++++--
 src/widget_context.rs               |  3 +++
 src/widgets/app.rs                  | 10 ++++++----
 15 files changed, 90 insertions(+), 40 deletions(-)
 create mode 100644 examples/multi_context.rs

diff --git a/examples/multi_context.rs b/examples/multi_context.rs
new file mode 100644
index 0000000..e69de29
diff --git a/examples/render_target.rs b/examples/render_target.rs
index 3df1195..32ffe68 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 569ebfe..1a6257e 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 cada031..ce07ef4 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 92679cd..064c71c 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 5f85576..858c3ae 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 ffbd8ea..fc8251b 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 0af9142..4b0bbdc 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 001531b..57ed353 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 a4d0b63..ac361e8 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 9f5f622..ebe9848 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 ebc6692..336ad11 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 e1b8ff4..4c4cd04 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 588e1cc..c6e64c7 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 4626c2a..9d37117 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;
+            }
         }
     }
 
-- 
GitLab