Skip to content
Snippets Groups Projects
Commit e9a55fc0 authored by John Mitchell's avatar John Mitchell
Browse files

Working on fixes to how context is managed.

parent ea637ae3
No related branches found
No related tags found
No related merge requests found
......@@ -90,17 +90,18 @@ pub struct KayakRootContext {
pub(crate) order_tree: Arc<RwLock<Tree>>,
pub(crate) index: Arc<RwLock<HashMap<Entity, usize>>>,
pub(crate) uninitilized_systems: HashSet<String>,
pub camera_entity: Entity,
}
impl Default for KayakRootContext {
fn default() -> Self {
Self::new()
Self::new(Entity::from_raw(0))
}
}
impl KayakRootContext {
/// Creates a new widget context.
pub fn new() -> Self {
pub fn new(camera_entity: Entity) -> Self {
Self {
tree: Arc::new(RwLock::new(Tree::default())),
layout_cache: Arc::new(RwLock::new(LayoutCache::default())),
......@@ -115,6 +116,7 @@ impl KayakRootContext {
index: Default::default(),
order_tree: Default::default(),
uninitilized_systems: Default::default(),
camera_entity,
}
}
......@@ -483,7 +485,7 @@ fn update_widgets_sys(world: &mut World) {
world,
);
for (camera_entity, mut context) in context_data.drain(..) {
for (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);
......@@ -516,7 +518,7 @@ fn update_widgets_sys(world: &mut World) {
// dbg!("Updating widgets!");
update_widgets(
camera_entity,
context.camera_entity,
world,
&context.tree,
&context.layout_cache,
......@@ -564,7 +566,7 @@ fn update_widgets_sys(world: &mut World) {
indices.clear();
}
world.entity_mut(camera_entity).insert(context);
world.entity_mut(entity).insert(context);
}
}
......@@ -586,14 +588,14 @@ fn update_widgets(
) {
for entity in widgets.iter() {
// A small hack to add parents to widgets
let mut command_queue = CommandQueue::default();
{
let mut commands = Commands::new(&mut command_queue, &world);
if let Some(mut entity_commands) = commands.get_entity(entity.0) {
entity_commands.set_parent(camera_entity);
}
}
command_queue.apply(world);
// let mut command_queue = CommandQueue::default();
// {
// let mut commands = Commands::new(&mut command_queue, &world);
// if let Some(mut entity_commands) = commands.get_entity(entity.0) {
// entity_commands.set_parent(camera_entity);
// }
// }
// command_queue.apply(world);
if let Some(entity_ref) = world.get_entity(entity.0) {
if let Some(widget_type) = entity_ref.get::<WidgetName>() {
......@@ -808,6 +810,7 @@ fn update_widget(
let new_tick = widget_update_system.get_last_change_tick();
new_ticks.insert(widget_type.clone(), new_tick);
widget_update_system.set_last_change_tick(old_tick);
widget_update_system.apply_buffers(world);
if should_rerender {
if let Ok(cloned_widget_entities) = cloned_widget_entities.try_read() {
......@@ -912,7 +915,7 @@ fn update_widget(
// Mark node as needing a recalculation of rendering/layout.
commands.entity(entity.0).insert(DirtyNode);
for (_index, changed_entity, _parent, changes) in diff.changes.iter() {
for (_index, changed_entity, parent, changes) in diff.changes.iter() {
if changes.iter().any(|change| *change == Change::Deleted) {
// commands.entity(changed_entity.0).despawn();
// commands.entity(changed_entity.0).remove::<DirtyNode>();
......@@ -921,6 +924,10 @@ fn update_widget(
if changes.iter().any(|change| *change == Change::Inserted) {
if let Some(mut entity_commands) = commands.get_entity(changed_entity.0) {
entity_commands.insert(Mounted);
entity_commands.set_parent(parent.0);
}
if let Some(mut parent_commands) = commands.get_entity(parent.0) {
parent_commands.add_child(changed_entity.0);
}
}
}
......
......@@ -62,6 +62,7 @@ pub mod prelude {
pub use crate::widgets;
pub use kayak_font::Alignment;
pub use kayak_ui_macros::{constructor, rsx};
pub use crate::render::draw_ui_graph;
}
pub use focus_tree::Focusable;
......
......@@ -2,12 +2,12 @@ use crate::{
context::{KayakRootContext, WidgetName},
node::Node,
render_primitive::RenderPrimitive,
styles::Corner,
styles::Corner, CameraUIKayak,
};
use bevy::{
prelude::{Assets, Camera, Color, Commands, Entity, Image, Plugin, Query, Rect, Res, Vec2},
render::{Extract, RenderApp, RenderStage},
window::Windows,
prelude::*,
render::{Extract, RenderApp, RenderStage, view::ExtractedView, render_phase::RenderPhase},
window::Windows, ui::TransparentUi,
};
use kayak_font::KayakFont;
......@@ -26,33 +26,40 @@ impl Plugin for BevyKayakUIExtractPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
let render_app = app.sub_app_mut(RenderApp);
render_app.add_system_to_stage(RenderStage::Extract, extract);
render_app.add_system_to_stage(RenderStage::Extract, extract_default_ui_camera_view::<Camera2d>);
render_app.add_system_to_stage(RenderStage::Extract, extract_default_ui_camera_view::<Camera3d>);
}
}
pub fn extract(
mut commands: Commands,
context_query: Extract<Query<(Entity, &KayakRootContext, &Camera)>>,
context_query: Extract<Query<(Entity, &KayakRootContext)>>,
fonts: Extract<Res<Assets<KayakFont>>>,
font_mapping: Extract<Res<FontMapping>>,
node_query: Extract<Query<&Node>>,
widget_names: Extract<Query<&WidgetName>>,
images: Extract<Res<Assets<Image>>>,
windows: Extract<Res<Windows>>,
cameras: Extract<Query<&Camera>>,
) {
let mut render_primitives = Vec::new();
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) {
window.scale_factor() as f32
} else {
1.0
for (_, context) in context_query.iter() {
let dpi = if let Ok(camera) = cameras.get(context.camera_entity) {
match &camera.target {
bevy::render::camera::RenderTarget::Window(window_id) => {
if let Some(window) = windows.get(*window_id) {
window.scale_factor() as f32
} else {
1.0
}
}
_ => 1.0,
}
_ => 1.0,
} else {
1.0
};
let mut new_render_primitives = context.build_render_primitives(&node_query, &widget_names);
render_primitives.extend(new_render_primitives.drain(..).map(|r| (entity, dpi, r)));
render_primitives.extend(new_render_primitives.drain(..).map(|r| (context.camera_entity, dpi, r)));
}
let mut extracted_quads = Vec::new();
......@@ -120,3 +127,48 @@ pub fn extract(
// dbg!(&extracted_quads);
commands.spawn_batch(extracted_quads);
}
#[derive(Component)]
pub struct DefaultCameraView(pub Entity);
const UI_CAMERA_TRANSFORM_OFFSET: f32 = -0.1;
pub fn extract_default_ui_camera_view<T: Component>(
mut commands: Commands,
query: Extract<Query<(Entity, &Camera, &CameraUIKayak), With<T>>>,
) {
for (entity, camera, camera_ui) in &query {
if let (Some(logical_size), Some((physical_origin, _)), Some(physical_size)) = (
camera.logical_viewport_size(),
camera.physical_viewport_rect(),
camera.physical_viewport_size(),
) {
// use a projection matrix with the origin in the top left instead of the bottom left that comes with OrthographicProjection
let projection_matrix =
Mat4::orthographic_rh(0.0, logical_size.x, logical_size.y, 0.0, 0.0, 1000.0);
let default_camera_view = commands
.spawn(ExtractedView {
projection: projection_matrix,
transform: GlobalTransform::from_xyz(
0.0,
0.0,
1000.0 + UI_CAMERA_TRANSFORM_OFFSET,
),
hdr: camera.hdr,
viewport: UVec4::new(
physical_origin.x,
physical_origin.y,
physical_size.x,
physical_size.y,
),
})
.id();
commands.get_or_spawn(entity).insert((
DefaultCameraView(default_camera_view),
RenderPhase::<TransparentUi>::default(),
));
}
}
}
\ No newline at end of file
......@@ -94,7 +94,7 @@ impl Plugin for BevyKayakUIRenderPlugin {
.unwrap();
graph_2d
.add_node_edge(
bevy::core_pipeline::core_2d::graph::node::TONEMAPPING,
bevy::core_pipeline::core_2d::graph::node::END_MAIN_PASS_POST_PROCESSING,
draw_ui_graph::node::MAIN_PASS,
)
.unwrap();
......@@ -120,7 +120,7 @@ impl Plugin for BevyKayakUIRenderPlugin {
.unwrap();
graph_3d
.add_node_edge(
bevy::core_pipeline::core_3d::graph::node::TONEMAPPING,
bevy::core_pipeline::core_3d::graph::node::END_MAIN_PASS_POST_PROCESSING,
draw_ui_graph::node::MAIN_PASS,
)
.unwrap();
......
......@@ -14,6 +14,8 @@ use bevy::utils::FloatOrd;
use crate::CameraUIKayak;
use super::extract::DefaultCameraView;
pub struct TransparentUI {
pub sort_key: FloatOrd,
pub entity: Entity,
......@@ -44,6 +46,7 @@ pub struct MainPassUINode {
),
With<ExtractedView>,
>,
default_camera_view_query: QueryState<&'static DefaultCameraView>,
}
impl MainPassUINode {
......@@ -52,6 +55,7 @@ impl MainPassUINode {
pub fn new(world: &mut World) -> Self {
Self {
query: world.query_filtered(),
default_camera_view_query: world.query(),
}
}
}
......@@ -63,6 +67,7 @@ impl Node for MainPassUINode {
fn update(&mut self, world: &mut World) {
self.query.update_archetypes(world);
self.default_camera_view_query.update_archetypes(world);
}
fn run(
......@@ -71,26 +76,37 @@ impl Node for MainPassUINode {
render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let input_view_entity = graph.get_input_entity(Self::IN_VIEW)?;
// adapted from bevy itself;
// see: <https://github.com/bevyengine/bevy/commit/09a3d8abe062984479bf0e99fcc1508bb722baf6>
let (transparent_phase, target, camera_ui) = match self.query.get_manual(world, view_entity)
let (transparent_phase, target, _camera_ui) = match self.query.get_manual(world, input_view_entity)
{
Ok(it) => it,
_ => return Ok(()),
};
let view_entity = if let Ok(default_view) = self
.default_camera_view_query
.get_manual(world, input_view_entity)
{
default_view.0
} else {
input_view_entity
};
// let clear_color = world.get_resource::<ClearColor>().unwrap();
{
let pass_descriptor = RenderPassDescriptor {
label: Some("main_transparent_pass_UI"),
color_attachments: &[Some(target.get_unsampled_color_attachment(Operations {
load: match camera_ui.clear_color {
ClearColorConfig::Default => {
LoadOp::Clear(world.resource::<ClearColor>().0.into())
}
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
ClearColorConfig::None => LoadOp::Load,
},
// load: match camera_ui.clear_color {
// ClearColorConfig::Default => {
// LoadOp::Clear(world.resource::<ClearColor>().0.into())
// }
// ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
// ClearColorConfig::None => LoadOp::Load,
// },
load: LoadOp::Load,
store: true,
}))],
depth_stencil_attachment: None,
......
......@@ -2,6 +2,7 @@ use bevy::prelude::{Msaa, Rect, Resource};
use bevy::render::render_resource::{
DynamicUniformBuffer, ShaderType, SpecializedRenderPipeline, SpecializedRenderPipelines,
};
use bevy::render::view::{ViewTarget, ExtractedView};
use bevy::utils::FloatOrd;
use bevy::{
ecs::system::{
......@@ -67,27 +68,10 @@ impl FontRenderingPipeline for UnifiedPipeline {
}
}
bitflags::bitflags! {
#[repr(transparent)]
pub struct UnifiedPipelineKey: u32 {
const NONE = 0;
const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS;
}
}
impl UnifiedPipelineKey {
const MSAA_MASK_BITS: u32 = 0b111;
const MSAA_SHIFT_BITS: u32 = 32 - Self::MSAA_MASK_BITS.count_ones();
pub fn from_msaa_samples(msaa_samples: u32) -> Self {
let msaa_bits =
(msaa_samples.trailing_zeros() & Self::MSAA_MASK_BITS) << Self::MSAA_SHIFT_BITS;
Self::from_bits(msaa_bits).unwrap()
}
pub fn msaa_samples(&self) -> u32 {
1 << ((self.bits >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS)
}
#[derive(Debug, Component, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UnifiedPipelineKey {
pub msaa: u32,
pub hdr: bool,
}
impl FromWorld for UnifiedPipeline {
......@@ -242,7 +226,7 @@ impl FromWorld for UnifiedPipeline {
impl SpecializedRenderPipeline for UnifiedPipeline {
type Key = UnifiedPipelineKey;
fn specialize(&self, _key: Self::Key) -> RenderPipelineDescriptor {
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
let vertex_buffer_layout = VertexBufferLayout {
array_stride: 60,
step_mode: VertexStepMode::Vertex,
......@@ -282,7 +266,11 @@ impl SpecializedRenderPipeline for UnifiedPipeline {
shader_defs: vec![],
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(),
format: if key.hdr {
ViewTarget::TEXTURE_FORMAT_HDR
} else {
TextureFormat::bevy_default()
},
blend: Some(BlendState {
color: BlendComponent {
src_factor: BlendFactor::SrcAlpha,
......@@ -315,7 +303,7 @@ impl SpecializedRenderPipeline for UnifiedPipeline {
},
depth_stencil: None,
multisample: MultisampleState {
count: 1,
count: key.msaa,
mask: !0,
alpha_to_coverage_enabled: false,
},
......@@ -534,7 +522,7 @@ pub fn queue_quads(
mut pipelines: ResMut<SpecializedRenderPipelines<UnifiedPipeline>>,
mut pipeline_cache: ResMut<PipelineCache>,
mut extracted_sprites: Query<(Entity, &ExtractedQuad)>,
mut views: Query<(Entity, &mut RenderPhase<TransparentUI>)>,
mut views: Query<(Entity, &mut RenderPhase<TransparentUI>, &ExtractedView)>,
mut image_bind_groups: ResMut<ImageBindGroups>,
unified_pipeline: Res<UnifiedPipeline>,
gpu_images: Res<RenderAssets<Image>>,
......@@ -562,15 +550,9 @@ pub fn queue_quads(
layout: &quad_pipeline.view_layout,
}));
let key = UnifiedPipelineKey::from_msaa_samples(msaa.samples);
let spec_pipeline = pipelines.specialize(&mut pipeline_cache, &quad_pipeline, key);
let draw_quad = draw_functions.read().get_id::<DrawUI>().unwrap();
for (camera_entity, mut transparent_phase) in views.iter_mut() {
for (camera_entity, mut transparent_phase, view) 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
......@@ -596,6 +578,12 @@ pub fn queue_quads(
});
}
}
let key = UnifiedPipelineKey {
msaa: 1,
hdr: view.hdr,
};
let spec_pipeline = pipelines.specialize(&mut pipeline_cache, &quad_pipeline, key);
transparent_phase.add(TransparentUI {
draw_function: draw_quad,
pipeline: spec_pipeline,
......
......@@ -225,6 +225,21 @@ impl KayakWidgetContext {
}
}
// Despawns a widget entity and it's decedents. This is done in a safe way by keeping entity id's around.
pub fn despawn_safe(&self, commands: &mut Commands, entity: Entity) {
if let Ok(mut tree) = self.old_tree.write() {
let mut down_iter = tree.down_iter();
down_iter.current_node = Some(WrappedIndex(entity));
for child in down_iter {
commands.entity(child.0).despawn();
commands.get_or_spawn(child.0);
}
commands.entity(entity).despawn();
commands.get_or_spawn(entity);
tree.remove(WrappedIndex(entity));
}
}
/// Attempts to get the layout rect for the widget with the given ID
///
/// # Arguments
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment