From 927337c86d8a6761a138a811772e83ff4bd3ca4d Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Tue, 21 Nov 2023 14:08:22 +0100 Subject: [PATCH] wip ui --- Cargo.lock | 21 +++++ Cargo.toml | 52 ++++++------ kubi-ui/Cargo.toml | 16 ++++ kubi-ui/src/backend.rs | 2 + kubi-ui/src/backend/glium.rs | 0 kubi-ui/src/draw.rs | 22 +++++ kubi-ui/src/element.rs | 21 +++++ kubi-ui/src/element/layout_box.rs | 29 +++++++ kubi-ui/src/element/progress_bar.rs | 58 +++++++++++++ kubi-ui/src/event.rs | 10 +++ kubi-ui/src/lib.rs | 52 ++++++++++++ kubi-ui/src/measure.rs | 13 +++ kubi-ui/src/state.rs | 9 ++ kubi/Cargo.toml | 1 + kubi/src/gui_v2.rs | 92 --------------------- kubi/src/{gui.rs => legacy_gui.rs} | 0 kubi/src/{gui => legacy_gui}/progressbar.rs | 0 kubi/src/{gui => legacy_gui}/text_widget.rs | 0 kubi/src/lib.rs | 5 +- kubi/src/loading_screen.rs | 2 +- 20 files changed, 283 insertions(+), 122 deletions(-) create mode 100644 kubi-ui/Cargo.toml create mode 100644 kubi-ui/src/backend.rs create mode 100644 kubi-ui/src/backend/glium.rs create mode 100644 kubi-ui/src/draw.rs create mode 100644 kubi-ui/src/element.rs create mode 100644 kubi-ui/src/element/layout_box.rs create mode 100644 kubi-ui/src/element/progress_bar.rs create mode 100644 kubi-ui/src/event.rs create mode 100644 kubi-ui/src/lib.rs create mode 100644 kubi-ui/src/measure.rs create mode 100644 kubi-ui/src/state.rs delete mode 100644 kubi/src/gui_v2.rs rename kubi/src/{gui.rs => legacy_gui.rs} (100%) rename kubi/src/{gui => legacy_gui}/progressbar.rs (100%) rename kubi/src/{gui => legacy_gui}/text_widget.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 933fd6d..8e73072 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,6 +78,15 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -724,6 +733,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42218cb640844e3872cc3c153dc975229e080a6c4733b34709ef445610550226" dependencies = [ + "approx", "serde", ] @@ -972,6 +982,7 @@ dependencies = [ "image", "kubi-logging", "kubi-shared", + "kubi-ui", "log", "lz4_flex", "ndk", @@ -1043,6 +1054,16 @@ dependencies = [ "strum", ] +[[package]] +name = "kubi-ui" +version = "0.0.0" +dependencies = [ + "glam", + "glium", + "hashbrown 0.14.0", + "nohash-hasher", +] + [[package]] name = "lazy_static" version = "1.4.0" diff --git a/Cargo.toml b/Cargo.toml index a0ee902..0cf01a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,26 +1,26 @@ -[workspace] -members = ["kubi", "kubi-server", "kubi-shared", "kubi-logging", "kubi-pool"] -default-members = ["kubi"] -resolver = "2" - -[profile.release-with-debug] -inherits = "release" -debug = true - -[profile.dev] -opt-level = 1 - -[profile.dev.package."*"] -opt-level = 1 - -[profile.dev.package.uflow] -opt-level = 3 - -[profile.dev.package.glium] -opt-level = 3 - -[profile.dev.package.bracket-noise] -opt-level = 3 - -[profile.dev.package.rayon] -opt-level = 3 +[workspace] +members = ["kubi", "kubi-server", "kubi-shared", "kubi-logging", "kubi-pool", "kubi-ui"] +default-members = ["kubi"] +resolver = "2" + +[profile.release-with-debug] +inherits = "release" +debug = true + +[profile.dev] +opt-level = 1 + +[profile.dev.package."*"] +opt-level = 1 + +[profile.dev.package.uflow] +opt-level = 3 + +[profile.dev.package.glium] +opt-level = 3 + +[profile.dev.package.bracket-noise] +opt-level = 3 + +[profile.dev.package.rayon] +opt-level = 3 diff --git a/kubi-ui/Cargo.toml b/kubi-ui/Cargo.toml new file mode 100644 index 0000000..664c51f --- /dev/null +++ b/kubi-ui/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "kubi-ui" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +hashbrown = "0.14" +nohash-hasher = "0.2" +glam = { version = "0.24", features = ["approx"] } +glium = { git = "https://github.com/glium/glium", rev = "5d50e7", optional = true } + +[features] +default = ["backend_glium", "builtin_elements"] +backend_glium = ["dep:glium"] +builtin_elements = [] diff --git a/kubi-ui/src/backend.rs b/kubi-ui/src/backend.rs new file mode 100644 index 0000000..4271bfd --- /dev/null +++ b/kubi-ui/src/backend.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "backend_glium")] +pub mod glium; diff --git a/kubi-ui/src/backend/glium.rs b/kubi-ui/src/backend/glium.rs new file mode 100644 index 0000000..e69de29 diff --git a/kubi-ui/src/draw.rs b/kubi-ui/src/draw.rs new file mode 100644 index 0000000..d183ebe --- /dev/null +++ b/kubi-ui/src/draw.rs @@ -0,0 +1,22 @@ +use glam::{Vec2, vec2, Vec4}; + +#[derive(Clone, Copy, Debug)] +pub enum UiDrawCall { + ///Filled, colored rectangle + Rectangle { + ///Position in pixels + position: Vec2, + ///Size in pixels + size: Vec2, + ///Color (RGBA) + color: Vec4, + } +} + +pub struct UiDrawCalls { + pub calls: Vec, +} + +pub struct UiDrawPlan { + +} diff --git a/kubi-ui/src/element.rs b/kubi-ui/src/element.rs new file mode 100644 index 0000000..89625b5 --- /dev/null +++ b/kubi-ui/src/element.rs @@ -0,0 +1,21 @@ +use std::any::Any; +use crate::{ + LayoutInfo, + draw::UiDrawCall, + measure::{IsMeasurable, Response}, + state::StateRepo +}; + +#[cfg(feature = "builtin_elements")] pub mod progress_bar; +#[cfg(feature = "builtin_elements")] pub mod layout_box; + +pub trait UiElement { + fn name(&self) -> &'static str { "UiElement" } + fn state_id(&self) -> Option { None } + fn is_stateful(&self) -> bool { self.state_id().is_some() } + fn is_stateless(&self) -> bool { self.state_id().is_none() } + fn init_state(&self) -> Option> { None } + fn is_measurable(&self) -> IsMeasurable { IsMeasurable::No } + fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Option { None } + fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec) -> Response; +} diff --git a/kubi-ui/src/element/layout_box.rs b/kubi-ui/src/element/layout_box.rs new file mode 100644 index 0000000..9578ba3 --- /dev/null +++ b/kubi-ui/src/element/layout_box.rs @@ -0,0 +1,29 @@ +use std::any::Any; +use crate::{UiDirection, LayoutInfo, draw::UiDrawCall, measure::{IsMeasurable, Response}, state::StateRepo}; +use super::UiElement; + +pub struct LayoutBox { + pub direction: UiDirection, + pub gap: f32, + pub elements: Vec>, +} + +impl UiElement for LayoutBox { + fn is_measurable(&self) -> IsMeasurable { + IsMeasurable::Maybe + } + + fn measure(&self, state: StateRepo, layout: &LayoutInfo) -> Option { + for element in &self.elements { + if element.is_measurable() == IsMeasurable::No { + return None + } + element.measure(None, layout); + } + todo!() + } + + fn process(&self, _state: Option<&mut Box>, layout: &LayoutInfo, draw: &mut Vec) -> Response { + todo!() + } +} diff --git a/kubi-ui/src/element/progress_bar.rs b/kubi-ui/src/element/progress_bar.rs new file mode 100644 index 0000000..7b1ee13 --- /dev/null +++ b/kubi-ui/src/element/progress_bar.rs @@ -0,0 +1,58 @@ +use glam::{vec2, Vec2, Vec4}; +use crate::{ + UiSize, LayoutInfo, + draw::UiDrawCall, + measure::{Response, IsMeasurable}, + state::StateRepo +}; +use super::UiElement; + +struct ProgressBar { + size: (UiSize, UiSize), + value: f32, + color_foreground: Vec4, + color_background: Vec4, +} + +const BAR_HEIGHT: f32 = 20.0; + +impl UiElement for ProgressBar { + fn name(&self) -> &'static str { "Progress bar" } + + fn is_measurable(&self) -> IsMeasurable { IsMeasurable::Yes } + + fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Option { + Some(Response { + size: Vec2::new( + match self.size.0 { + UiSize::Auto => layout.max_size.x, + UiSize::Percentage(p) => layout.max_size.x * p, + UiSize::Pixels(p) => p, + }, + match self.size.1 { + UiSize::Auto => BAR_HEIGHT, + UiSize::Percentage(p) => layout.max_size.y * p, + UiSize::Pixels(p) => p, + } + ) + }) + } + + fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec) -> Response { + let measure = self.measure(&state, layout).unwrap(); + + draw.push(UiDrawCall::Rectangle { + position: layout.position, + size: measure.size, + color: self.color_background + }); + + draw.push(UiDrawCall::Rectangle { + position: layout.position, + size: measure.size * vec2(self.value, 1.0), + color: self.color_foreground + }); + + measure + } +} diff --git a/kubi-ui/src/event.rs b/kubi-ui/src/event.rs new file mode 100644 index 0000000..c488363 --- /dev/null +++ b/kubi-ui/src/event.rs @@ -0,0 +1,10 @@ +use glam::Vec2; + +pub enum UiEvent { + MouseMove(Vec2), + MouseDown(Vec2), + MouseUp(Vec2), + KeyDown(u32), + KeyUp(u32), + TextInput(char), +} diff --git a/kubi-ui/src/lib.rs b/kubi-ui/src/lib.rs new file mode 100644 index 0000000..bb27ad9 --- /dev/null +++ b/kubi-ui/src/lib.rs @@ -0,0 +1,52 @@ +use std::collections::VecDeque; +use glam::Vec2; + +pub mod element; +pub mod event; +pub mod draw; +pub mod backend; +pub mod measure; +pub mod state; + +use state::StateRepo; + +pub struct KubiUi { + mouse_position: Vec2, + stateful_state: StateRepo, + event_queue: VecDeque, +} + +impl KubiUi { + pub fn new() -> Self { + KubiUi { + mouse_position: Vec2::ZERO, + stateful_state: StateRepo::default(), + event_queue: VecDeque::new(), + } + } +} + +impl Default for KubiUi { + fn default() -> Self { + Self::new() + } +} + +pub enum UiSize { + Auto, + Percentage(f32), + Pixels(f32), +} + +#[derive(Default)] +pub enum UiDirection { + #[default] + Vertical, + Horizontal, +} + +struct LayoutInfo { + position: Vec2, + max_size: Vec2, + direction: UiDirection, +} diff --git a/kubi-ui/src/measure.rs b/kubi-ui/src/measure.rs new file mode 100644 index 0000000..130e9a9 --- /dev/null +++ b/kubi-ui/src/measure.rs @@ -0,0 +1,13 @@ +use glam::Vec2; + +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)] +pub enum IsMeasurable { + #[default] + No, + Maybe, + Yes +} + +pub struct Response { + pub size: Vec2 +} diff --git a/kubi-ui/src/state.rs b/kubi-ui/src/state.rs new file mode 100644 index 0000000..a24d671 --- /dev/null +++ b/kubi-ui/src/state.rs @@ -0,0 +1,9 @@ +use hashbrown::{HashMap, HashSet}; +use nohash_hasher::BuildNoHashHasher; +use std::any::Any; + +#[derive(Default)] +pub struct StateRepo { + state: HashMap, BuildNoHashHasher>, + active_ids: HashSet> +} diff --git a/kubi/Cargo.toml b/kubi/Cargo.toml index 5bc6738..93cc7be 100644 --- a/kubi/Cargo.toml +++ b/kubi/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["lib", "cdylib"] [dependencies] kubi-shared = { path = "../kubi-shared" } kubi-logging = { path = "../kubi-logging" } +kubi-ui = { path = "../kubi-ui" } log = "0.4" glium = { git = "https://github.com/glium/glium", rev = "5d50e7" } glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] } diff --git a/kubi/src/gui_v2.rs b/kubi/src/gui_v2.rs deleted file mode 100644 index f1df83e..0000000 --- a/kubi/src/gui_v2.rs +++ /dev/null @@ -1,92 +0,0 @@ -use glam::{Vec2, vec2, Vec4}; -use shipyard::Unique; - -pub enum UiSize { - Auto, - Percentage(f32), - Pixels(f32), -} - -struct LayoutInfo { - position: Vec2, - max_preferred_size: Vec2, -} - -struct Response { - size: Vec2 -} - -pub trait UiElement { - fn process(&self, layout: &LayoutInfo, draw: &mut Vec) -> Response; - fn measure(&self, layout: &LayoutInfo) -> Option { None } -} - -pub enum LayoutDirection { - Horizontal, - Vertical -} - -pub struct LayoutBox { - pub direction: LayoutDirection, - pub gap: f32, - pub elements: Vec>, -} - -struct ProgressBar { - size: (UiSize, UiSize), - value: f32, - color_foreground: Vec4, - color_background: Vec4, -} - -const BAR_HEIGHT: f32 = 20.0; - -impl UiElement for ProgressBar { - fn measure(&self, layout: &LayoutInfo) -> Option { - let width = match self.size.0 { - UiSize::Auto => layout.max_preferred_size.x, - UiSize::Percentage(p) => layout.max_preferred_size.x * p, - UiSize::Pixels(p) => p, - }; - let height = match self.size.1 { - UiSize::Auto => BAR_HEIGHT, - UiSize::Percentage(p) => layout.max_preferred_size.y * p, - UiSize::Pixels(p) => p, - }; - let size = Vec2::new(width, height); - Some(Response { size }) - } - - fn process(&self, layout: &LayoutInfo, draw: &mut Vec) -> Response { - let measure = self.measure(layout).unwrap(); - - draw.push(UiDrawCall::Rectangle { - position: layout.position, - size: measure.size, - color: self.color_background - }); - draw.push(UiDrawCall::Rectangle { - position: layout.position, - size: measure.size * vec2(self.value, 1.0), - color: self.color_foreground - }); - - measure - } -} - -enum UiDrawCall { - Rectangle { - ///Position in pixels - position: Vec2, - ///Size in pixels - size: Vec2, - ///Color (RGBA) - color: Vec4, - } -} - -#[derive(Unique)] -struct UiDrawCalls { - pub calls: Vec, -} diff --git a/kubi/src/gui.rs b/kubi/src/legacy_gui.rs similarity index 100% rename from kubi/src/gui.rs rename to kubi/src/legacy_gui.rs diff --git a/kubi/src/gui/progressbar.rs b/kubi/src/legacy_gui/progressbar.rs similarity index 100% rename from kubi/src/gui/progressbar.rs rename to kubi/src/legacy_gui/progressbar.rs diff --git a/kubi/src/gui/text_widget.rs b/kubi/src/legacy_gui/text_widget.rs similarity index 100% rename from kubi/src/gui/text_widget.rs rename to kubi/src/legacy_gui/text_widget.rs diff --git a/kubi/src/lib.rs b/kubi/src/lib.rs index 67cf8c1..152f51d 100644 --- a/kubi/src/lib.rs +++ b/kubi/src/lib.rs @@ -29,8 +29,7 @@ pub(crate) mod delta_time; pub(crate) mod cursor_lock; pub(crate) mod control_flow; pub(crate) mod state; -pub(crate) mod gui; -pub(crate) mod gui_v2; +pub(crate) mod legacy_gui; pub(crate) mod networking; pub(crate) mod init; pub(crate) mod color; @@ -77,7 +76,7 @@ use control_flow::{exit_on_esc, insert_control_flow_unique, SetControlFlow}; use state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state, is_connecting}; use networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit, is_singleplayer}; use init::initialize_from_args; -use gui::{render_gui, init_gui, update_gui}; +use legacy_gui::{render_gui, init_gui, update_gui}; use loading_screen::update_loading_screen; use connecting_screen::switch_to_loading_if_connected; use fixed_timestamp::init_fixed_timestamp_storage; diff --git a/kubi/src/loading_screen.rs b/kubi/src/loading_screen.rs index e3e3e99..91bbcdb 100644 --- a/kubi/src/loading_screen.rs +++ b/kubi/src/loading_screen.rs @@ -5,7 +5,7 @@ use crate::{ world::ChunkStorage, state::{GameState, NextState, is_changing_state}, transform::Transform2d, - gui::{ + legacy_gui::{ GuiComponent, progressbar::ProgressbarComponent },