Skip to content
Snippets Groups Projects
Unverified Commit 64b5c7bc authored by John's avatar John Committed by GitHub
Browse files

Merge pull request #23 from StarArawn/fix-resize-bug

Clipping issues are fixed. Multiple other bugs fixed! :tada:
parents 5aa0d6d0 8c631cb9
No related branches found
No related tags found
No related merge requests found
Showing
with 139 additions and 138 deletions
......@@ -421,7 +421,6 @@ dependencies = [
"crevice",
"kayak_core",
"kayak_font",
"kayak_render_macros",
"serde",
"serde_json",
"serde_path_to_error",
......@@ -1923,6 +1922,7 @@ dependencies = [
name = "kayak_widgets"
version = "0.1.0"
dependencies = [
"bevy",
"kayak_ui",
]
......
......@@ -26,4 +26,4 @@ kayak_render_macros = { path = "kayak_render_macros" }
[dev-dependencies]
bevy = { git = "https://github.com/StarArawn/bevy", rev = "bcca341d696c66d0173d8b0ac7a1b23b4b9e775c" }
kayak_widgets = { path = "kayak_widgets" }
kayak_widgets = { path = "kayak_widgets", features = ["bevy_renderer"] }
......@@ -7,7 +7,6 @@ edition = "2021"
bytemuck = "1.7.2"
bevy = { git = "https://github.com/StarArawn/bevy", rev = "bcca341d696c66d0173d8b0ac7a1b23b4b9e775c" }
kayak_core = { path = "../kayak_core" }
kayak_render_macros = { path = "../kayak_render_macros" }
kayak_font = { path = "../kayak_font" }
#kayak_font = { path = "../kayak_font" }
crevice = { git = "https://github.com/StarArawn/bevy", rev = "bcca341d696c66d0173d8b0ac7a1b23b4b9e775c" }
......
use std::sync::{Arc, RwLock};
use kayak_core::{
context::KayakContext,
render_command::RenderCommand,
styles::{Style, StyleProp, Units},
};
use kayak_core::context::KayakContext;
pub struct BevyContext {
pub kayak_context: Arc<RwLock<KayakContext>>,
}
impl BevyContext {
pub fn new<F: Fn(&mut Style, &mut KayakContext)>(width: f32, height: f32, f: F) -> Self {
let mut app_styles = Style {
render_command: StyleProp::Value(RenderCommand::Window),
width: StyleProp::Value(Units::Pixels(width)),
height: StyleProp::Value(Units::Pixels(height)),
..Style::default()
};
pub fn new<F: Fn(&mut KayakContext)>(f: F) -> Self {
let kayak_context = Arc::new(RwLock::new(KayakContext::new()));
if let Ok(mut kayak_context) = kayak_context.write() {
f(&mut app_styles, &mut kayak_context);
f(&mut kayak_context);
kayak_context.widget_manager.dirty(true);
}
......
......@@ -3,7 +3,7 @@ use bevy::{
math::Vec2,
prelude::{EventReader, IntoExclusiveSystem, MouseButton, Plugin, Res, World},
render::color::Color,
window::{CursorMoved, Windows},
window::{CursorMoved, WindowCreated, WindowResized, Windows},
};
mod bevy_context;
......@@ -12,7 +12,7 @@ mod render;
pub use bevy_context::BevyContext;
pub use camera::*;
use kayak_core::InputEvent;
use kayak_core::{bind, Binding, InputEvent, MutableBound};
pub use render::unified::font::FontMapping;
pub use render::unified::image::ImageManager;
......@@ -21,8 +21,10 @@ pub struct BevyKayakUIPlugin;
impl Plugin for BevyKayakUIPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_plugin(render::BevyKayakUIRenderPlugin)
app.insert_resource(bind(WindowSize::default()))
.add_plugin(render::BevyKayakUIRenderPlugin)
.add_plugin(camera::KayakUICameraPlugin)
.add_system(update_window_size)
.add_system(process_events)
.add_system(update.exclusive_system());
}
......@@ -79,3 +81,43 @@ pub fn process_events(
context.process_events(input_events);
}
}
/// 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>,
windows: Res<Windows>,
window_size: Res<Binding<WindowSize>>,
) {
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);
}
for window_id in changed_window_ids {
if let Some(window) = windows.get(window_id) {
let width = window.width();
let height = window.height();
window_size.set(WindowSize(width, height));
}
}
}
......@@ -8,7 +8,7 @@ use bevy::{
},
sprite::Rect,
};
use kayak_core::render_primitive::RenderPrimitive;
use kayak_core::{render_primitive::RenderPrimitive, Binding, Bound};
use kayak_font::KayakFont;
use crate::{
......@@ -16,7 +16,7 @@ use crate::{
ui_pass::TransparentUI,
unified::pipeline::{DrawUI, QuadMeta, UnifiedPipeline},
},
BevyContext, FontMapping, ImageManager,
BevyContext, FontMapping, ImageManager, WindowSize,
};
use self::pipeline::{ExtractQuadBundle, ExtractedQuad, ImageBindGroups, UIQuadType};
......@@ -68,6 +68,7 @@ pub fn extract(
font_mapping: Res<FontMapping>,
image_manager: Res<ImageManager>,
images: Res<Assets<Image>>,
window_size: Res<Binding<WindowSize>>,
) {
let render_primitives = if let Ok(context) = context.kayak_context.read() {
context.widget_manager.build_render_primitives()
......@@ -75,6 +76,8 @@ pub fn extract(
vec![]
};
// dbg!(&render_primitives);
let mut extracted_quads = Vec::new();
for render_primitive in render_primitives {
match render_primitive {
......@@ -120,5 +123,6 @@ pub fn extract(
}
}
commands.insert_resource(window_size.get());
commands.spawn_batch(extracted_quads);
}
......@@ -34,7 +34,7 @@ use crevice::std140::AsStd140;
use kayak_font::{FontRenderingPipeline, FontTextureCache, KayakFont};
use super::UNIFIED_SHADER_HANDLE;
use crate::render::ui_pass::TransparentUI;
use crate::{render::ui_pass::TransparentUI, WindowSize};
pub struct UnifiedPipeline {
view_layout: BindGroupLayout,
......@@ -547,6 +547,7 @@ pub struct DrawUI {
SRes<RenderPipelineCache>,
SRes<FontTextureCache>,
SRes<ImageBindGroups>,
SRes<WindowSize>,
SQuery<Read<ViewUniformOffset>>,
SQuery<Read<ExtractedQuad>>,
)>,
......@@ -574,6 +575,7 @@ impl Draw<TransparentUI> for DrawUI {
pipelines,
font_texture_cache,
image_bind_groups,
window_size,
views,
quads,
) = self.params.get(world);
......@@ -585,8 +587,13 @@ impl Draw<TransparentUI> for DrawUI {
if extracted_quad.quad_type == UIQuadType::Clip {
let x = extracted_quad.rect.min.x as u32;
let y = extracted_quad.rect.min.y as u32;
let width = extracted_quad.rect.width() as u32;
let height = extracted_quad.rect.height() as u32;
let mut width = extracted_quad.rect.width() as u32;
let mut height = extracted_quad.rect.height() as u32;
width = width.min(window_size.0 as u32);
height = height.min(window_size.1 as u32);
if width == 0 || height == 0 {
return;
}
pass.set_scissor_rect(x, y, width, height);
return;
}
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Res, ResMut},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, FontMapping, UICameraBundle};
......@@ -25,7 +24,6 @@ fn CustomWidget() {
fn startup(
mut commands: Commands,
windows: Res<Windows>,
mut font_mapping: ResMut<FontMapping>,
asset_server: Res<AssetServer>,
) {
......@@ -33,15 +31,9 @@ fn startup(
font_mapping.add(asset_server.load("roboto.kayak_font"));
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
render! {
<App styles={Some(styles.clone())}>
<App>
<CustomWidget/>
</App>
}
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Handle, Res, ResMut},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, FontMapping, ImageManager, UICameraBundle};
......@@ -15,25 +14,18 @@ use kayak_widgets::{App, Clip, NinePatch, Text};
fn startup(
mut commands: Commands,
windows: Res<Windows>,
asset_server: Res<AssetServer>,
mut image_manager: ResMut<ImageManager>,
mut font_mapping: ResMut<FontMapping>,
) {
commands.spawn_bundle(UICameraBundle::new());
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
font_mapping.add(asset_server.load("roboto.kayak_font"));
let handle: Handle<bevy::render::texture::Image> = asset_server.load("kenny/panel_brown.png");
let panel_brown_handle = image_manager.get(&handle);
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
let nine_patch_styles = Style {
width: StyleProp::Value(Units::Pixels(512.0)),
height: StyleProp::Value(Units::Pixels(512.0)),
......@@ -69,7 +61,7 @@ Vestibulum rutrum imperdiet nisl, et consequat massa porttitor vel. Ut velit jus
"#.to_string();
render! {
<App styles={Some(styles.clone())}>
<App>
<NinePatch
styles={Some(nine_patch_styles)}
border={Space {
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Res, ResMut},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, FontMapping, UICameraBundle};
......@@ -58,7 +57,6 @@ fn Counter(context: &mut KayakContext) {
fn startup(
mut commands: Commands,
windows: Res<Windows>,
mut font_mapping: ResMut<FontMapping>,
asset_server: Res<AssetServer>,
) {
......@@ -66,15 +64,9 @@ fn startup(
font_mapping.add(asset_server.load("roboto.kayak_font"));
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
render! {
<App styles={Some(styles.clone())}>
<App>
<Counter />
</App>
}
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Handle, Res, ResMut, World},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, FontMapping, ImageManager, UICameraBundle};
......@@ -82,25 +81,18 @@ fn BlueButton(context: KayakContext, children: Children, styles: Option<Style>)
fn startup(
mut commands: Commands,
windows: Res<Windows>,
asset_server: Res<AssetServer>,
mut image_manager: ResMut<ImageManager>,
mut font_mapping: ResMut<FontMapping>,
) {
commands.spawn_bundle(UICameraBundle::new());
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
font_mapping.add(asset_server.load("roboto.kayak_font"));
let handle: Handle<bevy::render::texture::Image> = asset_server.load("kenny/panel_brown.png");
let panel_brown_handle = image_manager.get(&handle);
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
let nine_patch_styles = Style {
layout_type: StyleProp::Value(LayoutType::Column),
width: StyleProp::Value(Units::Pixels(512.0)),
......@@ -117,7 +109,7 @@ fn startup(
padding_right: StyleProp::Value(Units::Stretch(1.0)),
padding_top: StyleProp::Value(Units::Stretch(1.0)),
padding_bottom: StyleProp::Value(Units::Stretch(1.0)),
..styles.clone()
..Style::default()
};
let header_styles = Style {
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Res, ResMut, World},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, FontMapping, UICameraBundle};
......@@ -40,7 +39,6 @@ fn Counter(context: &mut KayakContext) {
fn startup(
mut commands: Commands,
windows: Res<Windows>,
mut font_mapping: ResMut<FontMapping>,
asset_server: Res<AssetServer>,
) {
......@@ -48,17 +46,11 @@ fn startup(
font_mapping.add(asset_server.load("roboto.kayak_font"));
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
commands.insert_resource(bind(GlobalCount(0)));
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
render! {
<App styles={Some(styles.clone())}>
<App>
<Counter />
</App>
}
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Res, ResMut},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, FontMapping, UICameraBundle};
......@@ -60,7 +59,6 @@ fn Removal(context: &mut KayakContext) {
fn startup(
mut commands: Commands,
windows: Res<Windows>,
mut font_mapping: ResMut<FontMapping>,
asset_server: Res<AssetServer>,
) {
......@@ -68,15 +66,9 @@ fn startup(
font_mapping.add(asset_server.load("roboto.kayak_font"));
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
render! {
<App styles={Some(styles.clone())}>
<App>
<Removal />
</App>
}
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Handle, Res, ResMut},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, ImageManager, UICameraBundle};
......@@ -14,22 +13,15 @@ use kayak_widgets::{App, Image};
fn startup(
mut commands: Commands,
windows: Res<Windows>,
asset_server: Res<AssetServer>,
mut image_manager: ResMut<ImageManager>,
) {
commands.spawn_bundle(UICameraBundle::new());
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
let handle: Handle<bevy::render::texture::Image> = asset_server.load("generic-rpg-vendor.png");
let ui_image_handle = image_manager.get(&handle);
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
let image_styles = Style {
width: StyleProp::Value(Units::Pixels(200.0)),
height: StyleProp::Value(Units::Pixels(182.0)),
......@@ -37,7 +29,7 @@ fn startup(
};
render! {
<App styles={Some(styles.clone())}>
<App>
<Image styles={Some(image_styles)} handle={ui_image_handle} />
</App>
}
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Handle, Res, ResMut},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, ImageManager, UICameraBundle};
......@@ -15,22 +14,15 @@ use kayak_widgets::{App, NinePatch};
fn startup(
mut commands: Commands,
windows: Res<Windows>,
asset_server: Res<AssetServer>,
mut image_manager: ResMut<ImageManager>,
) {
commands.spawn_bundle(UICameraBundle::new());
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
let handle: Handle<bevy::render::texture::Image> = asset_server.load("panel.png");
let ui_image_handle = image_manager.get(&handle);
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
// The border prop splits up the image into 9 quadrants like so:
// 1----2----3
// | |
......@@ -61,7 +53,7 @@ fn startup(
};
render! {
<App styles={Some(styles.clone())}>
<App>
<NinePatch
styles={Some(nine_patch_styles)}
border={Space {
......
use bevy::{
math::Vec2,
prelude::{App as BevyApp, AssetServer, Commands, Res, ResMut},
window::{WindowDescriptor, Windows},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_core::constructor;
......@@ -11,7 +10,6 @@ use kayak_widgets::{App, Text};
fn startup(
mut commands: Commands,
windows: Res<Windows>,
mut font_mapping: ResMut<FontMapping>,
asset_server: Res<AssetServer>,
) {
......@@ -19,16 +17,10 @@ fn startup(
font_mapping.add(asset_server.load("roboto.kayak_font"));
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width(), window.height())
} else {
panic!("Couldn't find primary window!");
};
let context = BevyContext::new(window_size.x, window_size.y, |styles, context| {
let context = BevyContext::new(|context| {
let data = vec!["Text1", "Text2", "Text3", "Text4"];
render! {
<App styles={Some(styles.clone())}>
<App>
{VecTracker::from(data.iter().map(|data| {
constructor! {
<Text content={data.clone().to_string()} size={16.0} />
......
......@@ -209,16 +209,10 @@ impl KayakContext {
panic!("Couldn't get lock on dirty nodes!")
};
for node_index in dirty_nodes {
// if self
// .widget_manager
// .dirty_nodes
// .iter()
// .any(|dirty_index| node_index == *dirty_index)
// {
let mut widget = self.widget_manager.take(node_index);
widget.render(self);
self.widget_manager.repossess(widget);
// }
self.widget_manager.dirty_render_nodes.insert(node_index);
}
// self.widget_manager.dirty_nodes.clear();
......
......@@ -17,7 +17,7 @@ use crate::{
#[derive(Debug)]
pub struct WidgetManager {
pub(crate) current_widgets: Arena<Option<Box<dyn Widget>>>,
pub(crate) dirty_render_nodes: Vec<Index>,
pub(crate) dirty_render_nodes: HashSet<Index>,
pub(crate) dirty_nodes: Arc<Mutex<HashSet<Index>>>,
pub(crate) nodes: Arena<Option<Node>>,
pub tree: Tree,
......@@ -30,7 +30,7 @@ impl WidgetManager {
pub fn new() -> Self {
Self {
current_widgets: Arena::new(),
dirty_render_nodes: Vec::new(),
dirty_render_nodes: HashSet::new(),
dirty_nodes: Arc::new(Mutex::new(HashSet::new())),
nodes: Arena::new(),
tree: Tree::default(),
......@@ -51,7 +51,7 @@ impl WidgetManager {
if force {
for (node_index, _) in self.current_widgets.iter() {
dirty_nodes.insert(node_index);
self.dirty_render_nodes.push(node_index);
self.dirty_render_nodes.insert(node_index);
}
}
}
......@@ -86,7 +86,7 @@ impl WidgetManager {
let boxed_widget: Box<dyn Widget> = Box::new(widget);
*self.current_widgets[*widget_id].as_mut().unwrap() = boxed_widget;
// Tell renderer that the nodes changed.
self.dirty_render_nodes.push(*widget_id);
self.dirty_render_nodes.insert(*widget_id);
return (true, *widget_id);
// } else {
// return (false, *widget_id);
......@@ -106,7 +106,7 @@ impl WidgetManager {
.set_id(widget_id);
// Tell renderer that the nodes changed.
self.dirty_render_nodes.push(widget_id);
self.dirty_render_nodes.insert(widget_id);
// Remove from the dirty nodes lists.
// if let Some(index) = self.dirty_nodes.iter().position(|id| widget_id == *id) {
......@@ -148,7 +148,7 @@ impl WidgetManager {
width: crate::styles::StyleProp::Default,
..Style::default()
};
for dirty_node_index in self.dirty_render_nodes.drain(..) {
for dirty_node_index in self.dirty_render_nodes.drain() {
let dirty_widget = self.current_widgets[dirty_node_index].as_ref().unwrap();
let parent_styles =
if let Some(parent_widget_id) = self.tree.parents.get(&dirty_node_index) {
......@@ -198,6 +198,7 @@ impl WidgetManager {
.cloned()
.unwrap_or(vec![]);
let styles = styles.unwrap_or(default_styles.clone());
if matches!(styles.render_command.resolve(), RenderCommand::Empty) {
continue;
}
......
......@@ -4,5 +4,10 @@ version = "0.1.0"
edition = "2021"
resolver = "2"
[features]
default = []
bevy_renderer = ["bevy", "kayak_ui/bevy_renderer"]
[dependencies]
kayak_ui = { path = "../", version = "0.1.0" }
bevy = { git = "https://github.com/StarArawn/bevy", rev = "bcca341d696c66d0173d8b0ac7a1b23b4b9e775c", optional = true }
use kayak_ui::bevy::WindowSize;
use kayak_ui::core::derivative::*;
use kayak_ui::core::{rsx, widget, Children};
use kayak_ui::core::{
render_command::RenderCommand,
rsx,
styles::{Style, StyleProp, Units},
widget, Binding, Bound, Children,
};
use crate::Clip;
#[widget]
pub fn App(children: Children) {
*styles = Some(Style {
render_command: StyleProp::Value(RenderCommand::Window),
..styles.clone().unwrap_or_default()
});
#[cfg(feature = "bevy_renderer")]
{
let window_size = if let Ok(world) = context.get_global_state::<bevy::prelude::World>() {
if let Some(window_size) = world.get_resource::<Binding<WindowSize>>() {
window_size.clone()
} else {
return;
}
} else {
return;
};
context.bind(&window_size);
let window_size = window_size.get();
*styles = Some(Style {
width: StyleProp::Value(Units::Pixels(window_size.0)),
height: StyleProp::Value(Units::Pixels(window_size.1)),
..styles.clone().unwrap_or_default()
});
}
rsx! {
<Clip>
{children}
......
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