diff --git a/kubi-ui/shaders/vertex.vert b/kubi-ui/shaders/vertex.vert index 9a1fb4e..cd61047 100644 --- a/kubi-ui/shaders/vertex.vert +++ b/kubi-ui/shaders/vertex.vert @@ -2,7 +2,8 @@ precision highp float; in vec2 position; +uniform vec2 resolution; void main() { - gl_Position = vec4(position, 0., 1.); + gl_Position = vec4(vec2(1., -1.) * (position / resolution), 0., 1.); } diff --git a/kubi-ui/src/backend/glium.rs b/kubi-ui/src/backend/glium.rs index ce92d1b..421b5dd 100644 --- a/kubi-ui/src/backend/glium.rs +++ b/kubi-ui/src/backend/glium.rs @@ -9,8 +9,8 @@ use glium::{ use crate::draw::{UiDrawPlan, UiVertex}; -const VERTEX_SHADER: &str = include_str!("../../shaders/fragment.frag"); -const FRAGMENT_SHADER: &str = include_str!("../../shaders/vertex.vert"); +const VERTEX_SHADER: &str = include_str!("../../shaders/vertex.vert"); +const FRAGMENT_SHADER: &str = include_str!("../../shaders/fragment.frag"); #[derive(Clone, Copy)] struct Vertex { @@ -50,10 +50,38 @@ impl GliumUiRenderer { } } - pub fn draw(&mut self, frame: &mut glium::Frame, resolution: Vec2, plan: &UiDrawPlan) { - self.vertex_buffer.write(&plan.vertices.iter().copied().map(Vertex::from).collect::>()); - self.index_buffer.write(&plan.indices); + fn ensure_buffer_size(&mut self, need_vtx: usize, need_idx: usize) { + let current_vtx_size = self.vertex_buffer.get_size(); + let current_idx_size = self.index_buffer.get_size(); + if current_vtx_size >= need_vtx && current_idx_size >= need_idx { + return + } + let new_vtx_size = (need_vtx + 1).next_power_of_two(); + let new_idx_size = (need_idx + 1).next_power_of_two(); + log::debug!("resizing buffers: vtx {} -> {}, idx {} -> {}", current_vtx_size, new_vtx_size, current_idx_size, new_idx_size); + if current_vtx_size != new_vtx_size { + self.vertex_buffer = VertexBuffer::empty_persistent(self.vertex_buffer.get_context(), new_vtx_size).unwrap(); + } + if current_idx_size != new_idx_size { + self.index_buffer = IndexBuffer::empty_persistent(self.index_buffer.get_context(), PrimitiveType::TrianglesList, new_idx_size).unwrap(); + } + } + fn write_buffer_data(&mut self, vtx: &[Vertex], idx: &[u32]) { + self.ensure_buffer_size(vtx.len(), idx.len()); + self.vertex_buffer.invalidate(); + self.vertex_buffer.slice_mut(0..vtx.len()).unwrap().write(vtx); + self.index_buffer.invalidate(); + self.index_buffer.slice_mut(0..idx.len()).unwrap().write(idx); + } + + pub fn update(&mut self, plan: &UiDrawPlan) { + let data_vtx = &plan.vertices.iter().copied().map(Vertex::from).collect::>(); + let data_idx = &plan.indices; + self.write_buffer_data(data_vtx, data_idx); + } + + pub fn draw(&self, frame: &mut glium::Frame, resolution: Vec2) { let params = DrawParameters { blend: Blend::alpha_blending(), ..Default::default() diff --git a/kubi/src/gui_integration.rs b/kubi/src/gui_integration.rs deleted file mode 100644 index e69de29..0000000 diff --git a/kubi/src/guiv2_integration.rs b/kubi/src/guiv2_integration.rs new file mode 100644 index 0000000..562d892 --- /dev/null +++ b/kubi/src/guiv2_integration.rs @@ -0,0 +1,45 @@ +use kubi_ui::{KubiUi, backend::glium::GliumUiRenderer}; +use shipyard::{AllStoragesView, Unique, UniqueView, NonSendSync, UniqueViewMut}; +use crate::rendering::{Renderer, RenderTarget, WindowSize}; + +#[derive(Unique)] +pub struct UiState { + pub ui: KubiUi, + pub renderer: GliumUiRenderer, +} + +pub fn kubi_ui_init( + storages: AllStoragesView +) { + let renderer = storages.borrow::>>().unwrap(); + storages.add_unique_non_send_sync(UiState { + ui: KubiUi::new(), + renderer: GliumUiRenderer::new(&renderer.display) + }); +} + +pub fn kubi_ui_begin( + mut ui: NonSendSync> +) { + ui.ui.begin(); +} + +pub fn kubi_ui_end( + mut ui: NonSendSync> +) { + let ui: &mut UiState = &mut ui; + let UiState { ui, renderer } = ui; + ui.end(); + let (upload_needed, plan) = ui.draw_plan(); + if upload_needed { + renderer.update(plan); + } +} + +pub fn kubi_ui_draw( + ui: NonSendSync>, + mut target: NonSendSync>, + size: UniqueView +) { + ui.renderer.draw(&mut target.0, size.0.as_vec2()); +} diff --git a/kubi/src/legacy_gui.rs b/kubi/src/legacy_gui.rs index 3a57db1..29561c5 100644 --- a/kubi/src/legacy_gui.rs +++ b/kubi/src/legacy_gui.rs @@ -9,29 +9,29 @@ use progressbar::render_progressbars; //TODO compute gui scale on window resize #[derive(Unique, Clone, Copy, Debug, Default)] -pub struct GuiView(pub Mat4); +pub struct LegacyGuiView(pub Mat4); #[derive(Component, Clone, Copy, Debug, Default)] -pub struct GuiComponent; +pub struct LegacyGuiComponent; #[derive(Component, Clone, Copy, Debug)] -pub struct PrimaryColor(pub Vec4); -impl Default for PrimaryColor { +pub struct LegacyPrimaryColor(pub Vec4); +impl Default for LegacyPrimaryColor { fn default() -> Self { Self(color_hex(0x156cddff)) } } #[derive(Component, Clone, Copy, Debug)] -pub struct SecondaryColor(pub Vec4); -impl Default for SecondaryColor { +pub struct LegacySecondaryColor(pub Vec4); +impl Default for LegacySecondaryColor { fn default() -> Self { Self(color_hex(0xc9d5e4ff)) } } -fn update_gui_view( - mut view: UniqueViewMut, +fn update_legacy_gui_view( + mut view: UniqueViewMut, resize: View, ) { let Some(&size) = resize.iter().next() else { @@ -41,19 +41,19 @@ fn update_gui_view( view.0 = Mat4::orthographic_rh_gl(0.0, w as f32, h as f32, 0.0, -1.0, 1.0); } -pub fn init_gui( +pub fn legacy_ui_init( storages: AllStoragesView ) { - storages.add_unique(GuiView::default()); + storages.add_unique(LegacyGuiView::default()); } -pub fn update_gui() -> Workload { +pub fn legacy_ui_update() -> Workload { ( - update_gui_view + update_legacy_gui_view ).into_sequential_workload() } -pub fn render_gui() -> Workload { +pub fn legacy_ui_render() -> Workload { ( render_progressbars ).into_sequential_workload() diff --git a/kubi/src/legacy_gui/progressbar.rs b/kubi/src/legacy_gui/progressbar.rs index b5f59d1..c88f80f 100644 --- a/kubi/src/legacy_gui/progressbar.rs +++ b/kubi/src/legacy_gui/progressbar.rs @@ -8,7 +8,7 @@ use crate::{ }, transform::Transform2d, }; -use super::{GuiComponent, PrimaryColor, SecondaryColor, GuiView}; +use super::{LegacyGuiComponent, LegacyPrimaryColor, LegacySecondaryColor, LegacyGuiView}; #[derive(Component, Debug, Clone, Copy, Default)] pub struct ProgressbarComponent { @@ -19,12 +19,12 @@ pub fn render_progressbars( mut target: NonSendSync>, rect: NonSendSync>, program: NonSendSync>, - view: UniqueView, - components: View, + view: UniqueView, + components: View, transforms: View, progressbars: View, - primary: View, - secondary: View, + primary: View, + secondary: View, ) { for (eid, (_, transform, progress)) in (&components, &transforms, &progressbars).iter().with_id() { let primary_color = primary.get(eid).copied().unwrap_or_default(); diff --git a/kubi/src/lib.rs b/kubi/src/lib.rs index 383ee25..7189640 100644 --- a/kubi/src/lib.rs +++ b/kubi/src/lib.rs @@ -30,6 +30,7 @@ pub(crate) mod cursor_lock; pub(crate) mod control_flow; pub(crate) mod state; pub(crate) mod legacy_gui; +pub(crate) mod guiv2_integration; pub(crate) mod networking; pub(crate) mod init; pub(crate) mod color; @@ -43,7 +44,7 @@ use world::{ loading::update_loaded_world_around_player, raycast::update_raycasts, queue::apply_queued_blocks, - tasks::{ChunkTaskManager}, + tasks::ChunkTaskManager, }; use player::{spawn_player, MainPlayer}; use prefabs::load_prefabs; @@ -76,7 +77,8 @@ use control_flow::{exit_on_esc, insert_control_flow_unique, RequestExit}; 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 legacy_gui::{render_gui, init_gui, update_gui}; +use legacy_gui::{legacy_ui_render, legacy_ui_init, legacy_ui_update}; +use guiv2_integration::{kubi_ui_init, kubi_ui_begin, kubi_ui_end, kubi_ui_draw}; use loading_screen::update_loading_screen; use connecting_screen::switch_to_loading_if_connected; use fixed_timestamp::init_fixed_timestamp_storage; @@ -94,6 +96,7 @@ fn startup() -> Workload { init_fixed_timestamp_storage, initial_resize_event, init_window_size, + kubi_ui_init, load_prefabs, init_primitives, insert_lock_state, @@ -101,7 +104,7 @@ fn startup() -> Workload { initialize_from_args, lock_cursor_now, init_input, - init_gui, + legacy_ui_init, insert_control_flow_unique, init_delta_time, ).into_sequential_workload() @@ -112,6 +115,7 @@ fn update() -> Workload { update_window_size, update_cursor_lock_state, process_inputs, + kubi_ui_begin, ( init_game_world.run_if_missing_unique::(), ( @@ -137,7 +141,8 @@ fn update() -> Workload { ).into_sequential_workload().run_if(is_ingame), update_networking_late.run_if(is_multiplayer), compute_cameras, - update_gui, + legacy_ui_update, + kubi_ui_end, update_state, exit_on_esc, disconnect_on_exit.run_if(is_multiplayer), @@ -153,7 +158,7 @@ fn render() -> Workload { render_selection_box, render_entities, ).into_sequential_workload().run_if(is_ingame), - render_gui, + legacy_ui_render, ).into_sequential_workload() } diff --git a/kubi/src/loading_screen.rs b/kubi/src/loading_screen.rs index 2cecc58..6da4029 100644 --- a/kubi/src/loading_screen.rs +++ b/kubi/src/loading_screen.rs @@ -6,7 +6,7 @@ use crate::{ state::{GameState, NextState, is_changing_state}, transform::Transform2d, legacy_gui::{ - GuiComponent, + LegacyGuiComponent, progressbar::ProgressbarComponent }, rendering::{WindowSize, if_resized}, @@ -21,7 +21,7 @@ fn spawn_loading_screen( ) { let size = *storages.borrow::>().unwrap(); let entity = storages.add_entity(( - GuiComponent, + LegacyGuiComponent, Transform2d(Mat3::from_scale_angle_translation( vec2(size.0.x as f32, 16.), 0.,