Compare commits

...

20 commits

Author SHA1 Message Date
griffi-gh fe1427249b
Merge pull request #8 from griffi-gh/upgrade-deps0
Upgrade to latest `glium`/`glutin`/`winit`, use `android-activity` instead of `ndk_glue`
2023-11-21 22:41:32 +01:00
griffi-gh 6f982d4308 change settings 2023-11-21 22:40:57 +01:00
griffi-gh 3069c1c72f . 2023-11-21 19:39:21 +01:00
griffi-gh 5e62e1781d gitignore logs 2023-11-21 19:39:09 +01:00
griffi-gh f7210e4dec minor changes 2023-11-21 19:33:05 +01:00
griffi-gh 7dc33c2dce stuff 2023-11-21 19:23:48 +01:00
griffi-gh 517838e2ae copy over simple init clode 2023-11-21 18:26:39 +01:00
griffi-gh 5987484452 fix android event loop init 2023-11-21 18:06:34 +01:00
griffi-gh ae7cc718cf fix visibility 2023-11-21 17:51:10 +01:00
griffi-gh 06a49e1b93 wip fix android 2023-11-21 17:49:40 +01:00
griffi-gh bc36bb8ce2 fix mouse input 2023-11-21 17:30:04 +01:00
griffi-gh 612e46f454 reuse window creation code 2023-11-21 17:27:44 +01:00
griffi-gh c69ce9105c fix the rest of stuff
now i need to fix mouse buttons and add init code back
2023-11-21 17:24:37 +01:00
griffi-gh 363dcddeca fix some stuff 2023-11-21 17:19:52 +01:00
griffi-gh 2656f5af21 upgrade more stuff 2023-11-21 17:11:53 +01:00
griffi-gh 3388dd6491 get it to compile 2023-11-21 17:03:50 +01:00
griffi-gh dec20225cb undo 2023-11-21 16:46:18 +01:00
griffi-gh d50f4323b1 start fixing stuff 2023-11-21 16:45:51 +01:00
griffi-gh 014e0e7824 upgrade shipyard/glium 2023-11-21 16:45:41 +01:00
griffi-gh 5678b0c06f update ui system 2023-11-21 16:14:26 +01:00
26 changed files with 1256 additions and 987 deletions

3
.gitignore vendored
View file

@ -15,3 +15,6 @@ _src
_visualizer.json _visualizer.json
*.kubi *.kubi
/*_log*.txt
/*.log

1679
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@ publish = false
kubi-shared = { path = "../kubi-shared" } kubi-shared = { path = "../kubi-shared" }
kubi-logging = { path = "../kubi-logging" } kubi-logging = { path = "../kubi-logging" }
log = "0.4" log = "0.4"
shipyard = { git = "https://github.com/leudz/shipyard", rev = "0934b426eb9a8", default-features = false, features = ["std", "proc", "thread_local"] } shipyard = { git = "https://github.com/leudz/shipyard", rev = "8ef90ea6c4d1eb6c9cb0988f0d2f873f75044d49", default-features = false, features = ["std", "proc", "thread_local"] }
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
toml = "0.8" toml = "0.8"
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] } glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] }

View file

@ -6,7 +6,7 @@ publish = false
[dependencies] [dependencies]
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math", "serde"] } glam = { version = "0.24", features = ["debug-glam-assert", "fast-math", "serde"] }
shipyard = { git = "https://github.com/leudz/shipyard", rev = "0934b426eb9a8", default-features = false, features = ["std"] } shipyard = { git = "https://github.com/leudz/shipyard", rev = "8ef90ea6c4d1eb6c9cb0988f0d2f873f75044d49", default-features = false, features = ["std"] }
strum = { version = "0.25", features = ["derive"] } strum = { version = "0.25", features = ["derive"] }
num_enum = "0.7" num_enum = "0.7"
postcard = { version = "1.0", features = ["alloc"] } postcard = { version = "1.0", features = ["alloc"] }

View file

@ -8,7 +8,7 @@ publish = false
hashbrown = "0.14" hashbrown = "0.14"
nohash-hasher = "0.2" nohash-hasher = "0.2"
glam = { version = "0.24", features = ["approx"] } glam = { version = "0.24", features = ["approx"] }
glium = { git = "https://github.com/glium/glium", rev = "5d50e7", optional = true } glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf", optional = true }
[features] [features]
default = ["backend_glium", "builtin_elements"] default = ["backend_glium", "builtin_elements"]

View file

@ -2,12 +2,13 @@ use std::any::Any;
use crate::{ use crate::{
LayoutInfo, LayoutInfo,
draw::UiDrawCall, draw::UiDrawCall,
measure::{IsMeasurable, Response}, measure::Response,
state::StateRepo state::StateRepo
}; };
#[cfg(feature = "builtin_elements")] pub mod container;
#[cfg(feature = "builtin_elements")] pub mod spacer;
#[cfg(feature = "builtin_elements")] pub mod progress_bar; #[cfg(feature = "builtin_elements")] pub mod progress_bar;
#[cfg(feature = "builtin_elements")] pub mod layout_box;
pub trait UiElement { pub trait UiElement {
fn name(&self) -> &'static str { "UiElement" } fn name(&self) -> &'static str { "UiElement" }
@ -15,7 +16,6 @@ pub trait UiElement {
fn is_stateful(&self) -> bool { self.state_id().is_some() } fn is_stateful(&self) -> bool { self.state_id().is_some() }
fn is_stateless(&self) -> bool { self.state_id().is_none() } fn is_stateless(&self) -> bool { self.state_id().is_none() }
fn init_state(&self) -> Option<Box<dyn Any>> { None } fn init_state(&self) -> Option<Box<dyn Any>> { None }
fn is_measurable(&self) -> IsMeasurable { IsMeasurable::No } fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response;
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Option<Response> { None } fn draw(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>);
fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response;
} }

View file

@ -0,0 +1,87 @@
use glam::{Vec2, Vec4};
use crate::{UiDirection, LayoutInfo, draw::UiDrawCall, measure::{IsMeasurable, Response}, state::StateRepo, UiSize};
use super::UiElement;
#[derive(Default, Clone, Copy, Debug)]
pub struct ContainerBorders {
pub top: Option<(Vec4, f32)>,
pub bottom: Option<(Vec4, f32)>,
pub left: Option<(Vec4, f32)>,
pub right: Option<(Vec4, f32)>,
}
pub enum ContainerAlign {
Begin,
Center,
End,
}
pub struct Container {
pub min_size: (UiSize, UiSize),
pub max_size: (UiSize, UiSize),
pub direction: UiDirection,
pub gap: f32,
pub padding: f32,
pub align: (ContainerAlign, ContainerAlign),
pub background: Option<Vec4>,
pub borders: ContainerBorders,
pub clip: bool,
pub elements: Vec<Box<dyn UiElement>>,
}
impl Default for Container {
fn default() -> Self {
Self {
min_size: (UiSize::Auto, UiSize::Auto),
max_size: (UiSize::Auto, UiSize::Auto),
direction: UiDirection::Vertical,
gap: 0.,
padding: 0.,
align: (ContainerAlign::Center, ContainerAlign::Begin),
background: Default::default(),
borders: Default::default(),
clip: Default::default(),
elements: Vec::new(),
}
}
}
impl UiElement for Container {
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response {
let mut size = Vec2::ZERO;
let mut leftover_gap = Vec2::ZERO;
for element in &self.elements {
let measure = element.measure(state, &LayoutInfo {
position: layout.position + size,
max_size: layout.max_size - size,
direction: self.direction,
});
match self.direction {
UiDirection::Horizontal => {
size.x += measure.desired_size.x + self.gap;
size.y = size.y.max(measure.desired_size.y);
leftover_gap.x = self.gap;
},
UiDirection::Vertical => {
size.x = size.x.max(measure.desired_size.x);
size.y += measure.desired_size.y + self.gap;
leftover_gap.y = self.gap;
}
}
}
size -= leftover_gap;
Response { desired_size: size }
}
fn draw(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) {
if let Some(color) = self.background {
draw.push(UiDrawCall::Rectangle {
position: layout.position,
size: measure.desired_size,
color
});
//TODO draw borders
}
}
}

View file

@ -1,29 +0,0 @@
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<Box<dyn UiElement>>,
}
impl UiElement for LayoutBox {
fn is_measurable(&self) -> IsMeasurable {
IsMeasurable::Maybe
}
fn measure(&self, state: StateRepo, layout: &LayoutInfo) -> Option<Response> {
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<dyn Any>>, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response {
todo!()
}
}

View file

@ -1,8 +1,8 @@
use glam::{vec2, Vec2, Vec4}; use glam::{vec2, Vec4};
use crate::{ use crate::{
UiSize, LayoutInfo, UiSize, LayoutInfo,
draw::UiDrawCall, draw::UiDrawCall,
measure::{Response, IsMeasurable}, measure::Response,
state::StateRepo state::StateRepo
}; };
use super::UiElement; use super::UiElement;
@ -19,13 +19,11 @@ const BAR_HEIGHT: f32 = 20.0;
impl UiElement for ProgressBar { impl UiElement for ProgressBar {
fn name(&self) -> &'static str { "Progress bar" } fn name(&self) -> &'static str { "Progress bar" }
fn is_measurable(&self) -> IsMeasurable { IsMeasurable::Yes } fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Response {
Response {
fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Option<Response> { desired_size: vec2(
Some(Response {
size: Vec2::new(
match self.size.0 { match self.size.0 {
UiSize::Auto => layout.max_size.x, UiSize::Auto => layout.max_size.x.max(300.),
UiSize::Percentage(p) => layout.max_size.x * p, UiSize::Percentage(p) => layout.max_size.x * p,
UiSize::Pixels(p) => p, UiSize::Pixels(p) => p,
}, },
@ -35,24 +33,20 @@ impl UiElement for ProgressBar {
UiSize::Pixels(p) => p, UiSize::Pixels(p) => p,
} }
) )
}) }
} }
fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response { fn draw(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) {
let measure = self.measure(&state, layout).unwrap();
draw.push(UiDrawCall::Rectangle { draw.push(UiDrawCall::Rectangle {
position: layout.position, position: layout.position,
size: measure.size, size: measure.desired_size,
color: self.color_background color: self.color_background
}); });
draw.push(UiDrawCall::Rectangle { draw.push(UiDrawCall::Rectangle {
position: layout.position, position: layout.position,
size: measure.size * vec2(self.value, 1.0), size: measure.desired_size * vec2(self.value, 1.0),
color: self.color_foreground color: self.color_foreground
}); });
measure
} }
} }

View file

@ -0,0 +1,18 @@
use glam::vec2;
use crate::{state::StateRepo, LayoutInfo, measure::Response, draw::UiDrawCall, UiDirection};
use super::UiElement;
pub struct Spacer(f32);
impl UiElement for Spacer {
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response {
Response {
desired_size: match layout.direction {
UiDirection::Horizontal => vec2(self.0, 0.),
UiDirection::Vertical => vec2(0., self.0),
}
}
}
fn draw(&self, _measure: &Response, _state: &mut StateRepo, _layout: &LayoutInfo, _draw: &mut Vec<UiDrawCall>) {}
}

View file

@ -32,13 +32,15 @@ impl Default for KubiUi {
} }
} }
#[derive(Default)]
pub enum UiSize { pub enum UiSize {
#[default]
Auto, Auto,
Percentage(f32), Percentage(f32),
Pixels(f32), Pixels(f32),
} }
#[derive(Default)] #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum UiDirection { pub enum UiDirection {
#[default] #[default]
Vertical, Vertical,
@ -46,6 +48,7 @@ pub enum UiDirection {
} }
struct LayoutInfo { struct LayoutInfo {
///Not availabe during measuring step
position: Vec2, position: Vec2,
max_size: Vec2, max_size: Vec2,
direction: UiDirection, direction: UiDirection,

View file

@ -9,5 +9,5 @@ pub enum IsMeasurable {
} }
pub struct Response { pub struct Response {
pub size: Vec2 pub desired_size: Vec2
} }

View file

@ -13,14 +13,18 @@ kubi-shared = { path = "../kubi-shared" }
kubi-logging = { path = "../kubi-logging" } kubi-logging = { path = "../kubi-logging" }
kubi-ui = { path = "../kubi-ui" } kubi-ui = { path = "../kubi-ui" }
log = "0.4" log = "0.4"
glium = { git = "https://github.com/glium/glium", rev = "5d50e7" } glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf" }
glutin = "0.31"
winit = { version = "0.29", features = ["android-native-activity"] }
glutin-winit = "0.4"
raw-window-handle = "0.5"
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] } glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] }
image = { version = "0.24", default_features = false, features = ["png"] } image = { version = "0.24", default_features = false, features = ["png"] }
strum = { version = "0.25", features = ["derive"] } strum = { version = "0.25", features = ["derive"] }
hashbrown = "0.14" hashbrown = "0.14"
nohash-hasher = "0.2" nohash-hasher = "0.2"
rayon = "1.7" rayon = "1.7"
shipyard = { git = "https://github.com/leudz/shipyard", rev = "0934b426eb9a8", default-features = false, features = ["std", "proc", "thread_local"] } shipyard = { git = "https://github.com/leudz/shipyard", rev = "8ef90ea6c4d1eb6c9cb0988f0d2f873f75044d49", default-features = false, features = ["std", "proc", "thread_local"] }
anyhow = "1.0" anyhow = "1.0"
flume = "0.11" flume = "0.11"
gilrs = { version = "0.10", default_features = false, features = ["xinput"] } gilrs = { version = "0.10", default_features = false, features = ["xinput"] }
@ -32,8 +36,8 @@ tinyset = "0.4"
serde_json = { version = "1.0", optional = true } #only used for `generate_visualizer_data` serde_json = { version = "1.0", optional = true } #only used for `generate_visualizer_data`
[target.'cfg(target_os = "android")'.dependencies] [target.'cfg(target_os = "android")'.dependencies]
ndk = "0.7" android-activity = "0.5"
ndk-glue = "0.7" ndk = "0.8"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.3" winapi = "0.3"
@ -64,6 +68,14 @@ target_sdk_version = 30
required = true required = true
glEsVersion = 0x00030000 glEsVersion = 0x00030000
[[package.metadata.android.uses_feature]]
name = "android.hardware.touchscreen.multitouch"
required = true
[[package.metadata.android.uses_feature]]
name = "android.hardware.touchscreen.multitouch.distinct"
required = true
[package.metadata.android.application.activity] [package.metadata.android.application.activity]
config_changes = "orientation|keyboardHidden|screenLayout|screenSize" config_changes = "orientation|keyboardHidden|screenLayout|screenSize"
exported = true exported = true

View file

@ -1,5 +1,5 @@
use shipyard::{UniqueViewMut, UniqueView, View, IntoIter, ViewMut, EntitiesViewMut, Workload, IntoWorkload}; use shipyard::{UniqueViewMut, UniqueView, View, IntoIter, ViewMut, EntitiesViewMut, Workload, IntoWorkload};
use glium::glutin::event::VirtualKeyCode; use winit::keyboard::KeyCode;
use kubi_shared::{ use kubi_shared::{
block::Block, block::Block,
queue::QueuedBlock, queue::QueuedBlock,
@ -7,20 +7,26 @@ use kubi_shared::{
}; };
use crate::{ use crate::{
player::MainPlayer, player::MainPlayer,
world::{raycast::{LookingAtBlock, RAYCAST_STEP}, queue::BlockUpdateQueue}, world::{
raycast::{LookingAtBlock, RAYCAST_STEP},
queue::BlockUpdateQueue
},
input::{Inputs, PrevInputs, RawKbmInputState}, input::{Inputs, PrevInputs, RawKbmInputState},
events::{EventComponent, player_actions::PlayerActionEvent}, events::{
EventComponent,
player_actions::PlayerActionEvent
},
}; };
const BLOCK_KEY_MAP: &[(VirtualKeyCode, Block)] = &[ const BLOCK_KEY_MAP: &[(KeyCode, Block)] = &[
(VirtualKeyCode::Key1, Block::Cobblestone), (KeyCode::Digit1, Block::Cobblestone),
(VirtualKeyCode::Key2, Block::Planks), (KeyCode::Digit2, Block::Planks),
(VirtualKeyCode::Key3, Block::Dirt), (KeyCode::Digit3, Block::Dirt),
(VirtualKeyCode::Key4, Block::Grass), (KeyCode::Digit4, Block::Grass),
(VirtualKeyCode::Key5, Block::Sand), (KeyCode::Digit5, Block::Sand),
(VirtualKeyCode::Key6, Block::Stone), (KeyCode::Digit6, Block::Stone),
(VirtualKeyCode::Key7, Block::Torch), (KeyCode::Digit7, Block::Torch),
(VirtualKeyCode::Key8, Block::Leaf), (KeyCode::Digit8, Block::Leaf),
]; ];
fn pick_block_with_number_keys( fn pick_block_with_number_keys(

View file

@ -1,21 +1,21 @@
use shipyard::{UniqueView, UniqueViewMut, Unique, AllStoragesView}; use shipyard::{UniqueView, UniqueViewMut, Unique, AllStoragesView};
use glium::glutin::{event::VirtualKeyCode, event_loop::ControlFlow}; use winit::{keyboard::KeyCode, event_loop::ControlFlow};
use crate::input::RawKbmInputState; use crate::input::RawKbmInputState;
#[derive(Unique)] #[derive(Unique)]
pub struct SetControlFlow(pub Option<ControlFlow>); pub struct RequestExit(pub bool);
pub fn exit_on_esc( pub fn exit_on_esc(
raw_inputs: UniqueView<RawKbmInputState>, raw_inputs: UniqueView<RawKbmInputState>,
mut control_flow: UniqueViewMut<SetControlFlow> mut exit: UniqueViewMut<RequestExit>
) { ) {
if raw_inputs.keyboard_state.contains(VirtualKeyCode::Escape as u32) { if raw_inputs.keyboard_state.contains(KeyCode::Escape as u32) {
control_flow.0 = Some(ControlFlow::Exit); exit.0 = true;
} }
} }
pub fn insert_control_flow_unique( pub fn insert_control_flow_unique(
storages: AllStoragesView storages: AllStoragesView
) { ) {
storages.add_unique(SetControlFlow(None)) storages.add_unique(RequestExit(false))
} }

View file

@ -1,6 +1,6 @@
use shipyard::{AllStoragesView, Unique, NonSendSync, UniqueView, UniqueViewMut}; use shipyard::{AllStoragesView, Unique, NonSendSync, UniqueView, UniqueViewMut};
use crate::rendering::Renderer; use crate::rendering::Renderer;
use glium::glutin::window::CursorGrabMode; use winit::window::CursorGrabMode;
#[derive(Unique)] #[derive(Unique)]
pub struct CursorLock(pub bool); pub struct CursorLock(pub bool);
@ -13,8 +13,8 @@ pub fn update_cursor_lock_state(
return return
} }
if lock.is_inserted_or_modified() { if lock.is_inserted_or_modified() {
let gl_window = display.display.gl_window(); //TODO MIGRATION
let window = gl_window.window(); let window = &display.window;
window.set_cursor_grab(match lock.0 { window.set_cursor_grab(match lock.0 {
true => CursorGrabMode::Confined, true => CursorGrabMode::Confined,
false => CursorGrabMode::None, false => CursorGrabMode::None,

View file

@ -1,6 +1,6 @@
use glam::UVec2; use glam::UVec2;
use shipyard::{World, Component, AllStoragesViewMut, SparseSet, NonSendSync, UniqueView}; use shipyard::{World, Component, AllStoragesViewMut, SparseSet, NonSendSync, UniqueView};
use glium::glutin::event::{Event, DeviceEvent, DeviceId, WindowEvent, Touch}; use winit::event::{Event, DeviceEvent, DeviceId, WindowEvent, Touch, RawKeyEvent, TouchPhase};
use crate::rendering::Renderer; use crate::rendering::Renderer;
pub mod player_actions; pub mod player_actions;
@ -24,7 +24,7 @@ pub struct TouchEvent(pub Touch);
#[derive(Component, Clone, Copy, Debug, Default)] #[derive(Component, Clone, Copy, Debug, Default)]
pub struct WindowResizedEvent(pub UVec2); pub struct WindowResizedEvent(pub UVec2);
pub fn process_glutin_events(world: &mut World, event: &Event<'_, ()>) { pub fn process_glutin_events(world: &mut World, event: &Event<()>) {
#[allow(clippy::collapsible_match, clippy::single_match)] #[allow(clippy::collapsible_match, clippy::single_match)]
match event { match event {
Event::WindowEvent { window_id: _, event } => match event { Event::WindowEvent { window_id: _, event } => match event {
@ -36,17 +36,25 @@ pub fn process_glutin_events(world: &mut World, event: &Event<'_, ()>) {
}, },
#[cfg(not(feature = "raw-evt"))] #[cfg(not(feature = "raw-evt"))]
WindowEvent::KeyboardInput { device_id, input, is_synthetic } => { WindowEvent::KeyboardInput { device_id, event, .. } => {
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
InputDeviceEvent { InputDeviceEvent {
device_id: *device_id, device_id: *device_id,
event: DeviceEvent::Key(*input) event: DeviceEvent::Key(RawKeyEvent {
physical_key: event.physical_key,
state: event.state,
})
} }
)); ));
} }
WindowEvent::Touch(touch) => { WindowEvent::Touch(touch) => {
// if matches!(touch.phase, TouchPhase::Started | TouchPhase::Cancelled | TouchPhase::Ended) {
// println!("TOUCH ==================== {:#?}", touch);
// } else {
// println!("TOUCH MOVED {:?} {}", touch.phase, touch.id);
// }
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
TouchEvent(*touch) TouchEvent(*touch)
@ -67,7 +75,7 @@ pub fn process_glutin_events(world: &mut World, event: &Event<'_, ()>) {
)); ));
}, },
Event::LoopDestroyed => { Event::LoopExiting => {
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
OnBeforeExitEvent OnBeforeExitEvent

View file

@ -1,21 +1,29 @@
use std::{fs::File, path::Path, io::{Read, Seek}}; use std::{fs::File, path::Path, io::{Read, Seek}};
use anyhow::Result; use anyhow::Result;
use shipyard::{Unique, AllStoragesView};
pub trait ReadOnly: Read + Seek {} pub trait ReadOnly: Read + Seek {}
impl<T: Read + Seek> ReadOnly for T {} impl<T: Read + Seek> ReadOnly for T {}
pub fn open_asset(path: &Path) -> Result<Box<dyn ReadOnly>> { #[derive(Unique)]
#[cfg(target_os = "android")] { pub struct AssetManager {
use anyhow::Context; #[cfg(target_os = "android")]
use std::ffi::CString; pub(crate) app: android_activity::AndroidApp,
}
let asset_manager = ndk_glue::native_activity().asset_manager(); impl AssetManager {
let path_cstr = CString::new(path.to_string_lossy().as_bytes())?; pub fn open_asset(&self, path: &Path) -> Result<Box<dyn ReadOnly>> {
let handle = asset_manager.open(&path_cstr).context("Asset doesn't exist")?; #[cfg(target_os = "android")] {
Ok(Box::new(handle)) use anyhow::Context;
} use std::ffi::CString;
#[cfg(not(target_os = "android"))] { let asset_manager = self.app.asset_manager();
let asset_path = Path::new("./assets/").join(path); let path_cstr = CString::new(path.to_string_lossy().as_bytes())?;
Ok(Box::new(File::open(asset_path)?)) let handle = asset_manager.open(&path_cstr).context("Asset doesn't exist")?;
Ok(Box::new(handle))
}
#[cfg(not(target_os = "android"))] {
let asset_path = Path::new("./assets/").join(path);
Ok(Box::new(File::open(asset_path)?))
}
} }
} }

View file

@ -1,6 +1,9 @@
use gilrs::{Gilrs, GamepadId, Button, Event, Axis}; use gilrs::{Gilrs, GamepadId, Button, Event, Axis};
use glam::{Vec2, DVec2, vec2, dvec2}; use glam::{Vec2, DVec2, vec2, dvec2};
use glium::glutin::event::{DeviceEvent, DeviceId, VirtualKeyCode, ElementState, TouchPhase}; use winit::{
keyboard::{KeyCode, PhysicalKey},
event::{DeviceEvent, DeviceId, ElementState, TouchPhase}
};
use hashbrown::HashMap; use hashbrown::HashMap;
use tinyset::{SetU32, SetU64}; use tinyset::{SetU32, SetU64};
use nohash_hasher::BuildNoHashHasher; use nohash_hasher::BuildNoHashHasher;
@ -94,21 +97,21 @@ fn process_events(
) { ) {
input_state.mouse_delta = DVec2::ZERO; input_state.mouse_delta = DVec2::ZERO;
for event in device_events.iter() { for event in device_events.iter() {
match event.event { match &event.event {
DeviceEvent::MouseMotion { delta } => { DeviceEvent::MouseMotion { delta } => {
input_state.mouse_delta = DVec2::from(delta); input_state.mouse_delta = DVec2::from(*delta);
}, },
DeviceEvent::Key(input) => { DeviceEvent::Key(input) => {
if let Some(keycode) = input.virtual_keycode { if let PhysicalKey::Code(code) = input.physical_key {
match input.state { match input.state {
ElementState::Pressed => input_state.keyboard_state.insert(keycode as u32), ElementState::Pressed => input_state.keyboard_state.insert(code as u32),
ElementState::Released => input_state.keyboard_state.remove(keycode as u32), ElementState::Released => input_state.keyboard_state.remove(code as u32),
}; };
} }
}, },
DeviceEvent::Button { button, state } => { DeviceEvent::Button { button, state } => {
if button < 32 { if *button < 32 {
input_state.button_state[button as usize] = matches!(state, ElementState::Pressed); input_state.button_state[*button as usize] = matches!(*state, ElementState::Pressed);
} }
}, },
_ => () _ => ()
@ -127,6 +130,7 @@ fn process_touch_events(
let position = dvec2(event.0.location.x, event.0.location.y); let position = dvec2(event.0.location.x, event.0.location.y);
match event.0.phase { match event.0.phase {
TouchPhase::Started => { TouchPhase::Started => {
//println!("touch started: finger {}", event.0.id);
touch_state.fingers.insert(event.0.id, Finger { touch_state.fingers.insert(event.0.id, Finger {
id: event.0.id, id: event.0.id,
device_id: event.0.device_id, device_id: event.0.device_id,
@ -143,6 +147,7 @@ fn process_touch_events(
} }
}, },
TouchPhase::Ended | TouchPhase::Cancelled => { TouchPhase::Ended | TouchPhase::Cancelled => {
//println!("touch ended: finger {}", event.0.id);
touch_state.fingers.remove(&event.0.id); touch_state.fingers.remove(&event.0.id);
}, },
} }
@ -173,14 +178,14 @@ fn update_input_state (
mut inputs: UniqueViewMut<Inputs>, mut inputs: UniqueViewMut<Inputs>,
) { ) {
inputs.movement += Vec2::new( inputs.movement += Vec2::new(
raw_inputs.keyboard_state.contains(VirtualKeyCode::D as u32) as u32 as f32 - raw_inputs.keyboard_state.contains(KeyCode::KeyD as u32) as u32 as f32 -
raw_inputs.keyboard_state.contains(VirtualKeyCode::A as u32) as u32 as f32, raw_inputs.keyboard_state.contains(KeyCode::KeyA as u32) as u32 as f32,
raw_inputs.keyboard_state.contains(VirtualKeyCode::W as u32) as u32 as f32 - raw_inputs.keyboard_state.contains(KeyCode::KeyW as u32) as u32 as f32 -
raw_inputs.keyboard_state.contains(VirtualKeyCode::S as u32) as u32 as f32 raw_inputs.keyboard_state.contains(KeyCode::KeyS as u32) as u32 as f32
); );
inputs.look += raw_inputs.mouse_delta.as_vec2(); inputs.look += raw_inputs.mouse_delta.as_vec2();
inputs.action_a |= raw_inputs.button_state[1]; inputs.action_a |= raw_inputs.button_state[0];
inputs.action_b |= raw_inputs.button_state[3]; inputs.action_b |= raw_inputs.button_state[1];
} }
fn update_input_state_gamepad ( fn update_input_state_gamepad (

View file

@ -6,7 +6,7 @@ use shipyard::{
NonSendSync, WorkloadModificator, NonSendSync, WorkloadModificator,
SystemModificator SystemModificator
}; };
use glium::glutin::{ use winit::{
event_loop::{EventLoop, ControlFlow}, event_loop::{EventLoop, ControlFlow},
event::{Event, WindowEvent} event::{Event, WindowEvent}
}; };
@ -72,7 +72,7 @@ use rendering::{
use block_placement::update_block_placement; use block_placement::update_block_placement;
use delta_time::{DeltaTime, init_delta_time}; use delta_time::{DeltaTime, init_delta_time};
use cursor_lock::{insert_lock_state, update_cursor_lock_state, lock_cursor_now}; use cursor_lock::{insert_lock_state, update_cursor_lock_state, lock_cursor_now};
use control_flow::{exit_on_esc, insert_control_flow_unique, SetControlFlow}; 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 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 networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit, is_singleplayer};
use init::initialize_from_args; use init::initialize_from_args;
@ -80,6 +80,7 @@ use legacy_gui::{render_gui, init_gui, update_gui};
use loading_screen::update_loading_screen; use loading_screen::update_loading_screen;
use connecting_screen::switch_to_loading_if_connected; use connecting_screen::switch_to_loading_if_connected;
use fixed_timestamp::init_fixed_timestamp_storage; use fixed_timestamp::init_fixed_timestamp_storage;
use filesystem::AssetManager;
/// stuff required to init the renderer and other basic systems /// stuff required to init the renderer and other basic systems
fn pre_startup() -> Workload { fn pre_startup() -> Workload {
@ -169,8 +170,15 @@ fn attach_console() {
} }
#[no_mangle] #[no_mangle]
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))] #[cfg(target_os = "android")]
pub fn kubi_main() { pub fn android_main(app: android_activity::AndroidApp) {
use android_activity::WindowManagerFlags;
app.set_window_flags(WindowManagerFlags::FULLSCREEN, WindowManagerFlags::empty());
kubi_main(app)
}
#[no_mangle]
pub fn kubi_main(#[cfg(target_os = "android")] app: android_activity::AndroidApp) {
//Attach console on release builds on windows //Attach console on release builds on windows
#[cfg(all(windows, not(debug_assertions)))] attach_console(); #[cfg(all(windows, not(debug_assertions)))] attach_console();
@ -183,6 +191,12 @@ pub fn kubi_main() {
//Create a shipyard world //Create a shipyard world
let mut world = World::new(); let mut world = World::new();
//Init assman
world.add_unique(AssetManager {
#[cfg(target_os = "android")]
app: app.clone()
});
//Register workloads //Register workloads
world.add_workload(pre_startup); world.add_workload(pre_startup);
world.add_workload(startup); world.add_workload(startup);
@ -190,19 +204,6 @@ pub fn kubi_main() {
world.add_workload(render); world.add_workload(render);
world.add_workload(after_frame_end); world.add_workload(after_frame_end);
//Run pre-startup procedure
world.run_workload(pre_startup).unwrap();
//Create event loop
let event_loop = EventLoop::new();
//Initialize renderer
{
let settings = world.borrow::<UniqueView<GameSettings>>().unwrap();
world.add_unique_non_send_sync(Renderer::init(&event_loop, &settings));
}
world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.)));
//Save _visualizer.json //Save _visualizer.json
#[cfg(feature = "generate_visualizer_data")] #[cfg(feature = "generate_visualizer_data")]
std::fs::write( std::fs::write(
@ -210,24 +211,65 @@ pub fn kubi_main() {
serde_json::to_string(&world.workloads_info()).unwrap(), serde_json::to_string(&world.workloads_info()).unwrap(),
).unwrap(); ).unwrap();
//Run startup systems //Run pre-startup procedure
world.run_workload(startup).unwrap(); world.run_workload(pre_startup).unwrap();
//Create event loop
let event_loop ={
#[cfg(not(target_os = "android"))] { EventLoop::new().unwrap() }
#[cfg(target_os = "android")] {
use winit::{
platform::android::EventLoopBuilderExtAndroid,
event_loop::EventLoopBuilder
};
EventLoopBuilder::new().with_android_app(app).build().unwrap()
}
};
//Run the event loop //Run the event loop
let mut last_update = Instant::now(); let mut last_update = Instant::now();
event_loop.run(move |event, _, control_flow| { let mut ready = false;
*control_flow = ControlFlow::Poll; event_loop.run(move |event, window_target| {
//Wait for the window to become active (required for android)
if !ready {
if Event::Resumed != event {
window_target.set_control_flow(ControlFlow::Wait);
return
}
//Initialize renderer
{
let settings = world.borrow::<UniqueView<GameSettings>>().unwrap();
world.add_unique_non_send_sync(Renderer::init(window_target, &settings));
}
world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.)));
//Run startup systems
world.run_workload(startup).unwrap();
ready = true;
}
window_target.set_control_flow(ControlFlow::Poll);
process_glutin_events(&mut world, &event); process_glutin_events(&mut world, &event);
#[allow(clippy::collapsible_match, clippy::single_match)] #[allow(clippy::collapsible_match, clippy::single_match)]
match event { match event {
#[cfg(target_os = "android")]
Event::Suspended => {
window_target.exit();
}
Event::WindowEvent { event, .. } => match event { Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
log::info!("exit requested"); log::info!("exit requested");
*control_flow = ControlFlow::Exit; window_target.exit();
}, },
_ => (), _ => (),
}, },
Event::MainEventsCleared => {
Event::AboutToWait => {
//Update delta time (maybe move this into a system?) //Update delta time (maybe move this into a system?)
{ {
let mut dt_view = world.borrow::<UniqueViewMut<DeltaTime>>().unwrap(); let mut dt_view = world.borrow::<UniqueViewMut<DeltaTime>>().unwrap();
@ -257,11 +299,11 @@ pub fn kubi_main() {
world.run_workload(after_frame_end).unwrap(); world.run_workload(after_frame_end).unwrap();
//Process control flow changes //Process control flow changes
if let Some(flow) = world.borrow::<UniqueView<SetControlFlow>>().unwrap().0 { if world.borrow::<UniqueView<RequestExit>>().unwrap().0 {
*control_flow = flow; window_target.exit();
} }
}, },
_ => (), _ => (),
}; };
}); }).unwrap();
} }

View file

@ -1,5 +1,5 @@
use shipyard::{UniqueView, UniqueViewMut, Workload, IntoWorkload, EntityId, Unique, AllStoragesViewMut, ViewMut, Get, SystemModificator, track}; use shipyard::{UniqueView, UniqueViewMut, Workload, IntoWorkload, EntityId, Unique, AllStoragesViewMut, ViewMut, Get, SystemModificator, track};
use glium::glutin::event::VirtualKeyCode; use winit::keyboard::KeyCode;
use glam::{Mat3, vec2}; use glam::{Mat3, vec2};
use crate::{ use crate::{
world::ChunkStorage, world::ChunkStorage,
@ -76,7 +76,7 @@ fn override_loading(
kbm_state: UniqueView<RawKbmInputState>, kbm_state: UniqueView<RawKbmInputState>,
mut state: UniqueViewMut<NextState> mut state: UniqueViewMut<NextState>
) { ) {
if kbm_state.keyboard_state.contains(VirtualKeyCode::F as u32) { if kbm_state.keyboard_state.contains(KeyCode::KeyF as u32) {
state.0 = Some(GameState::InGame); state.0 = Some(GameState::InGame);
} }
} }

View file

@ -1,5 +1,5 @@
use shipyard::{Unique, AllStoragesView, UniqueView, UniqueViewMut, Workload, IntoWorkload, EntitiesViewMut, Component, ViewMut, SystemModificator, View, IntoIter, WorkloadModificator}; use shipyard::{Unique, AllStoragesView, UniqueView, UniqueViewMut, Workload, IntoWorkload, EntitiesViewMut, Component, ViewMut, SystemModificator, View, IntoIter, WorkloadModificator};
use glium::glutin::event_loop::ControlFlow; use winit::event_loop::ControlFlow;
use std::net::SocketAddr; use std::net::SocketAddr;
use uflow::{ use uflow::{
client::{Client, Config as ClientConfig, Event as ClientEvent}, client::{Client, Config as ClientConfig, Event as ClientEvent},
@ -12,7 +12,7 @@ use kubi_shared::networking::{
}; };
use crate::{ use crate::{
events::EventComponent, events::EventComponent,
control_flow::SetControlFlow, control_flow::RequestExit,
world::tasks::ChunkTaskManager, world::tasks::ChunkTaskManager,
state::is_ingame_or_loading, state::is_ingame_or_loading,
fixed_timestamp::FixedTimestamp fixed_timestamp::FixedTimestamp
@ -155,10 +155,11 @@ pub fn update_networking_late() -> Workload {
} }
pub fn disconnect_on_exit( pub fn disconnect_on_exit(
control_flow: UniqueView<SetControlFlow>, exit: UniqueView<RequestExit>,
mut client: UniqueViewMut<UdpClient>, mut client: UniqueViewMut<UdpClient>,
) { ) {
if let Some(ControlFlow::ExitWithCode(_)) = control_flow.0 { //TODO check if this works
if exit.0 {
if client.0.is_active() { if client.0.is_active() {
client.0.flush(); client.0.flush();
client.0.disconnect(); client.0.disconnect();
@ -167,11 +168,6 @@ pub fn disconnect_on_exit(
} else { } else {
log::info!("Client inactive") log::info!("Client inactive")
} }
// if let Err(error) = client.0. {
// log::error!("failed to disconnect: {}", error);
// } else {
// log::info!("Client disconnected");
// }
} }
} }

View file

@ -1,7 +1,7 @@
use shipyard::{NonSendSync, UniqueView, Unique, AllStoragesView}; use shipyard::{NonSendSync, UniqueView, Unique, AllStoragesView};
use glium::{texture::{SrgbTexture2dArray, MipmapsOption}, Program}; use glium::{texture::{SrgbTexture2dArray, MipmapsOption}, Program};
use kubi_shared::block::BlockTexture; use kubi_shared::block::BlockTexture;
use crate::rendering::Renderer; use crate::{rendering::Renderer, filesystem::AssetManager};
mod texture; mod texture;
mod shaders; mod shaders;
@ -54,11 +54,13 @@ pub struct ProgressbarShaderPrefab(pub Program);
pub fn load_prefabs( pub fn load_prefabs(
storages: AllStoragesView, storages: AllStoragesView,
renderer: NonSendSync<UniqueView<Renderer>> renderer: NonSendSync<UniqueView<Renderer>>,
assman: UniqueView<AssetManager>
) { ) {
log::info!("Loading textures..."); log::info!("Loading textures...");
storages.add_unique_non_send_sync(BlockTexturesPrefab( storages.add_unique_non_send_sync(BlockTexturesPrefab(
load_texture2darray_prefab::<BlockTexture, _>( load_texture2darray_prefab::<BlockTexture, _>(
&assman,
"blocks".into(), "blocks".into(),
&renderer.display, &renderer.display,
MipmapsOption::AutoGeneratedMipmaps MipmapsOption::AutoGeneratedMipmaps

View file

@ -2,13 +2,14 @@ use strum::IntoEnumIterator;
use rayon::prelude::*; use rayon::prelude::*;
use std::{path::PathBuf, io::BufReader}; use std::{path::PathBuf, io::BufReader};
use glium::{texture::{SrgbTexture2dArray, RawImage2d, MipmapsOption}, backend::Facade}; use glium::{texture::{SrgbTexture2dArray, RawImage2d, MipmapsOption}, backend::Facade};
use crate::filesystem::open_asset; use crate::filesystem::AssetManager;
use super::AssetPaths; use super::AssetPaths;
pub fn load_texture2darray_prefab< pub fn load_texture2darray_prefab<
T: AssetPaths + IntoEnumIterator, T: AssetPaths + IntoEnumIterator,
E: Facade E: Facade
>( >(
assman: &AssetManager,
directory: PathBuf, directory: PathBuf,
facade: &E, facade: &E,
mipmaps: MipmapsOption, mipmaps: MipmapsOption,
@ -21,7 +22,7 @@ pub fn load_texture2darray_prefab<
//Get path to the image and open the file //Get path to the image and open the file
let reader = { let reader = {
let path = directory.join(file_name); let path = directory.join(file_name);
BufReader::new(open_asset(&path).expect("Failed to open texture file")) BufReader::new(assman.open_asset(&path).expect("Failed to open texture file"))
}; };
//Parse image data //Parse image data
let (image_data, dimensions) = { let (image_data, dimensions) = {

View file

@ -1,12 +1,17 @@
use std::num::NonZeroU32;
use raw_window_handle::HasRawWindowHandle;
use shipyard::{Unique, NonSendSync, UniqueView, UniqueViewMut, View, IntoIter, AllStoragesView}; use shipyard::{Unique, NonSendSync, UniqueView, UniqueViewMut, View, IntoIter, AllStoragesView};
use glium::{ use winit::{
Display, Surface, event_loop::EventLoopWindowTarget,
Version, Api, window::{WindowBuilder, Fullscreen, Window},
glutin::{ dpi::PhysicalSize
event_loop::EventLoop, };
window::{WindowBuilder, Fullscreen}, use glium::{Display, Surface, Version, Api};
ContextBuilder, GlProfile, GlRequest, dpi::PhysicalSize use glutin::{
}, prelude::*,
context::ContextAttributesBuilder,
surface::{WindowSurface, SurfaceAttributesBuilder},
display::GetGlDisplay,
}; };
use glam::{Vec3, UVec2}; use glam::{Vec3, UVec2};
use crate::{events::WindowResizedEvent, settings::{GameSettings, FullscreenMode}}; use crate::{events::WindowResizedEvent, settings::{GameSettings, FullscreenMode}};
@ -30,10 +35,12 @@ pub struct WindowSize(pub UVec2);
#[derive(Unique)] #[derive(Unique)]
pub struct Renderer { pub struct Renderer {
pub display: Display pub window: Window,
pub display: Display<WindowSurface>,
} }
impl Renderer { impl Renderer {
pub fn init(event_loop: &EventLoop<()>, settings: &GameSettings) -> Self { pub fn init(event_loop: &EventLoopWindowTarget<()>, settings: &GameSettings) -> Self {
log::info!("initializing display"); log::info!("initializing display");
let wb = WindowBuilder::new() let wb = WindowBuilder::new()
@ -82,16 +89,43 @@ impl Renderer {
} }
}); });
let cb = ContextBuilder::new() // First we start by opening a new Window
//.with_srgb(false) let display_builder = glutin_winit::DisplayBuilder::new().with_window_builder(Some(wb));
.with_depth_buffer(24) let config_template_builder = glutin::config::ConfigTemplateBuilder::new();
.with_multisampling(settings.msaa.unwrap_or_default()) let (window, gl_config) = display_builder
.with_vsync(settings.vsync) .build(event_loop, config_template_builder, |mut configs| {
.with_gl_profile(GlProfile::Core) configs.next().unwrap()
.with_gl(GlRequest::Latest); })
.unwrap();
let window = window.unwrap();
let display = Display::new(wb, cb, event_loop) // Now we get the window size to use as the initial size of the Surface
.expect("Failed to create a glium Display"); let (width, height): (u32, u32) = window.inner_size().into();
let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
window.raw_window_handle(),
NonZeroU32::new(width).unwrap(),
NonZeroU32::new(height).unwrap(),
);
// Finally we can create a Surface, use it to make a PossiblyCurrentContext and create the glium Display
let surface = unsafe { gl_config.display().create_window_surface(&gl_config, &attrs).unwrap() };
let context_attributes = ContextAttributesBuilder::new().build(Some(window.raw_window_handle()));
let current_context = unsafe {
gl_config.display().create_context(&gl_config, &context_attributes).expect("failed to create context")
}.make_current(&surface).unwrap();
let display = Display::from_context_surface(current_context, surface).unwrap();
//TODO MIGRATION
// let cb = ContextBuilder::new()
// //.with_srgb(false)
// .with_depth_buffer(24)
// .with_multisampling(settings.msaa.unwrap_or_default())
// .with_vsync(settings.vsync)
// .with_gl_profile(GlProfile::Core)
// .with_gl(GlRequest::Latest);
// let display = Display::new(wb, cb)
// .expect("Failed to create a glium Display");
log::info!("Vendor: {}", display.get_opengl_vendor_string()); log::info!("Vendor: {}", display.get_opengl_vendor_string());
log::info!("Renderer: {}", display.get_opengl_renderer_string()); log::info!("Renderer: {}", display.get_opengl_renderer_string());
@ -104,7 +138,7 @@ impl Renderer {
assert!(display.is_glsl_version_supported(&Version(Api::GlEs, 3, 0)), "GLSL ES 3.0 is not supported"); assert!(display.is_glsl_version_supported(&Version(Api::GlEs, 3, 0)), "GLSL ES 3.0 is not supported");
Self { display } Self { window, display }
} }
} }

View file

@ -27,9 +27,13 @@ impl Default for GameSettings {
fullscreen: None, fullscreen: None,
msaa: Some(4), msaa: Some(4),
max_anisotropy: Some(16), max_anisotropy: Some(16),
render_distance: 6, render_distance: match true {
cfg!(debug_assertions) => 5,
cfg!(target_os = "android") => 6,
#[allow(unreachable_patterns)] _ => 8,
},
mouse_sensitivity: 1., mouse_sensitivity: 1.,
debug_draw_current_chunk_border: cfg!(not(target_os = "android")) && cfg!(debug_assertions), debug_draw_current_chunk_border: false, //cfg!(not(target_os = "android")) && cfg!(debug_assertions),
} }
} }
} }