diff --git a/.gitignore b/.gitignore index cc87256f..6ebb03b4 100755 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ Cargo.lock **/wasm_help/staging .vscode/launch.json manual/book/* +dependency_order.md diff --git a/Cargo.toml b/Cargo.toml index 992aa165..d5e3f4ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-lib" -version = "0.8.2" +version = "0.8.7" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "Meta-crate holding the entirety of bracket-lib (and exposing it). Use this for the full roguelike toolkit experience." homepage = "https://github.com/thebracket/bracket-lib" @@ -23,9 +23,11 @@ exclude = [ "screenshots" ] resolver = "2" # Enables the new Cargo resolution engine +incremental = false # Causing issues with Windows builds [features] default = [ "opengl" ] +bevy = ["bracket-geometry/bevy"] specs = [ "bracket-geometry/specs" ] serde = [ "bracket-color/serde", "bracket-geometry/serde", "bracket-random/serde" ] threaded = [ "bracket-pathfinding/threaded" ] @@ -35,13 +37,13 @@ crossterm = [ "bracket-terminal/cross_term" ] webgpu = [ "bracket-terminal/webgpu" ] [dependencies] -bracket-algorithm-traits = { path = "./bracket-algorithm-traits", version = "~0.8.2" } -bracket-color = { path = "./bracket-color", version = "~0.8.2", features = [ "palette" ] } -bracket-geometry = { path = "./bracket-geometry", version = "~0.8.2" } -bracket-noise = { path = "./bracket-noise", version = "~0.8.2" } -bracket-pathfinding = { path = "./bracket-pathfinding", version = "~0.8.2" } -bracket-random = { path = "./bracket-random", version = "~0.8.2", features = [ "parsing" ] } -bracket-terminal = { path = "./bracket-terminal", version = "~0.8.2", default-features = false } +bracket-algorithm-traits = { path = "./bracket-algorithm-traits", version = "~0.8" } +bracket-color = { path = "./bracket-color", version = "~0.8", features = [ "palette" ] } +bracket-geometry = { path = "./bracket-geometry", version = "~0.8" } +bracket-noise = { path = "./bracket-noise", version = "~0.8" } +bracket-pathfinding = { path = "./bracket-pathfinding", version = "~0.8" } +bracket-random = { path = "./bracket-random", version = "~0.8", features = [ "parsing" ] } +bracket-terminal = { path = "./bracket-terminal", version = "~0.8", default-features = false } [workspace] members = [ @@ -55,16 +57,5 @@ members = [ "rltk", "bracket-rex", "bracket-embedding", - "bracket-bevy" + "bracket-bevy", ] - -# Comment this out for releases -#[patch.crates-io] -#bracket-algorithm-traits = { path = "bracket-algorithm-traits/" } -#bracket-color = { path = "bracket-color/" } -#bracket-geometry = { path = "bracket-geometry/" } -#bracket-noise = { path = "bracket-noise/" } -#bracket-pathfinding = { path = "bracket-pathfinding/" } -#bracket-random = { path = "bracket-random/" } -#bracket-terminal = { path = "bracket-terminal/" } -#rltk = { path = "rltk/" } diff --git a/README.md b/README.md index ed159547..9921a534 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ In your `Cargo.toml` file, include: ```toml [dependencies] -bracket-lib = "0.7" +bracket-lib = "~0.8" ``` ## Feature Flags diff --git a/bracket-algorithm-traits/Cargo.toml b/bracket-algorithm-traits/Cargo.toml index 16afbb48..ab4ede58 100755 --- a/bracket-algorithm-traits/Cargo.toml +++ b/bracket-algorithm-traits/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-algorithm-traits" -version = "0.8.2" +version = "0.8.7" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "Traits required for the bracket-* crates. Adapt your maps to the traits with Algorithm2D, Algorithm3D and BaseMap." homepage = "https://github.com/thebracket/bracket-lib" @@ -15,5 +15,5 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bracket-geometry = { path = "../bracket-geometry", version = "~0.8.2" } +bracket-geometry = { path = "../bracket-geometry", version = "~0.8" } smallvec = "~1" diff --git a/bracket-bevy/Cargo.toml b/bracket-bevy/Cargo.toml index 45626125..f897339b 100644 --- a/bracket-bevy/Cargo.toml +++ b/bracket-bevy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-bevy" -version = "0.9.0" +version = "0.11.0" edition = "2021" authors = ["Herbert Wolverson "] publish = true @@ -13,13 +13,14 @@ categories = ["game-engines", "graphics"] license = "MIT" [dependencies] -bevy = "0.8" + +bevy = "0.11.0" parking_lot = "0.12" lazy_static = "1.4" bracket-random = { path = "../bracket-random" } bracket-color = { path = "../bracket-color", features = [ "bevy" ] } -bracket-geometry = { path = "../bracket-geometry", version = "~0.8.3" } +bracket-geometry = { path = "../bracket-geometry", version = "~0.8", features = [ "bevy" ] } [dev-dependencies] -bracket-pathfinding = { path = "../bracket-pathfinding", version = "~0.8.4" } -bracket-noise = { path = "../bracket-noise", version = "~0.8.2" } \ No newline at end of file +bracket-pathfinding = { path = "../bracket-pathfinding", version = "~0.8" } +bracket-noise = { path = "../bracket-noise", version = "~0.8" } diff --git a/bracket-bevy/examples/bevy_a_star_mouse.rs b/bracket-bevy/examples/bevy_a_star_mouse.rs index 29186356..865f3dfc 100644 --- a/bracket-bevy/examples/bevy_a_star_mouse.rs +++ b/bracket-bevy/examples/bevy_a_star_mouse.rs @@ -23,6 +23,7 @@ enum Mode { Moving, } +#[derive(Resource)] struct State { map: Vec, player_position: usize, diff --git a/bracket-bevy/examples/bevy_alpha.rs b/bracket-bevy/examples/bevy_alpha.rs index 96c0b224..f2cfb15a 100644 --- a/bracket-bevy/examples/bevy_alpha.rs +++ b/bracket-bevy/examples/bevy_alpha.rs @@ -34,8 +34,8 @@ fn tick(ctx: Res, mut state: Local) { ctx.set_active_console(0); ctx.cls(); state.totc.print_sub_rect( - Rect::with_size(0, 0, 79, 49), - Rect::with_exact(0, 0, 79, 49), + bracket_bevy::prelude::Rect::with_size(0, 0, 79, 49), + bracket_bevy::prelude::Rect::with_exact(0, 0, 79, 49), 0, &ctx, ); diff --git a/bracket-bevy/examples/bevy_colorfont.rs b/bracket-bevy/examples/bevy_colorfont.rs index 90b42f04..67a64e3f 100644 --- a/bracket-bevy/examples/bevy_colorfont.rs +++ b/bracket-bevy/examples/bevy_colorfont.rs @@ -24,8 +24,8 @@ impl Default for TickResource { fn tick(ctx: Res, tale_of_two_cities: Local) { ctx.cls(); tale_of_two_cities.0.print_sub_rect( - Rect::with_size(0, 0, 79, 25), - Rect::with_exact(0, 0, 79, 25), + bracket_bevy::prelude::Rect::with_size(0, 0, 79, 25), + bracket_bevy::prelude::Rect::with_exact(0, 0, 79, 25), 0, &ctx, ); diff --git a/bracket-bevy/examples/bevy_hello_terminal.rs b/bracket-bevy/examples/bevy_hello_terminal.rs index 43ca1f4e..e3b999aa 100644 --- a/bracket-bevy/examples/bevy_hello_terminal.rs +++ b/bracket-bevy/examples/bevy_hello_terminal.rs @@ -17,6 +17,7 @@ fn main() { .run(); } +#[derive(Resource)] struct State { y: i32, going_down: bool, diff --git a/bracket-bevy/examples/bevy_roguelike_tutorial_4/main.rs b/bracket-bevy/examples/bevy_roguelike_tutorial_4/main.rs index 2cff57f6..39af8f1a 100644 --- a/bracket-bevy/examples/bevy_roguelike_tutorial_4/main.rs +++ b/bracket-bevy/examples/bevy_roguelike_tutorial_4/main.rs @@ -25,7 +25,7 @@ fn setup(mut commands: Commands, rng: Res) { let (player_x, player_y) = rooms[0].center(); commands.insert_resource(map); commands - .spawn() + .spawn_empty() .insert(Position { x: player_x, y: player_y, @@ -40,7 +40,7 @@ fn setup(mut commands: Commands, rng: Res) { fn tick( ctx: Res, - map: Res>, + map: Res, keyboard: Res>, mut queries: ParamSet<( Query<&mut Position, With>, @@ -54,13 +54,13 @@ fn tick( let mut player_query = queries.p0(); let mut pos = player_query.single_mut(); let destination_idx = xy_idx(pos.x + delta.0, pos.y + delta.1); - if map[destination_idx] != TileType::Wall { + if map.0[destination_idx] != TileType::Wall { pos.x = min(79, max(0, pos.x + delta.0)); pos.y = min(49, max(0, pos.y + delta.1)); } } - draw_map(&map, &ctx); + draw_map(&map.0, &ctx); for (pos, render) in queries.p1().iter() { ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph); } diff --git a/bracket-bevy/examples/bevy_roguelike_tutorial_4/map.rs b/bracket-bevy/examples/bevy_roguelike_tutorial_4/map.rs index 03b4a0cf..1cf7ffc8 100644 --- a/bracket-bevy/examples/bevy_roguelike_tutorial_4/map.rs +++ b/bracket-bevy/examples/bevy_roguelike_tutorial_4/map.rs @@ -1,4 +1,5 @@ use crate::rect::Rect; +use bevy::prelude::Resource; use bracket_bevy::{ prelude::{to_cp437, RGB}, BracketContext, RandomNumbers, @@ -11,6 +12,9 @@ pub enum TileType { Floor, } +#[derive(Resource)] +pub struct Map(pub Vec); + pub fn xy_idx(x: i32, y: i32) -> usize { (y as usize * 80) + x as usize } @@ -70,7 +74,7 @@ fn apply_vertical_tunnel(map: &mut [TileType], y1: i32, y2: i32, x: i32) { /// Makes a new map using the algorithm from http://rogueliketutorials.com/tutorials/tcod/part-3/ /// This gives a handful of random rooms and corridors joining them together. -pub fn new_map_rooms_and_corridors(rng: &RandomNumbers) -> (Vec, Vec) { +pub fn new_map_rooms_and_corridors(rng: &RandomNumbers) -> (Vec, Map) { let mut map = vec![TileType::Wall; 80 * 50]; let mut rooms: Vec = Vec::new(); @@ -109,7 +113,7 @@ pub fn new_map_rooms_and_corridors(rng: &RandomNumbers) -> (Vec, Vec, player_position: usize, diff --git a/bracket-bevy/examples/bevy_two_layers_two_fonts.rs b/bracket-bevy/examples/bevy_two_layers_two_fonts.rs index 25938056..baeeb9bd 100644 --- a/bracket-bevy/examples/bevy_two_layers_two_fonts.rs +++ b/bracket-bevy/examples/bevy_two_layers_two_fonts.rs @@ -18,6 +18,7 @@ fn main() { .run(); } +#[derive(Resource)] struct Bouncer(i32); fn tick(ctx: Res, mut bouncer: ResMut) { diff --git a/bracket-bevy/examples/bevy_walking.rs b/bracket-bevy/examples/bevy_walking.rs index b635efca..1204cafe 100644 --- a/bracket-bevy/examples/bevy_walking.rs +++ b/bracket-bevy/examples/bevy_walking.rs @@ -16,6 +16,7 @@ enum TileType { Floor, } +#[derive(Resource)] struct State { map: Vec, visited: Vec, diff --git a/bracket-bevy/src/builder/bterm_builder.rs b/bracket-bevy/src/builder/bterm_builder.rs index 38a7ad35..7615fc0c 100644 --- a/bracket-bevy/src/builder/bterm_builder.rs +++ b/bracket-bevy/src/builder/bterm_builder.rs @@ -3,11 +3,13 @@ use crate::{ apply_all_batches, default_gutter_size, replace_meshes, update_mouse_position, update_timing, window_resize, ScreenScaler, }, - load_terminals, update_consoles, RandomNumbers, TerminalBuilderFont, TerminalLayer, fix_images, + fix_images, load_terminals, update_consoles, RandomNumbers, TerminalBuilderFont, TerminalLayer, }; use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, - prelude::{CoreStage, Plugin, SystemStage}, + + prelude::{Plugin, Resource, Msaa, Startup, PostUpdate, PreUpdate, First}, + utils::HashMap, }; use bracket_color::prelude::RGBA; @@ -19,7 +21,7 @@ pub enum TerminalScalingMode { ResizeTerminals, } -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct BTermBuilder { pub(crate) fonts: Vec, pub(crate) layers: Vec, @@ -176,37 +178,32 @@ impl BTermBuilder { impl Plugin for BTermBuilder { fn build(&self, app: &mut bevy::prelude::App) { - app.insert_resource(bevy::prelude::Msaa { samples: 1 }); - if self.with_diagnostics { - app.add_plugin(FrameTimeDiagnosticsPlugin); + app.insert_resource(Msaa::Off); + + if self.with_diagnostics { + app.add_plugins(FrameTimeDiagnosticsPlugin); } if self.log_diagnostics { - app.add_plugin(LogDiagnosticsPlugin::default()); + app.add_plugins(LogDiagnosticsPlugin::default()); } app.insert_resource(self.clone()); app.insert_resource(ScreenScaler::new(self.gutter)); - app.add_startup_system(load_terminals); + app.add_systems(Startup, load_terminals); if self.with_diagnostics { - app.add_stage_before( - CoreStage::Update, - "bracket_term_diagnostics", - SystemStage::single_threaded(), - ); - app.add_system(update_timing); - app.add_system(update_mouse_position); + app.add_systems(First, update_timing); + app.add_systems(PreUpdate,update_mouse_position); } - app.add_stage_after( - CoreStage::Update, - "bracket_term_update", - SystemStage::single_threaded(), - ); - if self.auto_apply_batches { - app.add_system(apply_all_batches); + + if self.auto_apply_batches { + app.add_systems(PostUpdate, apply_all_batches); } - app.add_system(update_consoles); - app.add_system(replace_meshes); - app.add_system(window_resize); - app.add_system(fix_images); + + //update_schedule_label + app.add_systems(PostUpdate, update_consoles); + app.add_systems(PostUpdate, replace_meshes); + app.add_systems(PostUpdate, window_resize); + app.add_systems(PostUpdate,fix_images); + if self.with_random_number_generator { app.insert_resource(RandomNumbers::new()); } diff --git a/bracket-bevy/src/builder/image_fixer.rs b/bracket-bevy/src/builder/image_fixer.rs index a1d4d952..1a4ebb20 100644 --- a/bracket-bevy/src/builder/image_fixer.rs +++ b/bracket-bevy/src/builder/image_fixer.rs @@ -1,19 +1,22 @@ -use bevy::{prelude::*, render::{texture::ImageSampler, render_resource::SamplerDescriptor}}; +use bevy::{ + prelude::*, + render::{render_resource::SamplerDescriptor, texture::ImageSampler}, +}; -pub(crate) struct ImagesToLoad (pub(crate) Vec); +#[derive(Resource)] +pub(crate) struct ImagesToLoad(pub(crate) Vec); -pub(crate) fn fix_images( - mut fonts: ResMut, - mut images: ResMut>, -) { +pub(crate) fn fix_images(mut fonts: ResMut, mut images: ResMut>) { if fonts.0.is_empty() { return; } for (handle, img) in images.iter_mut() { let mut to_remove = Vec::new(); - if let Some(i) = fonts.0.iter().enumerate().find(|(_i, h)| h.id == handle) { - img.sampler_descriptor = ImageSampler::Descriptor(SamplerDescriptor{ + + if let Some(i) = fonts.0.iter().enumerate().find(|(_i, h)| h.id() == handle) { + img.sampler_descriptor = ImageSampler::Descriptor(SamplerDescriptor { + label: Some("LeaveItAlone"), address_mode_u: bevy::render::render_resource::AddressMode::ClampToEdge, address_mode_v: bevy::render::render_resource::AddressMode::ClampToEdge, @@ -25,6 +28,8 @@ pub(crate) fn fix_images( }); to_remove.push(i.0); } - to_remove.iter().for_each(|i| { fonts.0.remove(*i); }); + to_remove.iter().for_each(|i| { + fonts.0.remove(*i); + }); } -} \ No newline at end of file +} diff --git a/bracket-bevy/src/builder/loader_system.rs b/bracket-bevy/src/builder/loader_system.rs index b5140c6a..d24f7ac3 100644 --- a/bracket-bevy/src/builder/loader_system.rs +++ b/bracket-bevy/src/builder/loader_system.rs @@ -3,7 +3,9 @@ use crate::{ TerminalLayer, }; use bevy::{ - prelude::{AssetServer, Assets, Camera2dBundle, Commands, Component, Mesh, Res, ResMut, HandleUntyped}, + prelude::{ + AssetServer, Assets, Camera2dBundle, Commands, Component, HandleUntyped, Mesh, Res, ResMut, + }, sprite::ColorMaterial, }; @@ -21,7 +23,7 @@ pub(crate) fn load_terminals( ) { if context.with_ortho_camera { commands - .spawn_bundle(Camera2dBundle::default()) + .spawn(Camera2dBundle::default()) .insert(BracketCamera); } diff --git a/bracket-bevy/src/builder/mod.rs b/bracket-bevy/src/builder/mod.rs index a1a91ec3..e29a8f21 100644 --- a/bracket-bevy/src/builder/mod.rs +++ b/bracket-bevy/src/builder/mod.rs @@ -7,4 +7,4 @@ pub use bterm_builder::*; mod loader_system; pub(crate) use loader_system::*; mod image_fixer; -pub(crate) use image_fixer::*; \ No newline at end of file +pub(crate) use image_fixer::*; diff --git a/bracket-bevy/src/consoles/scaler.rs b/bracket-bevy/src/consoles/scaler.rs index 0906a1a7..e2dd6b14 100644 --- a/bracket-bevy/src/consoles/scaler.rs +++ b/bracket-bevy/src/consoles/scaler.rs @@ -1,3 +1,5 @@ +use bevy::prelude::Resource; + pub(crate) struct FontScaler { chars_per_row: u16, n_rows: u16, @@ -29,6 +31,7 @@ impl FontScaler { } } +#[derive(Resource)] pub(crate) struct ScreenScaler { pub(crate) screen: (f32, f32), desired_gutter: f32, diff --git a/bracket-bevy/src/consoles/simple_console/back_end/simple_no_background.rs b/bracket-bevy/src/consoles/simple_console/back_end/simple_no_background.rs index 4960a99b..5432bedb 100644 --- a/bracket-bevy/src/consoles/simple_console/back_end/simple_no_background.rs +++ b/bracket-bevy/src/consoles/simple_console/back_end/simple_no_background.rs @@ -107,7 +107,7 @@ impl SimpleConsoleBackend for SimpleBackendNoBackground { fn spawn(&self, commands: &mut Commands, material: Handle, idx: usize) { if let Some(mesh_handle) = &self.mesh_handle { commands - .spawn_bundle(MaterialMesh2dBundle { + .spawn(MaterialMesh2dBundle { mesh: mesh_handle.clone().into(), transform: Transform::default(), material, diff --git a/bracket-bevy/src/consoles/simple_console/back_end/simple_with_background.rs b/bracket-bevy/src/consoles/simple_console/back_end/simple_with_background.rs index 7f2d60e1..2065820a 100644 --- a/bracket-bevy/src/consoles/simple_console/back_end/simple_with_background.rs +++ b/bracket-bevy/src/consoles/simple_console/back_end/simple_with_background.rs @@ -145,7 +145,7 @@ impl SimpleConsoleBackend for SimpleBackendWithBackground { fn spawn(&self, commands: &mut Commands, material: Handle, idx: usize) { if let Some(mesh_handle) = &self.mesh_handle { commands - .spawn_bundle(MaterialMesh2dBundle { + .spawn(MaterialMesh2dBundle { mesh: mesh_handle.clone().into(), transform: Transform::default(), material, diff --git a/bracket-bevy/src/consoles/simple_console/front_end.rs b/bracket-bevy/src/consoles/simple_console/front_end.rs index 52d24c57..976ebfe4 100644 --- a/bracket-bevy/src/consoles/simple_console/front_end.rs +++ b/bracket-bevy/src/consoles/simple_console/front_end.rs @@ -120,7 +120,9 @@ impl ConsoleFrontEnd for SimpleConsole { } fn cls(&mut self) { - self.terminal.iter_mut().for_each(|c| c.glyph = 32); + self.terminal + .iter_mut() + .for_each(|c| *c = TerminalGlyph::default()); } fn cls_bg(&mut self, color: RGBA) { diff --git a/bracket-bevy/src/consoles/sparse_console/back_end/sparse_no_background.rs b/bracket-bevy/src/consoles/sparse_console/back_end/sparse_no_background.rs index 36eba3eb..881f1d60 100644 --- a/bracket-bevy/src/consoles/sparse_console/back_end/sparse_no_background.rs +++ b/bracket-bevy/src/consoles/sparse_console/back_end/sparse_no_background.rs @@ -106,7 +106,7 @@ impl SparseConsoleBackend for SparseBackendNoBackground { fn spawn(&self, commands: &mut Commands, material: Handle, idx: usize) { if let Some(mesh_handle) = &self.mesh_handle { commands - .spawn_bundle(MaterialMesh2dBundle { + .spawn(MaterialMesh2dBundle { mesh: mesh_handle.clone().into(), transform: Transform::default(), material, diff --git a/bracket-bevy/src/consoles/sparse_console/back_end/sparse_with_background.rs b/bracket-bevy/src/consoles/sparse_console/back_end/sparse_with_background.rs index 82183a10..1958187f 100644 --- a/bracket-bevy/src/consoles/sparse_console/back_end/sparse_with_background.rs +++ b/bracket-bevy/src/consoles/sparse_console/back_end/sparse_with_background.rs @@ -137,7 +137,7 @@ impl SparseConsoleBackend for SparseBackendWithBackground { fn spawn(&self, commands: &mut Commands, material: Handle, idx: usize) { if let Some(mesh_handle) = &self.mesh_handle { commands - .spawn_bundle(MaterialMesh2dBundle { + .spawn(MaterialMesh2dBundle { mesh: mesh_handle.clone().into(), transform: Transform::default(), material, diff --git a/bracket-bevy/src/consoles/update_system.rs b/bracket-bevy/src/consoles/update_system.rs index 1527d842..948a0139 100644 --- a/bracket-bevy/src/consoles/update_system.rs +++ b/bracket-bevy/src/consoles/update_system.rs @@ -1,12 +1,13 @@ use crate::{BracketCamera, BracketContext, TerminalScalingMode}; use bevy::{ - diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin}, + diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin}, ecs::event::Events, prelude::*, render::camera::RenderTarget, sprite::Mesh2dHandle, window::WindowResized, }; +use bevy::window::{PrimaryWindow, WindowRef}; use super::{BracketMesh, ScreenScaler}; @@ -43,9 +44,9 @@ pub(crate) fn replace_meshes( for ev in ev_asset.iter() { if let AssetEvent::Created { handle } = ev { for (old, new, done) in ctx.mesh_replacement.iter_mut() { - if handle.id == new.0.id { + if handle.id() == new.0.id() { update_mesh.for_each_mut(|mut m| { - if old.0.id == m.0.id { + if old.0.id() == m.0.id() { *m = new.clone(); } }); @@ -61,7 +62,7 @@ pub(crate) fn replace_meshes( ctx.mesh_replacement.retain(|(_, _, done)| !done); } -pub(crate) fn update_timing(mut ctx: ResMut, diagnostics: Res) { +pub(crate) fn update_timing(mut ctx: ResMut, diagnostics: Res) { if let Some(fps_diagnostic) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) { if let Some(fps_avg) = fps_diagnostic.measurement() { ctx.fps = fps_avg.value.round(); @@ -95,35 +96,57 @@ pub(crate) fn apply_all_batches(mut context: ResMut) { } pub(crate) fn update_mouse_position( - wnds: Res, + wnds: Query<&Window>, + primary_window: Query<&Window, With>, q_camera: Query<(&Camera, &GlobalTransform), With>, mut context: ResMut, - scaler: Res, + mut scaler: ResMut, ) { // Modified from: https://bevy-cheatbook.github.io/cookbook/cursor2world.html // Bevy really needs a nicer way to do this let (camera, camera_transform) = q_camera.single(); - let wnd = if let RenderTarget::Window(id) = camera.target { - wnds.get(id) - } else { - wnds.get_primary() - }; - - let wnd = if let Some(wnd) = wnd { - wnd - } else { - return; - }; - - if let Some(screen_pos) = wnd.cursor_position() { - let window_size = Vec2::new(wnd.width() as f32, wnd.height() as f32); - let ndc = (screen_pos / window_size) * 2.0 - Vec2::ONE; - let ndc_to_world = camera_transform.compute_matrix() * camera.projection_matrix().inverse(); - let world_pos = ndc_to_world.project_point3(ndc.extend(-1.0)); - let world_pos: Vec2 = world_pos.truncate(); + + let mut wnd_opt: Option<&Window> = None; + + match camera.target { + RenderTarget::Window(window_ref) => { + match window_ref { + WindowRef::Primary => { + wnd_opt =Some(primary_window.single()); + } + + WindowRef::Entity(entity) => { + wnd_opt = Some(wnds.get(entity) + .expect(format!("Couldn't get window with entity id {} and generation {} from query!", + entity.index(), + entity.generation()).as_str()) + ); + } + } + } + // Is there a reason why the camera's RenderTarget should ever be an image?? + RenderTarget::Image(_) => { panic!("The camera RenderTarget was an image, we shouldn't reach this case!") } + RenderTarget::TextureView(_) => todo!(), + } + + if wnd_opt.is_some() { + let wnd = wnd_opt.expect("Window was None!"); + if let Some(screen_pos) = wnd.cursor_position() { + + // This is a workaround to ensure that the Scaler's width and height are never 0. + // Res had to be changed to ResMut + // We should probably check why it's occasionally 0 to begin with. + scaler.set_screen_size(wnd.width(), wnd.height()); + + let window_size = Vec2::new(wnd.width() as f32, wnd.height() as f32); + let ndc = (screen_pos / window_size) * 2.0 - Vec2::ONE; + let ndc_to_world = camera_transform.compute_matrix() * camera.projection_matrix().inverse(); + let world_pos = ndc_to_world.project_point3(ndc.extend(-1.0)); + let world_pos: Vec2 = world_pos.truncate(); - let result = (world_pos.x, world_pos.y); + let result = (world_pos.x, world_pos.y * -1.0); - context.set_mouse_pixel_position(result, &scaler); + context.set_mouse_pixel_position(result, &scaler); + } } } diff --git a/bracket-bevy/src/consoles/virtual_console.rs b/bracket-bevy/src/consoles/virtual_console.rs index f86c991f..da2e0075 100644 --- a/bracket-bevy/src/consoles/virtual_console.rs +++ b/bracket-bevy/src/consoles/virtual_console.rs @@ -123,7 +123,9 @@ impl ConsoleFrontEnd for VirtualConsole { } fn cls(&mut self) { - self.terminal.iter_mut().for_each(|c| c.glyph = 32); + self.terminal + .iter_mut() + .for_each(|c| *c = TerminalGlyph::default()); } fn cls_bg(&mut self, color: RGBA) { diff --git a/bracket-bevy/src/context.rs b/bracket-bevy/src/context.rs index 17ba9ea8..2722d4ab 100644 --- a/bracket-bevy/src/context.rs +++ b/bracket-bevy/src/context.rs @@ -3,11 +3,12 @@ use crate::{ fonts::FontStore, FontCharType, TerminalScalingMode, }; -use bevy::{sprite::Mesh2dHandle, utils::HashMap}; +use bevy::{sprite::Mesh2dHandle, utils::HashMap, prelude::Resource}; use bracket_color::prelude::RGBA; use bracket_geometry::prelude::{Point, Rect}; use parking_lot::Mutex; +#[derive(Resource)] pub struct BracketContext { pub(crate) fonts: Vec, pub(crate) terminals: Mutex>>, diff --git a/bracket-bevy/src/lib.rs b/bracket-bevy/src/lib.rs index 35d4a576..99d1936c 100644 --- a/bracket-bevy/src/lib.rs +++ b/bracket-bevy/src/lib.rs @@ -11,7 +11,6 @@ mod random_resource; pub use consoles::{DrawBatch, VirtualConsole}; pub use random_resource::*; mod textblock; - pub type FontCharType = u16; pub mod prelude { diff --git a/bracket-bevy/src/random_resource/mod.rs b/bracket-bevy/src/random_resource/mod.rs index 363a87d2..2ae39401 100644 --- a/bracket-bevy/src/random_resource/mod.rs +++ b/bracket-bevy/src/random_resource/mod.rs @@ -1,6 +1,8 @@ +use bevy::prelude::Resource; use bracket_random::prelude::RandomNumberGenerator; use parking_lot::Mutex; +#[derive(Resource)] pub struct RandomNumbers { rng: Mutex, } diff --git a/bracket-color/Cargo.toml b/bracket-color/Cargo.toml index 3c5122c0..0ae96f52 100755 --- a/bracket-color/Cargo.toml +++ b/bracket-color/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-color" -version = "0.8.2" +version = "0.8.8" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "RGB and HSV color handling and utilities, including lerp and W3C named colors. Part of the bracket-lib family." homepage = "https://github.com/thebracket/bracket-lib" @@ -17,13 +17,14 @@ palette = [ "lazy_static", "parking_lot" ] [dependencies] serde = { version = "~1.0.110", features = ["derive"], optional = true } -crossterm = { version = "~0.24", optional = true } +crossterm = { version = "~0.25", optional = true } lazy_static = { version = "1.4.0", optional = true } parking_lot = { version = "~0.12", optional = true } -bevy = { version = "0.8", optional = true } + +bevy = { version = "0.11.0", optional = true } [dev-dependencies] -crossterm = "~0.24" +crossterm = "~0.25" [[example]] name = "colors" diff --git a/bracket-color/README.md b/bracket-color/README.md index 0cce1b0a..5d6eb9fd 100755 --- a/bracket-color/README.md +++ b/bracket-color/README.md @@ -8,7 +8,7 @@ To obtain `bracket-color`, include the following in your `Cargo.toml` file: ```toml [dependencies] -bracket-color = "0.8.2" +bracket-color = "~0.8" ``` ## RGB @@ -52,6 +52,7 @@ Everything is exported via the `bracket_color::prelude` namespace. * If you enable the `serde` feature flag, the RGB, HSV and ColorPair structures are derived as `Serde` serializable/de-serializable. * The `rex` feature flag enables [RexPaint](https://www.gridsagegames.com/rexpaint/) support. * The `palette` feature flag enables a static (thread-safe) palette map, linking named colors to colors. It's empty by default (the `add_named_colors_to_palette` adds all of the constant named colors for you, in lower case). +* If you enable the `bevy` feature, conversions between Bevy's `Color` type and the `bracket-color` types are enabled. ## Examples diff --git a/bracket-color/examples/util/mod.rs b/bracket-color/examples/util/mod.rs index cafaf439..b620f9ed 100755 --- a/bracket-color/examples/util/mod.rs +++ b/bracket-color/examples/util/mod.rs @@ -2,7 +2,7 @@ use bracket_color::prelude::*; use crossterm::queue; use crossterm::style::{Print, SetForegroundColor}; use std::convert::TryInto; -use std::io::{stdout, Write}; +use std::io::stdout; pub fn print_color(color: RGB, text: &str) { queue!(stdout(), SetForegroundColor(color.try_into().unwrap())).expect("Command Fail"); diff --git a/bracket-color/src/color_pair.rs b/bracket-color/src/color_pair.rs index 168ad14d..b2cf11ad 100755 --- a/bracket-color/src/color_pair.rs +++ b/bracket-color/src/color_pair.rs @@ -3,6 +3,8 @@ use crate::prelude::RGBA; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Copy, Clone, Default, Debug)] /// Represents two colors together, a foreground and a background. +/// Frequently used to represent a glyph rendered on a console with +/// a solid background color. pub struct ColorPair { /// The foreground color pub fg: RGBA, @@ -14,6 +16,11 @@ impl ColorPair { #[inline] #[must_use] /// Creates a new `ColorPair`, from two given colors. + /// + /// # Arguments + /// + /// * `fg` - The foreground color to use. + /// * `bg` - The background color to use. pub fn new(fg: COLOR, bg: COLOR2) -> Self where COLOR: Into, diff --git a/bracket-color/src/hsv.rs b/bracket-color/src/hsv.rs index 67d2745e..627fe930 100755 --- a/bracket-color/src/hsv.rs +++ b/bracket-color/src/hsv.rs @@ -4,9 +4,14 @@ use std::convert::From; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Copy, Clone, Default, Debug)] /// Represents an H/S/V triplet, in the range 0..1 (32-bit float) +/// This can provide for a more natural color progression, and provides +/// compatibility with HSV-based color systems. pub struct HSV { + /// Hue (range 0..1) pub h: f32, + /// Saturation (range 0..1) pub s: f32, + /// Value (range 0..1) pub v: f32, } @@ -36,6 +41,12 @@ impl HSV { } /// Constructs a new HSV color, from 3 32-bit floats + /// + /// # Arguments + /// + /// * `h` - The hue (0..1) to use. + /// * `s` - The saturation (0..1) to use. + /// * `v` - The value (0..1) to use. #[inline] #[must_use] pub const fn from_f32(h: f32, s: f32, v: f32) -> Self { @@ -101,12 +112,28 @@ impl HSV { g = p; b = q; } + // Catch-all; this shouldn't happen _ => {} } RGB::from_f32(r, g, b) } + /// Progress smoothly between two colors, in the HSV color space. + /// + /// # Arguments + /// + /// * `color` - the target color. + /// * `percent` - the percentage (0..1) of the starting (self) and target color to use. + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGB::named(RED); + /// let blue = RGB::named(YELLOW); + /// let color = red.lerp(blue, 0.5); + /// ``` #[inline] #[must_use] pub fn lerp(&self, color: Self, percent: f32) -> Self { diff --git a/bracket-color/src/lerpit.rs b/bracket-color/src/lerpit.rs index 157e9425..770e430a 100755 --- a/bracket-color/src/lerpit.rs +++ b/bracket-color/src/lerpit.rs @@ -15,7 +15,23 @@ pub struct RgbLerp { } impl RgbLerp { - /// Creates a new RGB iterator + /// Creates a new RGB lerp iterator. The iterator smoothly transitions between two colors, + /// using the specified number of steps. + /// + /// # Arguments + /// + /// * `start` - the color to start from. + /// * `end` - the color to end at on the final step. + /// * `steps` - number of steps to iterate between the start and end colors. + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// for color in RgbLerp::new(RGB::named(RED), RGB::named(YELLOW), 20) { + /// println!("{:?}", color); // In-between color + /// } + /// ``` #[inline] pub fn new(start: RGB, end: RGB, steps: T) -> Self where diff --git a/bracket-color/src/lib.rs b/bracket-color/src/lib.rs index ab9a0908..84721e17 100755 --- a/bracket-color/src/lib.rs +++ b/bracket-color/src/lib.rs @@ -31,20 +31,20 @@ extern crate lazy_static; /// Import color pair support -mod color_pair; +pub mod color_pair; /// Import HSV color support -mod hsv; +pub mod hsv; /// Import Lerp as an iterator -mod lerpit; +pub mod lerpit; /// Import library of named colors -mod named; +pub mod named; /// Import Palette support #[cfg(feature = "palette")] -mod palette; +pub mod palette; /// Import RGB color support -mod rgb; +pub mod rgb; /// Import RGBA color support -mod rgba; +pub mod rgba; /// Exports the color functions/types in the `prelude` namespace. pub mod prelude { diff --git a/bracket-color/src/named.rs b/bracket-color/src/named.rs index 5729f99c..bc075d67 100755 --- a/bracket-color/src/named.rs +++ b/bracket-color/src/named.rs @@ -1,4 +1,6 @@ #![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::missing_docs)] + // Named Colors (derived from X11 rgb.txt, which is also the source of HTML/W3C/SVG names) pub const SNOW: (u8, u8, u8) = (255, 250, 250); pub const GHOST_WHITE: (u8, u8, u8) = (248, 248, 255); diff --git a/bracket-color/src/palette.rs b/bracket-color/src/palette.rs index f1974d0a..fef44322 100755 --- a/bracket-color/src/palette.rs +++ b/bracket-color/src/palette.rs @@ -8,15 +8,40 @@ lazy_static! { } /// Register a palette color by name with the global registry. +/// +/// # Arguments +/// +/// * `name` - the name of the color to register. +/// * `color` - a bracket-lib compatible color to associate with the name. +/// +/// # Example +/// +/// ```rust +/// use bracket_color::prelude::*; +/// register_palette_color("red", RED); +/// ``` #[allow(clippy::needless_pass_by_value)] pub fn register_palette_color>(name: S, color: COLOR) { PALETTE.lock().insert(name.to_string(), color.into()); } /// Retrieve a palette color by name from the global registry. +/// Returns `Some(RGBA)` if the color is registered, `None` if it is not. +/// +/// # Arguments +/// +/// * `name` - the requested name. +/// +/// # Example +/// +/// ```rust +/// use bracket_color::prelude::*; +/// register_palette_color("red", RED); +/// let color = palette_color("red").expect("Cannot find red"); +/// ``` #[allow(clippy::module_name_repetitions)] #[allow(clippy::needless_pass_by_value)] -pub fn palette_color(name: &S) -> Option { +pub fn palette_color(name: S) -> Option { let plock = PALETTE.lock(); plock.get(&name.to_string()).copied() } diff --git a/bracket-color/src/rgb.rs b/bracket-color/src/rgb.rs index ed361022..229a5c11 100755 --- a/bracket-color/src/rgb.rs +++ b/bracket-color/src/rgb.rs @@ -6,16 +6,22 @@ use std::ops; #[derive(PartialEq, Copy, Clone, Default, Debug)] /// Represents an R/G/B triplet, in the range 0..1 (32-bit float) pub struct RGB { + /// The red component (0..1) pub r: f32, + /// The green components (0..1) pub g: f32, + /// The blue component (0..1) pub b: f32, } #[derive(Debug, PartialEq, Copy, Clone)] /// Error message type when failing to convert a hex code to RGB. pub enum HtmlColorConversionError { + /// The HTML string was not a valid length. (Expects #AABBCC) InvalidStringLength, + /// No # was included in the string. MissingHash, + /// An unexpected character (not #, A-F) was detected in the color string. InvalidCharacter, } @@ -141,6 +147,20 @@ impl RGB { } /// Constructs a new RGB color, from 3 32-bit floats in the range 0..1 + /// + /// # Arguments + /// + /// * `r` - the red component (0..1) + /// * `g` - the green component (0..1) + /// * `b` - the blue component (0..1) + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGB::from_f32(1.0, 0.0, 0.0); + /// let green = RGB::from_f32(0.0, 1.0, 0.0); + /// ``` #[inline] #[must_use] pub fn from_f32(r: f32, g: f32, b: f32) -> Self { @@ -155,6 +175,20 @@ impl RGB { } /// Constructs a new RGB color, from 3 bytes in the range 0..255 + /// + /// # Arguments + /// + /// * `r` - the red component, ranged from 0 to 255 + /// * `g` - the green component, ranged from 0 to 255 + /// * `b` - the blue component, ranged from 0 to 255 + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGB::from_u8(255, 0, 0); + /// let green = RGB::from_u8(0, 255, 0); + /// ``` #[inline] #[must_use] pub fn from_u8(r: u8, g: u8, b: u8) -> Self { @@ -166,6 +200,18 @@ impl RGB { } /// Construct an RGB color from a tuple of u8, or a named constant + /// + /// # Arguments + /// + /// * `col` a tuple of three `u8` values. See `from_u8`. These are usually provided from the `named` colors list. + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGB::named(RED); + /// let green = RGB::named((0, 255, 0)); + /// ``` #[inline] #[must_use] pub fn named(col: (u8, u8, u8)) -> Self { @@ -173,8 +219,22 @@ impl RGB { } /// Constructs from an HTML color code (e.g. "#eeffee") + /// + /// # Arguments + /// + /// * `code` - an HTML color notation (e.g. "#ffeeff") + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGB::from_hex("#FF0000"); + /// let green = RGB::from_hex("#00FF00"); + /// ``` /// /// # Errors + /// + /// See `HtmlColorConversionError` #[allow(clippy::cast_precision_loss)] pub fn from_hex>(code: S) -> Result { let mut full_code = code.as_ref().chars(); @@ -258,11 +318,7 @@ impl RGB { let v: f32 = max; let d = max - min; - let s = if max == 0.0 { - 0.0 - } else { - d / max - }; + let s = if max == 0.0 { 0.0 } else { d / max }; if (max - min).abs() < std::f32::EPSILON { h = 0.0; // Achromatic diff --git a/bracket-color/src/rgba.rs b/bracket-color/src/rgba.rs index 756fdb11..1247c71e 100755 --- a/bracket-color/src/rgba.rs +++ b/bracket-color/src/rgba.rs @@ -6,9 +6,13 @@ use std::ops; #[derive(PartialEq, Copy, Clone, Default, Debug)] /// Represents an R/G/B triplet, in the range 0..1 (32-bit float) pub struct RGBA { + /// The red component (0..1) pub r: f32, + /// The green component (0..1) pub g: f32, + /// The blue component (0..1) pub b: f32, + /// The alpha component (0..1), 0 is transparent, 1 is solid pub a: f32, } @@ -105,6 +109,22 @@ impl RGBA { } /// Constructs a new RGB color, from 3 32-bit floats in the range 0..1 + /// + /// # Arguments + /// + /// * `r` - the red component (0..1) + /// * `g` - the green component (0..1) + /// * `b` - the blue component (0..1) + /// * `a` - the alpha component (0..1). 0 is transparent, 1 is solid. + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGBA::from_f32(1.0, 0.0, 0.0, 1.0); + /// let green = RGBA::from_f32(0.0, 1.0, 0.0, 1.0); + /// let invisible = RGBA::from_f32(0.0, 0.0, 0.0, 0.0); + /// ``` #[inline] #[must_use] pub fn from_f32(r: f32, g: f32, b: f32, a: f32) -> Self { @@ -121,6 +141,21 @@ impl RGBA { } /// Constructs a new RGB color, from 3 bytes in the range 0..255 + /// + /// # Arguments + /// + /// * `r` - the red component, ranged from 0 to 255 + /// * `g` - the green component, ranged from 0 to 255 + /// * `b` - the blue component, ranged from 0 to 255 + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGBA::from_u8(255, 0, 0, 255); + /// let green = RGBA::from_u8(0, 255, 0, 255); + /// let invisible = RGBA::from_u8(0, 0, 0, 0); + /// ``` #[inline] #[must_use] pub fn from_u8(r: u8, g: u8, b: u8, a: u8) -> Self { @@ -133,6 +168,18 @@ impl RGBA { } /// Construct an RGB color from a tuple of u8, or a named constant + /// + /// # Arguments + /// + /// * `col` a tuple of three `u8` values. See `from_u8`. These are usually provided from the `named` colors list. + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGBA::named(RED); + /// let green = RGBA::named((0, 255, 0)); + /// ``` #[inline] #[must_use] pub fn named(col: (u8, u8, u8)) -> Self { @@ -141,7 +188,21 @@ impl RGBA { /// Constructs from an HTML color code (e.g. "#eeffeeff") /// + /// # Arguments + /// + /// * `code` - an HTML color notation (e.g. "#ffeeffff") + /// + /// # Example + /// + /// ```rust + /// use bracket_color::prelude::*; + /// let red = RGBA::from_hex("#FF0000FF"); + /// let green = RGBA::from_hex("#00FF00FF"); + /// ``` + /// /// # Errors + /// + /// See `HtmlColorConversionError` #[allow(clippy::cast_precision_loss)] pub fn from_hex>(code: S) -> Result { let mut full_code = code.as_ref().chars(); @@ -233,10 +294,11 @@ impl RGBA { RGB::from_f32(self.r, self.g, self.b) } + /// Converts an RGBA to an array of `f32`, useful in Bevy. #[cfg(feature = "bevy")] #[must_use] pub fn as_rgba_f32(&self) -> [f32; 4] { - [self.r, self.g, self.b, self.a] + bevy::prelude::Color::as_linear_rgba_f32([self.r, self.g, self.b, self.a].into()) } /// Applies a quick grayscale conversion to the color diff --git a/bracket-embedding/Cargo.toml b/bracket-embedding/Cargo.toml index 5376efa6..ccbce62f 100644 --- a/bracket-embedding/Cargo.toml +++ b/bracket-embedding/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-embedding" -version = "0.8.0" -edition = "2018" -publish = false +version = "0.8.7" +edition = "2021" +publish = true description = "Provides resource embedding services for bracket-lib" homepage = "https://github.com/thebracket/bracket-lib" repository = "https://github.com/thebracket/bracket-lib" diff --git a/bracket-embedding/README.md b/bracket-embedding/README.md new file mode 100644 index 00000000..d1548787 --- /dev/null +++ b/bracket-embedding/README.md @@ -0,0 +1,17 @@ +# Bracket-embedding + +`bracket-lib` includes a system for embedding resources inside your binary (particularly useful for wasm builds). +This crate provides the supporting infrastructure for the embedding. It's not a lot of use on its own. + +## Example of use + +```rust +use bracket_embedding::prelude::*; + +embedded_resource!(SOURCE_FILE, "embedding.rs"); + +fn main() { + // This helper macro links the above embedding, allowing it to be accessed as a resource from various parts of the program. + link_resource!(SOURCE_FILE, "embedding.rs"); +} +``` diff --git a/bracket-embedding/resources/terminal8x8.png b/bracket-embedding/resources/terminal8x8.png new file mode 100644 index 00000000..4e405544 Binary files /dev/null and b/bracket-embedding/resources/terminal8x8.png differ diff --git a/bracket-embedding/resources/vga8x16.png b/bracket-embedding/resources/vga8x16.png new file mode 100644 index 00000000..913e32c3 Binary files /dev/null and b/bracket-embedding/resources/vga8x16.png differ diff --git a/bracket-embedding/src/embedding.rs b/bracket-embedding/src/embedding.rs index ac9b5c6d..749027cf 100644 --- a/bracket-embedding/src/embedding.rs +++ b/bracket-embedding/src/embedding.rs @@ -1,20 +1,25 @@ -use std::collections::HashMap; +use lazy_static::lazy_static; use parking_lot::Mutex; -use lazy_static::*; +use std::collections::HashMap; -const TERMINAL_8_8_BYTES: &[u8] = include_bytes!("../../bracket-terminal/resources/terminal8x8.png"); -const TERMINAL_8_16_BYTES: &[u8] = include_bytes!("../../bracket-terminal/resources/vga8x16.png"); +// These are included by default in `bracket-terminal`. +const TERMINAL_8_8_BYTES: &[u8] = + include_bytes!("../resources/terminal8x8.png"); +const TERMINAL_8_16_BYTES: &[u8] = include_bytes!("../resources/vga8x16.png"); lazy_static! { pub static ref EMBED: Mutex = Mutex::new(Dictionary::new()); } +/// Stores a dictionary of resources, generally added via `embedded_resource!` and `link_resource!` macros. #[derive(Default)] pub struct Dictionary { entries: HashMap, } impl Dictionary { + /// Create a new, empty dictionary. + #[must_use] pub fn new() -> Dictionary { let mut dict = Dictionary { entries: HashMap::new(), @@ -24,11 +29,13 @@ impl Dictionary { dict } + /// Request a resource, returning either a byte array or `None`. + #[must_use] pub fn get_resource(&self, path: String) -> Option<&'static [u8]> { - let fixed_path = if std::path::MAIN_SEPARATOR != '/' { - path.replace(std::path::MAIN_SEPARATOR, "/") + let fixed_path = if std::path::MAIN_SEPARATOR == '/' { + path } else { - path + path.replace(std::path::MAIN_SEPARATOR, "/") }; if self.entries.contains_key(&fixed_path) { @@ -37,6 +44,7 @@ impl Dictionary { None } + /// Insert a resource into the dictionary. pub fn add_resource(&mut self, path: String, bytes: &'static [u8]) { self.entries.insert(path, bytes); } diff --git a/bracket-embedding/src/lib.rs b/bracket-embedding/src/lib.rs index 586a3210..7f105f98 100644 --- a/bracket-embedding/src/lib.rs +++ b/bracket-embedding/src/lib.rs @@ -1,3 +1,24 @@ +//! The `bracket-embedding` crate is used to provide resource embedding. +//! This allows you to include binary assets inside your program when shipping, +//! with no external files. This can be especially useful for WASM builds. +//! +//! For example: +//! +//! ```rust +//! use bracket_embedding::prelude::*; +//! +//! embedded_resource!(SOURCE_FILE, "embedding.rs"); +//! +//! fn main() { +//! // This helper macro links the above embedding, allowing it to be accessed as a resource from various parts of the program. +//! link_resource!(SOURCE_FILE, "embedding.rs"); +//! } +//! ``` +//! +//! This crate isn't very useful on its own, but is heavily used by the other parts of `bracket-lib`. + +#![warn(clippy::all, clippy::pedantic, clippy::cargo)] +#![allow(clippy::needless_doctest_main)] mod embedding; pub mod prelude { @@ -5,6 +26,27 @@ pub mod prelude { pub use crate::{embedded_resource, link_resource}; } +/// Declare an embedded resource. +/// +/// # Arguments +/// +/// * `resource_name` - a constant that will represent the resource. +/// * `filename` - the path to the file to embed. +/// +/// Once embedded, you need to use `link_resource` to make it available. +/// +/// # Example +/// +/// ```rust +/// use bracket_embedding::prelude::*; +/// +/// embedded_resource!(SOURCE_FILE, "embedding.rs"); +/// +/// fn main() { +/// // This helper macro links the above embedding, allowing it to be accessed as a resource from various parts of the program. +/// link_resource!(SOURCE_FILE, "embedding.rs"); +/// } +/// ``` #[macro_export] macro_rules! embedded_resource { ($resource_name : ident, $filename : expr) => { @@ -12,6 +54,28 @@ macro_rules! embedded_resource { }; } +/// Link an embedded resource, making it available to `bracket-lib` via the resources +/// system. +/// +/// # Arguments +/// +/// * `resource_name` - a constant that will represent the resource. +/// * `filename` - the path to the file to embed. +/// +/// The resource must be previously declared with `embedded_resource!`. +/// +/// # Example +/// +/// ```rust +/// use bracket_embedding::prelude::*; +/// +/// embedded_resource!(SOURCE_FILE, "embedding.rs"); +/// +/// fn main() { +/// // This helper macro links the above embedding, allowing it to be accessed as a resource from various parts of the program. +/// link_resource!(SOURCE_FILE, "embedding.rs"); +/// } +/// ``` #[macro_export] macro_rules! link_resource { ($resource_name : ident, $filename : expr) => { diff --git a/bracket-geometry/Cargo.toml b/bracket-geometry/Cargo.toml index 729cb8cb..3e274a6e 100755 --- a/bracket-geometry/Cargo.toml +++ b/bracket-geometry/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-geometry" -version = "0.8.3" +version = "0.8.8" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "Geometry utilities. Rect, lines, circles, distance calculations. Part of the bracket-lib family." homepage = "https://github.com/thebracket/bracket-lib" @@ -13,9 +13,11 @@ categories = ["game-engines", "graphics"] license = "MIT" [dependencies] -ultraviolet = "~0.9" -serde = { version = "~1.0.110", features = ["derive"], optional = true } -specs = { version = "~0", optional = true } +serde = { version = "~1.0.139", features = ["derive"], optional = true } +specs = { version = "~0.18.0", optional = true } + +bevy = { version = "0.11.0", optional = true } +ultraviolet = "~0.9.0" [dev-dependencies] -crossterm = "~0.24" +crossterm = "~0.25" diff --git a/bracket-geometry/README.md b/bracket-geometry/README.md index 946583d2..a24313d7 100755 --- a/bracket-geometry/README.md +++ b/bracket-geometry/README.md @@ -10,7 +10,7 @@ You can include it in your project by adding the following to your `Cargo.toml` ```toml [dependencies] -bracket-geometry = "0.8.2" +bracket-geometry = "~0.8" ``` ## Point2D diff --git a/bracket-geometry/src/angle.rs b/bracket-geometry/src/angle.rs index 2bbd1106..46604728 100755 --- a/bracket-geometry/src/angle.rs +++ b/bracket-geometry/src/angle.rs @@ -11,12 +11,22 @@ pub struct Degrees(pub f32); pub struct Radians(pub f32); impl Degrees { + /// Creates a new angle in degrees. + /// + /// # Arguments + /// + /// * `angle` - the angle to represent, in degrees. pub fn new(angle: f32) -> Self { Self(angle) } } impl Radians { + /// Creates a new angle in radians. + /// + /// # Arguments + /// + /// * `angle` - the angle to represent, in radians. pub fn new(angle: f32) -> Self { Self(angle) } diff --git a/bracket-geometry/src/circle_bresenham.rs b/bracket-geometry/src/circle_bresenham.rs index 9500e804..e11b8e6f 100755 --- a/bracket-geometry/src/circle_bresenham.rs +++ b/bracket-geometry/src/circle_bresenham.rs @@ -13,6 +13,12 @@ pub struct BresenhamCircle { } impl BresenhamCircle { + /// Creates a new circle, using the Bresenham Circle algorithm. + /// + /// # Arguments + /// + /// * `center` - the center of the circle. + /// * `radius` - the radius of the desired circle. #[inline] #[allow(dead_code)] pub fn new(center: Point, radius: i32) -> Self { @@ -76,6 +82,12 @@ pub struct BresenhamCircleNoDiag { } impl BresenhamCircleNoDiag { + /// Creates a Bresenham Circle without allowing diagonal gaps. + /// + /// # Arguments + /// + /// * `center` - the center of the circle + /// * `radius` - the radius of the circle #[inline] #[allow(dead_code)] pub fn new(center: Point, radius: i32) -> Self { diff --git a/bracket-geometry/src/distance.rs b/bracket-geometry/src/distance.rs index dbb3c844..7825d3e3 100755 --- a/bracket-geometry/src/distance.rs +++ b/bracket-geometry/src/distance.rs @@ -4,10 +4,15 @@ use std::cmp::{max, min}; /// Enumeration of available 2D Distance algorithms #[derive(Clone, Copy)] pub enum DistanceAlg { + /// Use the Pythagoras algorithm for determining distance - sqrt(A^2 + B^2) Pythagoras, + /// Us the Pythagoras algorithm for distance, but omitting the square-root for a faster but squared result. PythagorasSquared, + /// Use Manhattan distance (distance up plus distance along) Manhattan, + /// Use Chebyshev distance (like Manhattan, but adds one to each entry) Chebyshev, + /// Use a diagonal distance, the max of the x and y distances Diagonal, } diff --git a/bracket-geometry/src/lib.rs b/bracket-geometry/src/lib.rs index 48866768..38445276 100755 --- a/bracket-geometry/src/lib.rs +++ b/bracket-geometry/src/lib.rs @@ -1,3 +1,6 @@ +#![warn(clippy::all, clippy::pedantic, clippy::cargo)] +#![warn(missing_docs)] + //! This crate is part of the `bracket-lib` family. //! //! It provides point (2D and 3D), rectangle, line and circle plotting functionality. @@ -71,6 +74,7 @@ mod point3; mod rect; mod rectf; +/// Export the library into a prelude for convenience. See the main library declaration. pub mod prelude { pub use crate::angle::*; pub use crate::angles::*; diff --git a/bracket-geometry/src/line_bresenham.rs b/bracket-geometry/src/line_bresenham.rs index d112f621..7a5c6a15 100755 --- a/bracket-geometry/src/line_bresenham.rs +++ b/bracket-geometry/src/line_bresenham.rs @@ -1,4 +1,4 @@ -//! Original at: https://github.com/mbr/bresenham-rs/blob/master/src/lib.rs +//! Original at: //! Modified to use more BTerm-friendly types //! use crate::prelude::Point; @@ -18,7 +18,7 @@ pub struct Bresenham { struct Octant(u8); impl Octant { - /// adapted from http://codereview.stackexchange.com/a/95551 + /// adapted from #[inline] fn from_points(start: Point, end: Point) -> Octant { let mut dx = end.x - start.x; @@ -36,11 +36,11 @@ impl Octant { let tmp = dx; dx = dy; dy = -tmp; - octant += 2 + octant += 2; } if dx < dy { - octant += 1 + octant += 1; } Octant(octant) @@ -100,6 +100,24 @@ impl Bresenham { octant, } } + + /// Return the next point without checking if we are past `end`. + #[inline] + pub fn advance(&mut self) -> Point { + let p = Point::new(self.x, self.y); + + if self.diff >= 0 { + self.y += 1; + self.diff -= self.dx; + } + + self.diff += self.dy; + + // loop inc + self.x += 1; + + self.octant.from_octant0(p) + } } impl Iterator for Bresenham { @@ -108,80 +126,138 @@ impl Iterator for Bresenham { #[inline] fn next(&mut self) -> Option { if self.x >= self.x1 { - return None; - } - - let p = Point::new(self.x, self.y); - - if self.diff >= 0 { - self.y += 1; - self.diff -= self.dx; + None + } else { + Some(self.advance()) } + } +} - self.diff += self.dy; +/// New type over `Bresenham` which include the `end` points when iterated over. +pub struct BresenhamInclusive(Bresenham); +impl BresenhamInclusive { + /// Creates a new iterator. Yields points `start..=end`. + #[inline] + pub fn new(start: Point, end: Point) -> Self { + Self(Bresenham::new(start, end)) + } - // loop inc - self.x += 1; + /// Return the next point without checking if we are past `end`. + #[inline] + pub fn advance(&mut self) -> Point { + self.0.advance() + } +} +impl Iterator for BresenhamInclusive { + type Item = Point; - Some(self.octant.from_octant0(p)) + #[inline] + fn next(&mut self) -> Option { + if self.0.x > self.0.x1 { + None + } else { + Some(self.0.advance()) + } } } #[cfg(test)] mod tests { - use super::{Bresenham, Point}; + use super::*; use std::vec::Vec; #[test] - fn test_wp_example() { - let bi = Bresenham::new(Point::new(0, 1), Point::new(6, 4)); + fn test_empty() { + let bi = Bresenham::new(Point::new(0, 0), Point::new(0, 0)); let res: Vec<_> = bi.collect(); + assert_eq!(res, []); - assert_eq!( - res, - [ - Point::new(0, 1), - Point::new(1, 1), - Point::new(2, 2), - Point::new(3, 2), - Point::new(4, 3), - Point::new(5, 3) - ] - ) + let bi = BresenhamInclusive::new(Point::new(0, 0), Point::new(0, 0)); + let res: Vec<_> = bi.collect(); + assert_eq!(res, [Point::new(0, 0)]); + + let mut bi = BresenhamInclusive::new(Point::new(0, 0), Point::new(0, 0)); + bi.advance(); + let res: Vec<_> = bi.collect(); + assert_eq!(res, []); } #[test] - fn test_inverse_wp() { - let bi = Bresenham::new(Point::new(6, 4), Point::new(0, 1)); + fn test_wp_example() { + let start = Point::new(0, 1); + let end = Point::new(6, 4); + + let bi = Bresenham::new(start, end); + let res: Vec<_> = bi.collect(); + let mut expected = vec![ + Point::new(0, 1), + Point::new(1, 1), + Point::new(2, 2), + Point::new(3, 2), + Point::new(4, 3), + Point::new(5, 3) + ]; + assert_eq!(res, expected); + + let bi = BresenhamInclusive::new(start, end); let res: Vec<_> = bi.collect(); + expected.push(end); + assert_eq!(res, expected); + } - assert_eq!( - res, - [ - Point::new(6, 4), - Point::new(5, 4), - Point::new(4, 3), - Point::new(3, 3), - Point::new(2, 2), - Point::new(1, 2) - ] - ) + #[test] + fn test_inverse_wp() { + let start = Point::new(6, 4); + let end = Point::new(0, 1); + + let bi = Bresenham::new(start, end); + let res: Vec<_> = bi.collect(); + let mut expected = vec![ + Point::new(6, 4), + Point::new(5, 4), + Point::new(4, 3), + Point::new(3, 3), + Point::new(2, 2), + Point::new(1, 2) + ]; + assert_eq!(res, expected); + + let bi = BresenhamInclusive::new(start, end); + let res: Vec<_> = bi.collect(); + expected.push(end); + assert_eq!(res, expected); } #[test] fn test_straight_hline() { - let bi = Bresenham::new(Point::new(2, 3), Point::new(5, 3)); + let start = Point::new(2, 3); + let end = Point::new(5, 3); + + let bi = Bresenham::new(start, end); let res: Vec<_> = bi.collect(); + let mut expected = vec![Point::new(2, 3), Point::new(3, 3), Point::new(4, 3)]; + assert_eq!(res, expected); - assert_eq!(res, [Point::new(2, 3), Point::new(3, 3), Point::new(4, 3)]); + let bi = BresenhamInclusive::new(start, end); + let res: Vec<_> = bi.collect(); + expected.push(end); + assert_eq!(res, expected); } #[test] fn test_straight_vline() { - let bi = Bresenham::new(Point::new(2, 3), Point::new(2, 6)); + let start = Point::new(2, 3); + let end = Point::new(2, 6); + + let bi = Bresenham::new(start, end); let res: Vec<_> = bi.collect(); + let mut expected = vec![Point::new(2, 3), Point::new(2, 4), Point::new(2, 5)]; + assert_eq!(res, expected); - assert_eq!(res, [Point::new(2, 3), Point::new(2, 4), Point::new(2, 5)]); + let bi = BresenhamInclusive::new(start, end); + let res: Vec<_> = bi.collect(); + expected.push(end); + assert_eq!(res, expected); } #[test] diff --git a/bracket-geometry/src/line_vector.rs b/bracket-geometry/src/line_vector.rs index f9eb80df..1c80652e 100755 --- a/bracket-geometry/src/line_vector.rs +++ b/bracket-geometry/src/line_vector.rs @@ -2,6 +2,8 @@ use crate::prelude::Point; use core::iter::Iterator; use ultraviolet::Vec2; +/// Define a line using a fast 2D vector. It may not be as pixel-perfect as Bresenham, but with vectorization it is sometimes +/// faster for a quick line solution. pub struct VectorLine { end: Point, current_pos: Vec2, @@ -11,6 +13,7 @@ pub struct VectorLine { } impl VectorLine { + /// Define a vector line between two points. pub fn new(start: Point, end: Point) -> Self { let current_pos = Vec2::new(start.x as f32 + 0.5, start.y as f32 + 0.5); let destination = Vec2::new(end.x as f32 + 0.5, end.y as f32 + 0.5); diff --git a/bracket-geometry/src/lines.rs b/bracket-geometry/src/lines.rs index f06b5323..c239ed6d 100755 --- a/bracket-geometry/src/lines.rs +++ b/bracket-geometry/src/lines.rs @@ -2,7 +2,9 @@ use crate::prelude::{Bresenham, DistanceAlg, Point}; /// Enumeration of available 2D Distance algorithms pub enum LineAlg { + /// Use Bresenham's rasterization algorithm for line definition Bresenham, + /// Use a vector approach to line solving. Vector, } diff --git a/bracket-geometry/src/point.rs b/bracket-geometry/src/point.rs index d885d55b..e758cd26 100755 --- a/bracket-geometry/src/point.rs +++ b/bracket-geometry/src/point.rs @@ -2,13 +2,16 @@ use std::convert::{From, TryInto}; use std::ops; use ultraviolet::Vec2; +/// A 2D floating-point position. pub type PointF = Vec2; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)] /// Helper struct defining a 2D point in space. pub struct Point { + /// The point's X location pub x: i32, + /// The point's Y location pub y: i32, } @@ -17,6 +20,11 @@ impl specs::prelude::Component for Point { type Storage = specs::prelude::VecStorage; } +#[cfg(feature = "bevy")] +impl bevy::ecs::component::Component for Point { + type Storage = bevy::ecs::component::TableStorage; +} + impl Point { /// Create a new point from an x/y coordinate. #[inline] @@ -32,18 +40,19 @@ impl Point { } /// Create a new point from i32, this can be constant + #[must_use] pub const fn constant(x: i32, y: i32) -> Self { Point { x, y } } - // Create a zero point + /// Create a zero point #[inline] pub fn zero() -> Self { Point { x: 0, y: 0 } } #[inline] - // Create a point from a tuple of two i32s + /// Create a point from a tuple of two i32s pub fn from_tuple(t: (T, T)) -> Self where T: TryInto, @@ -53,6 +62,7 @@ impl Point { #[inline] /// Helper for map index conversion + #[must_use] pub fn to_index(self, width: T) -> usize where T: TryInto, @@ -64,11 +74,17 @@ impl Point { } /// Converts the point to an i32 tuple + #[must_use] pub fn to_tuple(self) -> (i32, i32) { (self.x, self.y) } /// Converts the point to a usize tuple + /// + /// # Panics + /// + /// This can panic if X or Y are not convertible to a `usize`. + #[must_use] pub fn to_unsigned_tuple(self) -> (usize, usize) { ( self.x.try_into().ok().unwrap(), @@ -77,6 +93,7 @@ impl Point { } /// Converts the point to an UltraViolet vec2 + #[must_use] pub fn to_vec2(self) -> Vec2 { Vec2::new(self.x as f32, self.y as f32) } @@ -89,13 +106,13 @@ impl Point { } */ - /// Creates a point from an UltraViolet vec2 + /// Creates a point from an `UltraViolet` vec2 pub fn from_vec2(v: Vec2) -> Self { Self::new(v.x as i32, v.y as i32) } /* - /// Creates a point from an UltraViolet vec2i + /// Creates a point from an `UltraViolet` vec2i pub fn from_vec2i(v: Vec2i) -> Self { Self::new(v.x, v.y) } diff --git a/bracket-geometry/src/point3.rs b/bracket-geometry/src/point3.rs index 095ac8ff..985cebc4 100755 --- a/bracket-geometry/src/point3.rs +++ b/bracket-geometry/src/point3.rs @@ -6,8 +6,11 @@ use ultraviolet::Vec3; #[derive(Eq, PartialEq, Copy, Clone, Debug)] /// Helper struct defining a 2D point in space. pub struct Point3 { + /// The 3D point's X location pub x: i32, + /// The 3D point's Y location pub y: i32, + /// The 3D point's Z location pub z: i32, } @@ -16,6 +19,11 @@ impl specs::prelude::Component for Point3 { type Storage = specs::prelude::VecStorage; } +#[cfg(feature = "bevy")] +impl bevy::ecs::component::Component for Point3 { + type Storage = bevy::ecs::component::TableStorage; +} + impl Point3 { /// Create a new point from an x/y/z coordinate. pub fn new(x: T, y: T, z: T) -> Self @@ -30,6 +38,7 @@ impl Point3 { } /// Create a point from an x/y/z tuple + #[must_use] pub fn from_tuple(t: (i32, i32, i32)) -> Self { Self { x: t.0, diff --git a/bracket-geometry/src/rect.rs b/bracket-geometry/src/rect.rs index bab3802e..4910ee30 100755 --- a/bracket-geometry/src/rect.rs +++ b/bracket-geometry/src/rect.rs @@ -3,12 +3,17 @@ use std::collections::HashSet; use std::convert::TryInto; use std::ops; +/// Defines a two-dimensional rectangle. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub struct Rect { + /// The X position of the first point (typically the left) pub x1: i32, + /// The X position of the second point (typically the right) pub x2: i32, + /// The Y position of the first point (typically the top) pub y1: i32, + /// The Y position of the second point (typically the bottom) pub y2: i32, } @@ -24,7 +29,7 @@ impl Default for Rect { } impl Rect { - // Create a new rectangle, specifying X/Y Width/Height + /// Create a new rectangle, specifying X/Y Width/Height pub fn with_size(x: T, y: T, w: T, h: T) -> Rect where T: TryInto, @@ -39,7 +44,7 @@ impl Rect { } } - // Create a new rectangle, specifying exact dimensions + /// Create a new rectangle, specifying exact dimensions pub fn with_exact(x1: T, y1: T, x2: T, y2: T) -> Rect where T: TryInto, @@ -52,7 +57,7 @@ impl Rect { } } - // Creates a zero rectangle + /// Creates a zero rectangle pub fn zero() -> Rect { Rect { x1: 0, @@ -62,22 +67,25 @@ impl Rect { } } - // Returns true if this overlaps with other + /// Returns true if this overlaps with other + #[must_use] pub fn intersect(&self, other: &Rect) -> bool { self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1 } - // Returns the center of the rectangle + /// Returns the center of the rectangle + #[must_use] pub fn center(&self) -> Point { Point::new((self.x1 + self.x2) / 2, (self.y1 + self.y2) / 2) } - // Returns true if a point is inside the rectangle + /// Returns true if a point is inside the rectangle + #[must_use] pub fn point_in_rect(&self, point: Point) -> bool { point.x >= self.x1 && point.x < self.x2 && point.y >= self.y1 && point.y < self.y2 } - // Calls a function for each x/y point in the rectangle + /// Calls a function for each x/y point in the rectangle pub fn for_each(&self, mut f: F) where F: FnMut(Point), @@ -89,7 +97,8 @@ impl Rect { } } - // Gets a set of all tiles in the rectangle + /// Gets a set of all tiles in the rectangle + #[must_use] pub fn point_set(&self) -> HashSet { let mut result = HashSet::new(); for y in self.y1..self.y2 { @@ -100,12 +109,14 @@ impl Rect { result } - // Returns the rectangle's width + /// Returns the rectangle's width + #[must_use] pub fn width(&self) -> i32 { i32::abs(self.x2 - self.x1) } - // Returns the rectangle's height + /// Returns the rectangle's height + #[must_use] pub fn height(&self) -> i32 { i32::abs(self.y2 - self.y1) } diff --git a/bracket-geometry/src/rectf.rs b/bracket-geometry/src/rectf.rs index bace3976..27060ab0 100755 --- a/bracket-geometry/src/rectf.rs +++ b/bracket-geometry/src/rectf.rs @@ -2,12 +2,17 @@ use crate::prelude::PointF; use std::convert::TryInto; use std::ops; +/// Defines a rectangle with floating-point coordinates. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RectF { + /// The X position of the first point (typically the left) pub x1: f32, + /// The X position of the second point (typically the right) pub x2: f32, + /// The Y position of the first point (typically the top) pub y1: f32, + /// The Y position of the second point (typically the bottom) pub y2: f32, } @@ -23,7 +28,7 @@ impl Default for RectF { } impl RectF { - // Create a new rectangle, specifying X/Y Width/Height + /// Create a new rectangle, specifying X/Y Width/Height pub fn with_size(x: T, y: T, w: T, h: T) -> RectF where T: TryInto, @@ -38,7 +43,7 @@ impl RectF { } } - // Create a new rectangle, specifying exact dimensions + /// Create a new rectangle, specifying exact dimensions pub fn with_exact(x1: T, y1: T, x2: T, y2: T) -> RectF where T: TryInto, @@ -51,7 +56,8 @@ impl RectF { } } - // Creates a zero rectangle + /// Creates a zero rectangle + #[must_use] pub fn zero() -> RectF { RectF { x1: 0.0, @@ -61,12 +67,14 @@ impl RectF { } } - // Returns true if this overlaps with other + /// Returns true if this overlaps with other + #[must_use] pub fn intersect(&self, other: &RectF) -> bool { self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1 } - // Returns the center of the rectangle + /// Returns the center of the rectangle + #[must_use] pub fn center(&self) -> PointF { PointF { x: (self.x1 + self.x2) / 2.0, @@ -74,17 +82,20 @@ impl RectF { } } - // Returns true if a point is inside the rectangle + /// Returns true if a point is inside the rectangle + #[must_use] pub fn point_in_rect(&self, point: PointF) -> bool { point.x >= self.x1 && point.x < self.x2 && point.y >= self.y1 && point.y < self.y2 } - // Returns the rectangle's width + /// Returns the rectangle's width + #[must_use] pub fn width(&self) -> f32 { f32::abs(self.x2 - self.x1) } - // Returns the rectangle's height + /// Returns the rectangle's height + #[must_use] pub fn height(&self) -> f32 { f32::abs(self.y2 - self.y1) } diff --git a/bracket-noise/Cargo.toml b/bracket-noise/Cargo.toml index 58261eb7..fce36069 100755 --- a/bracket-noise/Cargo.toml +++ b/bracket-noise/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-noise" -version = "0.8.2" +version = "0.8.7" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "Rust port of Auburn's amazing FastNoise library. Part of the bracket-lib family." homepage = "https://github.com/thebracket/bracket-lib" @@ -15,8 +15,8 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bracket-random = { path = "../bracket-random", version = "~0.8.2" } +bracket-random = { path = "../bracket-random", version = "~0.8" } [dev-dependencies] -crossterm = "~0.24" -bracket-color = { path = "../bracket-color", version = "~0.8.2", features = [ "palette" ] } +crossterm = "~0.25" +bracket-color = { path = "../bracket-color", version = "~0.8", features = [ "palette" ] } diff --git a/bracket-noise/README.md b/bracket-noise/README.md index a23db6c5..5c1a7205 100755 --- a/bracket-noise/README.md +++ b/bracket-noise/README.md @@ -8,7 +8,7 @@ To obtain `bracket-noise`, include the following in your `Cargo.toml` file: ```toml [dependencies] -bracket-noise = "0.8.2" +bracket-noise = "~0.8" ``` ## Examples diff --git a/bracket-noise/src/fastnoise.rs b/bracket-noise/src/fastnoise.rs index e8ffce64..aea3d8a7 100755 --- a/bracket-noise/src/fastnoise.rs +++ b/bracket-noise/src/fastnoise.rs @@ -5,7 +5,7 @@ use bracket_random::prelude::RandomNumberGenerator; -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] /// Type of noise to generate pub enum NoiseType { Value, @@ -20,7 +20,7 @@ pub enum NoiseType { CubicFractal, } -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] /// Interpolation function to use pub enum Interp { Linear, @@ -28,7 +28,7 @@ pub enum Interp { Quintic, } -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] /// Fractal function to use pub enum FractalType { FBM, @@ -36,7 +36,7 @@ pub enum FractalType { RigidMulti, } -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] /// Cellular noise distance function to use pub enum CellularDistanceFunction { Euclidean, @@ -44,7 +44,7 @@ pub enum CellularDistanceFunction { Natural, } -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] /// What type of cellular noise result do you want pub enum CellularReturnType { CellValue, diff --git a/bracket-pathfinding/Cargo.toml b/bracket-pathfinding/Cargo.toml index 877bbb1c..50f631c1 100755 --- a/bracket-pathfinding/Cargo.toml +++ b/bracket-pathfinding/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-pathfinding" -version = "0.8.4" +version = "0.8.7" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "Pathfinding and field-of view utilities. A Star, Dijkstra. Part of the bracket-lib family." homepage = "https://github.com/thebracket/bracket-lib" @@ -18,17 +18,17 @@ license = "MIT" threaded = ["rayon"] [dependencies] -bracket-geometry = { path = "../bracket-geometry", version = "~0.8.2" } -bracket-algorithm-traits = { path = "../bracket-algorithm-traits", version = "~0.8.2" } +bracket-geometry = { path = "../bracket-geometry", version = "~0.8" } +bracket-algorithm-traits = { path = "../bracket-algorithm-traits", version = "~0.8" } num-rational = { version = "0.4", default-features = false, features = ["std"] } rayon = { version = "1.5.0", optional = true } smallvec = "~1" [dev-dependencies] -crossterm = "~0.24" -bracket-random = { path = "../bracket-random", version = "0.8.2" } -bracket-color = { path = "../bracket-color", version = "~0.8.2", features = [ "palette" ] } -criterion = "0.3.4" +crossterm = "~0.25" +bracket-random = { path = "../bracket-random", version = "0.8" } +bracket-color = { path = "../bracket-color", version = "~0.8", features = [ "palette" ] } +criterion = "~0.4" [[bench]] name = "fov_benchmark" diff --git a/bracket-pathfinding/examples/astar/common.rs b/bracket-pathfinding/examples/astar/common.rs index a906a810..382ee68c 100755 --- a/bracket-pathfinding/examples/astar/common.rs +++ b/bracket-pathfinding/examples/astar/common.rs @@ -28,8 +28,8 @@ pub fn flush_console() { pub const MAP_WIDTH: usize = 80; pub const MAP_HEIGHT: usize = 20; pub const MAP_TILES: usize = MAP_WIDTH * MAP_HEIGHT; -pub const START_POINT: Point = Point::constant(2, MAP_HEIGHT as i32 / 2); -pub const END_POINT: Point = Point::constant(MAP_WIDTH as i32 - 2, MAP_HEIGHT as i32 / 2); +pub const START_POINT: Point = Point::constant(2, 2); +pub const END_POINT: Point = Point::constant(MAP_WIDTH as i32 -2, MAP_HEIGHT as i32 - 2); pub struct Map { pub tiles: Vec, @@ -41,24 +41,11 @@ impl Map { tiles: vec!['.'; MAP_TILES], }; - // Add random walls + // Add walls for i in 0..15 { tiles.tiles[10 + i * MAP_WIDTH] = '#'; - tiles.tiles[18 + i * MAP_WIDTH] = '#'; + tiles.tiles[18 + (i+5) * MAP_WIDTH] = '#'; } - /* - let n_walls = 200; - let mut rng = RandomNumberGenerator::new(); - for _ in 0..n_walls { - let target = Point::new( - rng.roll_dice(1, MAP_WIDTH as i32 - 1), - rng.roll_dice(1, MAP_HEIGHT as i32 - 1), - ); - if target != START_POINT && target != END_POINT { - let idx = tiles.point2d_to_index(target); - tiles.tiles[idx] = '#'; - } - }*/ tiles } @@ -67,7 +54,7 @@ impl Map { let destination = loc + delta; if self.in_bounds(destination) { let idx = self.point2d_to_index(destination); - if self.tiles[idx] == '.' { + if self.tiles[idx] != '#' { Some(idx) } else { None diff --git a/bracket-pathfinding/examples/astar/main.rs b/bracket-pathfinding/examples/astar/main.rs index 18e4d056..378e1cff 100755 --- a/bracket-pathfinding/examples/astar/main.rs +++ b/bracket-pathfinding/examples/astar/main.rs @@ -16,6 +16,8 @@ fn main() { for loc in &path.steps { map.tiles[*loc] = '*'; } + } else { + panic!("No path found"); } // Draw the result diff --git a/bracket-pathfinding/examples/dijkstra_weighted/main.rs b/bracket-pathfinding/examples/dijkstra_weighted/main.rs index 81ee394a..43024343 100644 --- a/bracket-pathfinding/examples/dijkstra_weighted/main.rs +++ b/bracket-pathfinding/examples/dijkstra_weighted/main.rs @@ -1,8 +1,8 @@ mod common; use bracket_color::prelude::*; use bracket_pathfinding::prelude::*; -use common::*; use bracket_random::prelude::RandomNumberGenerator; +use common::*; fn main() { let map = Map::new(); diff --git a/bracket-pathfinding/src/astar.rs b/bracket-pathfinding/src/astar.rs index 60702bef..c46c15a9 100755 --- a/bracket-pathfinding/src/astar.rs +++ b/bracket-pathfinding/src/astar.rs @@ -109,7 +109,7 @@ impl AStar { let s = Node { idx, f: q.g + cost + distance_to_end, - g: q.g + cost, + g: cost, }; // If a node with the same position as successor is in the open list with a lower f, skip add diff --git a/bracket-pathfinding/src/dijkstra.rs b/bracket-pathfinding/src/dijkstra.rs index 238fd0e3..11a98797 100755 --- a/bracket-pathfinding/src/dijkstra.rs +++ b/bracket-pathfinding/src/dijkstra.rs @@ -135,15 +135,6 @@ impl DijkstraMap { RunThreaded::False } - #[cfg(feature = "threaded")] - fn build_helper_weighted(dm: &mut DijkstraMap, starts: &[(usize, f32)], map: &dyn BaseMap) -> RunThreaded { - if starts.len() >= THREADED_REQUIRED_STARTS { - DijkstraMap::build_parallel_weighted(dm, starts, map); - return RunThreaded::True; - } - RunThreaded::False - } - /// Builds the Dijkstra map: iterate from each starting point, to each exit provided by BaseMap's /// exits implementation. Each step adds cost to the current depth, and is discarded if the new /// depth is further than the current depth. @@ -265,60 +256,6 @@ impl DijkstraMap { } } - #[cfg(feature = "threaded")] - fn build_parallel(dm: &mut DijkstraMap, starts: &[usize], map: &dyn BaseMap) { - let mapsize: usize = (dm.size_x * dm.size_y) as usize; - let mut layers: Vec = Vec::with_capacity(starts.len()); - for start_chunk in starts.chunks(rayon::current_num_threads()) { - let mut layer = ParallelDm { - map: vec![MAX; mapsize], - max_depth: dm.max_depth, - starts: Vec::new(), - }; - layer - .starts - .extend(start_chunk.iter().copied().map(|x| x as usize)); - layers.push(layer); - } - - let exits: Vec> = (0..mapsize) - .map(|idx| map.get_available_exits(idx)) - .collect(); - - // Run each map in parallel - layers.par_iter_mut().for_each(|l| { - let mut open_list: VecDeque<(usize, f32)> = VecDeque::with_capacity(mapsize); - - for start in l.starts.iter().copied() { - open_list.push_back((start, 0.0)); - } - - while let Some((tile_idx, depth)) = open_list.pop_front() { - let exits = &exits[tile_idx]; - for (new_idx, add_depth) in exits { - let new_idx = *new_idx; - let new_depth = depth + add_depth; - let prev_depth = l.map[new_idx]; - if new_depth >= prev_depth { - continue; - } - if new_depth >= l.max_depth { - continue; - } - l.map[new_idx] = new_depth; - open_list.push_back((new_idx, new_depth)); - } - } - }); - - // Recombine down to a single result - for l in layers { - for i in 0..mapsize { - dm.map[i] = f32::min(dm.map[i], l.map[i]); - } - } - } - /// Helper for traversing maps as path-finding. Provides the index of the lowest available /// exit from the specified position index, or None if there isn't one. /// You would use this for pathing TOWARDS a starting node. diff --git a/bracket-pathfinding/src/field_of_view/mod.rs b/bracket-pathfinding/src/field_of_view/mod.rs index f71b02ec..66e74407 100644 --- a/bracket-pathfinding/src/field_of_view/mod.rs +++ b/bracket-pathfinding/src/field_of_view/mod.rs @@ -165,7 +165,9 @@ mod tests { let point = Point::new(x, y); assert!( r2 >= max_radius_sq || visible.contains(&point), - "Interior point ({:?}) not in FOV({})", point, radius + "Interior point ({:?}) not in FOV({})", + point, + radius ); } } diff --git a/bracket-random/Cargo.toml b/bracket-random/Cargo.toml index 0e730092..17ae6003 100755 --- a/bracket-random/Cargo.toml +++ b/bracket-random/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-random" -version = "0.8.3" +version = "0.8.7" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "Random number generator (xorshift based), focused on dice rolling. Optionally includes parsing of RPG-style dice strings (e.g. \"3d6+12\"). Part of the bracket-lib family." homepage = "https://github.com/thebracket/bracket-lib" @@ -22,7 +22,7 @@ rand_xorshift = { version = "0.3.0" } regex = { version = "1.3.6", optional = true } lazy_static = { version = "1.4.0", optional = true } serde_crate = { version = "~1.0.110", features = ["derive"], optional = true, package = "serde" } -rand = { version = "0.8.3", default-features = false } +rand = { version = "0.8", default-features = false } [target.'cfg(not(any(target_arch = "wasm32")))'.dependencies] getrandom = { version = "0.2.2" } @@ -32,7 +32,7 @@ js-sys = "0.3.48" wasm-bindgen = "0.2" [dev-dependencies] -criterion = "0.3.4" +criterion = "~0.4" serde_json = "~1.0" [[bench]] diff --git a/bracket-random/src/lib.rs b/bracket-random/src/lib.rs index f09482c7..4ceeac61 100755 --- a/bracket-random/src/lib.rs +++ b/bracket-random/src/lib.rs @@ -23,4 +23,4 @@ pub mod prelude { pub mod rand { pub use rand::*; -} \ No newline at end of file +} diff --git a/bracket-rex/Cargo.toml b/bracket-rex/Cargo.toml index 790c4cb8..54d3f286 100644 --- a/bracket-rex/Cargo.toml +++ b/bracket-rex/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-rex" -version = "0.8.0" -edition = "2018" -publish = false +version = "0.8.7" +edition = "2021" +publish = true description = "Load/save REX Paint files and utilize them in bracket-terminal projects." homepage = "https://github.com/thebracket/bracket-lib" repository = "https://github.com/thebracket/bracket-lib" @@ -14,5 +14,5 @@ license = "MIT" [dependencies] byteorder = "1.4.2" flate2 = "1.0.20" -bracket-color = { path = "../bracket-color", version = "~0.8.2", features = [ "palette" ] } +bracket-color = { path = "../bracket-color", version = "~0.8", features = [ "palette" ] } bracket-embedding = { path = "../bracket-embedding", version = "~0.8" } \ No newline at end of file diff --git a/bracket-rex/README.md b/bracket-rex/README.md new file mode 100644 index 00000000..1d053942 --- /dev/null +++ b/bracket-rex/README.md @@ -0,0 +1,4 @@ +# Bracket-Rex + +This crate separates out `bracket-lib`'s [Rex Paint](https://www.gridsagegames.com/rexpaint/) support. It's primarily used inside `bracket-lib`, but can be used separately. + diff --git a/bracket-rex/src/lib.rs b/bracket-rex/src/lib.rs index 08a49a0f..8b219790 100644 --- a/bracket-rex/src/lib.rs +++ b/bracket-rex/src/lib.rs @@ -4,4 +4,4 @@ mod xpcolor; pub mod prelude { pub use crate::rex::*; pub use crate::xpcolor::*; -} \ No newline at end of file +} diff --git a/bracket-rex/src/rex.rs b/bracket-rex/src/rex.rs index dbbb12d6..cde20633 100644 --- a/bracket-rex/src/rex.rs +++ b/bracket-rex/src/rex.rs @@ -102,7 +102,9 @@ impl XpFile { /// Helper to read from an BTerm resource pub fn from_resource(path: &str) -> io::Result { - let res = bracket_embedding::prelude::EMBED.lock().get_resource(path.to_string()); + let res = bracket_embedding::prelude::EMBED + .lock() + .get_resource(path.to_string()); match res { None => panic!("Unable to open resource"), Some(r) => { diff --git a/bracket-rex/src/xpcolor.rs b/bracket-rex/src/xpcolor.rs index 383eab75..98a5ee36 100644 --- a/bracket-rex/src/xpcolor.rs +++ b/bracket-rex/src/xpcolor.rs @@ -91,4 +91,4 @@ impl From for RGBA { fn from(xp: XpColor) -> Self { RGBA::from_u8(xp.r, xp.g, xp.b, 255) } -} \ No newline at end of file +} diff --git a/bracket-terminal/Cargo.toml b/bracket-terminal/Cargo.toml index 23f40932..064fc37d 100755 --- a/bracket-terminal/Cargo.toml +++ b/bracket-terminal/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-terminal" -version = "0.8.5" +version = "0.8.7" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "ASCII/Codepage 437 terminal emulator with a game loop. Defaults to OpenGL, also support WebGPU (for Vulkan/Metal/WGPU), Curses and Crossterm for output. Part of the bracket-lib family." homepage = "https://github.com/thebracket/bracket-lib" @@ -16,16 +16,16 @@ exclude = [ ] [dependencies] -bracket-color = { path = "../bracket-color", version = "~0.8.2", features = [ "palette" ] } -bracket-geometry = { path = "../bracket-geometry", version = "~0.8.3" } -bracket-rex = { path = "../bracket-rex", version = "~0.8.0" } -bracket-embedding = { path = "../bracket-embedding", version = "~0.8.0" } +bracket-color = { path = "../bracket-color", version = "~0.8", features = [ "palette" ] } +bracket-geometry = { path = "../bracket-geometry", version = "~0.8" } +bracket-rex = { path = "../bracket-rex", version = "~0.8" } +bracket-embedding = { path = "../bracket-embedding", version = "~0.8" } lazy_static = "1.4.0" object-pool = "0.5.3" -glow = { version = "0.10.0", optional = true } +glow = { version = "~0.11", optional = true } image = { version = "0.24", default-features = false, features = ["jpeg", "png"], optional = true } png = { version = "0.17", optional = true } -crossterm = { version = "~0.24", optional = true } +crossterm = { version = "~0.25", optional = true } pancurses = { version = "0.17", optional = true } ultraviolet = "~0.9" parking_lot = { version = "~0.12" } @@ -36,8 +36,8 @@ pollster = { version = "0.2", optional=true } bytemuck = {version = "1.4.0", optional=true } [target.'cfg(not(any(target_arch = "wasm32")))'.dependencies] -glutin = {version = "0.29", optional = true } -winit = { version = "0.27" } +glutin = {version = "~0.29", optional = true } +winit = { version = "~0.27" } spin_sleep = { version = "1.0.0", optional = true } [features] @@ -49,10 +49,10 @@ cross_term = [ "crossterm", "ctrlc" ] webgpu = [ "wgpu", "pollster", "image", "bytemuck", "png" ] [dev-dependencies] -bracket-random = { path = "../bracket-random", version = "~0.8.2" } -bracket-pathfinding = { path = "../bracket-pathfinding", version = "~0.8.4" } -bracket-noise = { path = "../bracket-noise", version = "~0.8.2" } -criterion = "0.3.4" +bracket-random = { path = "../bracket-random", version = "~0.8" } +bracket-pathfinding = { path = "../bracket-pathfinding", version = "~0.8" } +bracket-noise = { path = "../bracket-noise", version = "~0.8" } +criterion = "~0.4" [target.wasm32-unknown-unknown.dependencies] web-sys = { version = "0.3", features=["console", "Attr", "CanvasRenderingContext2d", "Document", "Element", "Event", @@ -60,9 +60,9 @@ web-sys = { version = "0.3", features=["console", "Attr", "CanvasRenderingContex "MouseEvent"] } wasm-bindgen = "0.2" wasm-timer = "0.1.0" -rand = { version = "0.8.3", default-features = false } +rand = { version = "0.8", default-features = false } console_error_panic_hook = "0.1.6" -winit = { version = "0.27" } +winit = { version = "0.26" } [[bench]] name = "batching_benchmark" diff --git a/bracket-terminal/examples/batch_z_order.rs b/bracket-terminal/examples/batch_z_order.rs index 34bb33d5..7c8d5b6c 100644 --- a/bracket-terminal/examples/batch_z_order.rs +++ b/bracket-terminal/examples/batch_z_order.rs @@ -10,13 +10,18 @@ struct State {} impl GameState for State { fn tick(&mut self, ctx: &mut BTerm) { let mut draw_batch = DrawBatch::new(); - draw_batch.print_color_with_z(Point::new(10, 10), "This is at always on top", ColorPair::new(YELLOW, BLUE), 1000); + draw_batch.print_color_with_z( + Point::new(10, 10), + "This is at always on top", + ColorPair::new(YELLOW, BLUE), + 1000, + ); for y in 0..50 { for x in 0..80 { draw_batch.set( Point::new(x, y), ColorPair::new(DARKGRAY, BLACK), - to_cp437('#') + to_cp437('#'), ); } } diff --git a/bracket-terminal/examples/flexible.rs b/bracket-terminal/examples/flexible.rs index 5310b27d..d425ca91 100755 --- a/bracket-terminal/examples/flexible.rs +++ b/bracket-terminal/examples/flexible.rs @@ -62,7 +62,6 @@ fn main() -> BError { .build()?; context.with_post_scanlines(true); - context.with_post_scanlines(true); let gs = State { x: 0.0, diff --git a/bracket-terminal/examples/native_gl.rs b/bracket-terminal/examples/native_gl.rs index 29f435cf..b5af4a39 100755 --- a/bracket-terminal/examples/native_gl.rs +++ b/bracket-terminal/examples/native_gl.rs @@ -1,6 +1,7 @@ use bracket_terminal::prelude::*; #[cfg(feature = "opengl")] use glow::HasContext; +use glow::{NativeVertexArray, NativeBuffer}; use std::mem; bracket_terminal::add_wasm_support!(); @@ -93,8 +94,8 @@ fn gl_render(gs: &mut dyn std::any::Any, gl: &glow::Context) { struct State { setup_gl: bool, my_shader: Option, - vao: Option, - vbo: Option, + vao: Option, + vbo: Option, } #[cfg(target_arch = "wasm32")] diff --git a/bracket-terminal/examples/twelve_by_twelve.rs b/bracket-terminal/examples/twelve_by_twelve.rs new file mode 100644 index 00000000..6ec90cde --- /dev/null +++ b/bracket-terminal/examples/twelve_by_twelve.rs @@ -0,0 +1,248 @@ +bracket_terminal::add_wasm_support!(); +use bracket_pathfinding::prelude::*; +use bracket_random::prelude::*; +use bracket_terminal::prelude::*; + +#[derive(PartialEq, Copy, Clone)] +enum TileType { + Wall, + Floor, +} + +#[derive(PartialEq, Copy, Clone)] +enum Mode { + Waiting, + Moving, +} + +struct State { + map: Vec, + player_position: usize, + visible: Vec, + mode: Mode, + path: NavigationPath, +} + +pub fn xy_idx(x: i32, y: i32) -> usize { + (y as usize * 80) + x as usize +} + +pub fn idx_xy(idx: usize) -> (i32, i32) { + (idx as i32 % 80, idx as i32 / 80) +} + +impl State { + pub fn new() -> State { + let mut state = State { + map: vec![TileType::Floor; 80 * 50], + player_position: xy_idx(40, 25), + visible: vec![false; 80 * 50], + mode: Mode::Waiting, + path: NavigationPath::new(), + }; + + for x in 0..80 { + state.map[xy_idx(x, 0)] = TileType::Wall; + state.map[xy_idx(x, 49)] = TileType::Wall; + } + for y in 0..50 { + state.map[xy_idx(0, y)] = TileType::Wall; + state.map[xy_idx(79, y)] = TileType::Wall; + } + + let mut rng = RandomNumberGenerator::new(); + + for _ in 0..1400 { + let x = rng.range(1, 79); + let y = rng.range(1, 49); + let idx = xy_idx(x, y); + if state.player_position != idx { + state.map[idx] = TileType::Wall; + } + } + + state + } + + pub fn is_exit_valid(&self, x: i32, y: i32) -> bool { + if x < 1 || x > 79 || y < 1 || y > 49 { + return false; + } + let idx = (y * 80) + x; + self.map[idx as usize] == TileType::Floor + } +} + +// Implement the game loop +impl GameState for State { + #[allow(non_snake_case)] + fn tick(&mut self, ctx: &mut BTerm) { + // We'll use batched drawing + let mut draw_batch = DrawBatch::new(); + + // Set all tiles to not visible + for v in &mut self.visible { + *v = false; + } + + // Obtain the player's visible tile set, and apply it + let player_position = self.index_to_point2d(self.player_position); + let fov = field_of_view_set(player_position, 8, self); + + // Note that the steps above would generally not be run every frame! + for idx in &fov { + self.visible[xy_idx(idx.x, idx.y)] = true; + } + + // Clear the screen + draw_batch.cls(); + + // Iterate the map array, incrementing coordinates as we go. + let mut y = 0; + let mut x = 0; + for (i, tile) in self.map.iter().enumerate() { + // Render a tile depending upon the tile type; now we check visibility as well! + let mut fg; + let mut glyph = "."; + + match tile { + TileType::Floor => { + fg = RGB::from_f32(0.5, 0.5, 0.0); + } + TileType::Wall => { + fg = RGB::from_f32(0.0, 1.0, 0.0); + glyph = "#"; + } + } + if !self.visible[i] { + fg = fg.to_greyscale(); + } + draw_batch.print_color( + Point::new(x, y), + glyph, + ColorPair::new(fg, RGB::from_f32(0., 0., 0.)), + ); + + // Move the coordinates + x += 1; + if x > 79 { + x = 0; + y += 1; + } + } + + // Either render the proposed path or run along it + if self.mode == Mode::Waiting { + // Render a mouse cursor + let mouse_pos = INPUT.lock().mouse_tile(0); + let mouse_idx = self.point2d_to_index(mouse_pos); + draw_batch.print_color( + mouse_pos, + "X", + ColorPair::new(RGB::from_f32(0.0, 1.0, 1.0), RGB::from_f32(0.0, 1.0, 1.0)), + ); + if self.map[mouse_idx as usize] != TileType::Wall { + let path = a_star_search(self.player_position, mouse_idx, self); + if path.success { + for loc in path.steps.iter().skip(1) { + let x = (loc % 80) as i32; + let y = (loc / 80) as i32; + draw_batch.print_color( + Point::new(x, y), + "*", + ColorPair::new(RGB::from_f32(1., 0., 0.), RGB::from_f32(0., 0., 0.)), + ); + } + + if INPUT.lock().is_mouse_button_pressed(0) { + self.mode = Mode::Moving; + self.path = path; + } + } + } + } else { + self.player_position = self.path.steps[0] as usize; + self.path.steps.remove(0); + if self.path.steps.is_empty() { + self.mode = Mode::Waiting; + } + } + + // Render the player @ symbol + let ppos = idx_xy(self.player_position); + draw_batch.print_color( + Point::from_tuple(ppos), + "@", + ColorPair::new(RGB::from_f32(1.0, 1.0, 0.0), RGB::from_f32(0., 0., 0.)), + ); + + // Submit the rendering + draw_batch.submit(0).expect("Batch error"); + render_draw_buffer(ctx).expect("Render error"); + } +} + +impl BaseMap for State { + fn is_opaque(&self, idx: usize) -> bool { + self.map[idx] == TileType::Wall + } + + fn get_available_exits(&self, idx: usize) -> SmallVec<[(usize, f32); 10]> { + let mut exits = SmallVec::new(); + let x = (idx % 80) as i32; + let y = (idx / 80) as i32; + + // Cardinal directions + if self.is_exit_valid(x - 1, y) { + exits.push((idx - 1, 1.0)) + }; + if self.is_exit_valid(x + 1, y) { + exits.push((idx + 1, 1.0)) + }; + if self.is_exit_valid(x, y - 1) { + exits.push((idx - 80, 1.0)) + }; + if self.is_exit_valid(x, y + 1) { + exits.push((idx + 80, 1.0)) + }; + + // Diagonals + if self.is_exit_valid(x - 1, y - 1) { + exits.push(((idx - 80) - 1, 1.4)); + } + if self.is_exit_valid(x + 1, y - 1) { + exits.push(((idx - 80) + 1, 1.4)); + } + if self.is_exit_valid(x - 1, y + 1) { + exits.push(((idx + 80) - 1, 1.4)); + } + if self.is_exit_valid(x + 1, y + 1) { + exits.push(((idx + 80) + 1, 1.4)); + } + + exits + } + + fn get_pathing_distance(&self, idx1: usize, idx2: usize) -> f32 { + let p1 = Point::new(idx1 % 80, idx1 / 80); + let p2 = Point::new(idx2 % 80, idx2 / 80); + DistanceAlg::Pythagoras.distance2d(p1, p2) + } +} + +impl Algorithm2D for State { + fn dimensions(&self) -> Point { + Point::new(80, 50) + } +} + +fn main() -> BError { + let context = BTermBuilder::new() + .with_title("Bracket Terminal Example - A* Mouse - 12x12 font") + .with_font("terminal8x8.png", 8, 8) + .with_fancy_console(80, 50, "terminal8x8.png") + .with_tile_dimensions(12, 12) + .build()?; + let gs = State::new(); + main_loop(context, gs) +} diff --git a/bracket-terminal/src/bterm.rs b/bracket-terminal/src/bterm.rs index 8e269c97..e7af4efb 100755 --- a/bracket-terminal/src/bterm.rs +++ b/bracket-terminal/src/bterm.rs @@ -78,6 +78,7 @@ pub struct BTerm { pub post_scanlines: bool, pub post_screenburn: bool, pub screen_burn_color: bracket_color::prelude::RGB, + pub mouse_visible: bool, } impl BTerm { @@ -249,8 +250,8 @@ impl BTerm { center_y as f32 * font_size.1 * (scale - 1.0), ); - let w : f32; - let h : f32; + let w: f32; + let h: f32; { let be = crate::hal::BACKEND.lock(); @@ -329,6 +330,11 @@ impl BTerm { self.screen_burn_color = color; } + // Set the mouse cursor visibility + pub fn with_mouse_visibility(&mut self, with_visibility: bool) { + self.mouse_visible = with_visibility; + } + /// Internal: mark a key press pub(crate) fn on_key(&mut self, key: VirtualKeyCode, scan_code: u32, pressed: bool) { let mut input = INPUT.lock(); diff --git a/bracket-terminal/src/consoles/command_buffer.rs b/bracket-terminal/src/consoles/command_buffer.rs index a6d45bd7..7b59fbed 100755 --- a/bracket-terminal/src/consoles/command_buffer.rs +++ b/bracket-terminal/src/consoles/command_buffer.rs @@ -18,7 +18,9 @@ lazy_static! { lazy_static! { static ref BUFFER_POOL: Arc> = Arc::new(Pool::new(128, || DrawBatch { - batch: Vec::with_capacity(5000), z_count: 0, needs_sort: false + batch: Vec::with_capacity(5000), + z_count: 0, + needs_sort: false })); } @@ -195,9 +197,12 @@ impl DrawBatch { COLOR: Into, { let z = self.next_z(); - self.batch.push((z, DrawCommand::ClearToColor { - color: color.into(), - })); + self.batch.push(( + z, + DrawCommand::ClearToColor { + color: color.into(), + }, + )); self } @@ -216,11 +221,14 @@ impl DrawBatch { glyph: G, ) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::Set { - pos, - color, - glyph: glyph.try_into().ok().expect("Must be u16 convertible"), - })); + self.batch.push(( + z, + DrawCommand::Set { + pos, + color, + glyph: glyph.try_into().ok().expect("Must be u16 convertible"), + }, + )); self } @@ -232,11 +240,14 @@ impl DrawBatch { glyph: G, z: u32, ) -> &mut Self { - self.batch.push((z, DrawCommand::Set { - pos, - color, - glyph: glyph.try_into().ok().expect("Must be u16 convertible"), - })); + self.batch.push(( + z, + DrawCommand::Set { + pos, + color, + glyph: glyph.try_into().ok().expect("Must be u16 convertible"), + }, + )); self.needs_sort = true; self } @@ -252,14 +263,17 @@ impl DrawBatch { glyph: G, ) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::SetFancy { - position, - z_order: z_order.try_into().ok().expect("Must be i32 convertible"), - rotation: rotation.into(), - color, - glyph: glyph.try_into().ok().expect("Must be u16 convertible"), - scale, - })); + self.batch.push(( + z, + DrawCommand::SetFancy { + position, + z_order: z_order.try_into().ok().expect("Must be i32 convertible"), + rotation: rotation.into(), + color, + glyph: glyph.try_into().ok().expect("Must be u16 convertible"), + scale, + }, + )); self } @@ -295,12 +309,15 @@ impl DrawBatch { background: Option, ) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::Printer { - pos, - text: text.to_string(), - align, - background, - })); + self.batch.push(( + z, + DrawCommand::Printer { + pos, + text: text.to_string(), + align, + background, + }, + )); self } @@ -315,12 +332,15 @@ impl DrawBatch { background: Option, z: u32, ) -> &mut Self { - self.batch.push((z, DrawCommand::Printer { - pos, - text: text.to_string(), - align, - background, - })); + self.batch.push(( + z, + DrawCommand::Printer { + pos, + text: text.to_string(), + align, + background, + }, + )); self.needs_sort = true; self } @@ -328,19 +348,25 @@ impl DrawBatch { /// Prints text in the default colors at a given location pub fn print(&mut self, pos: Point, text: S) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::Print { - pos, - text: text.to_string(), - })); + self.batch.push(( + z, + DrawCommand::Print { + pos, + text: text.to_string(), + }, + )); self } /// Prints text in the default colors at a given location & render order pub fn print_with_z(&mut self, pos: Point, text: S, z: u32) -> &mut Self { - self.batch.push((z, DrawCommand::Print { - pos, - text: text.to_string(), - })); + self.batch.push(( + z, + DrawCommand::Print { + pos, + text: text.to_string(), + }, + )); self.needs_sort = true; self } @@ -348,21 +374,33 @@ impl DrawBatch { /// Prints text in the default colors at a given location pub fn print_color(&mut self, pos: Point, text: S, color: ColorPair) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::PrintColor { - pos, - text: text.to_string(), - color, - })); + self.batch.push(( + z, + DrawCommand::PrintColor { + pos, + text: text.to_string(), + color, + }, + )); self } /// Prints text in the default colors at a given location & render order - pub fn print_color_with_z(&mut self, pos: Point, text: S, color: ColorPair, z: u32) -> &mut Self { - self.batch.push((z, DrawCommand::PrintColor { - pos, - text: text.to_string(), - color, - })); + pub fn print_color_with_z( + &mut self, + pos: Point, + text: S, + color: ColorPair, + z: u32, + ) -> &mut Self { + self.batch.push(( + z, + DrawCommand::PrintColor { + pos, + text: text.to_string(), + color, + }, + )); self.needs_sort = true; self } @@ -370,19 +408,30 @@ impl DrawBatch { /// Prints text, centered to the whole console width, at vertical location y. pub fn print_centered>(&mut self, y: Y, text: S) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::PrintCentered { - y: y.try_into().ok().expect("Must be i32 convertible"), - text: text.to_string(), - })); + self.batch.push(( + z, + DrawCommand::PrintCentered { + y: y.try_into().ok().expect("Must be i32 convertible"), + text: text.to_string(), + }, + )); self } /// Prints text, centered to the whole console width, at vertical location y. - pub fn print_centered_with_z>(&mut self, y: Y, text: S, z: u32) -> &mut Self { - self.batch.push((z, DrawCommand::PrintCentered { - y: y.try_into().ok().expect("Must be i32 convertible"), - text: text.to_string(), - })); + pub fn print_centered_with_z>( + &mut self, + y: Y, + text: S, + z: u32, + ) -> &mut Self { + self.batch.push(( + z, + DrawCommand::PrintCentered { + y: y.try_into().ok().expect("Must be i32 convertible"), + text: text.to_string(), + }, + )); self.needs_sort = true; self } @@ -395,11 +444,14 @@ impl DrawBatch { color: ColorPair, ) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::PrintColorCentered { - y: y.try_into().ok().expect("Must be i32 convertible"), - text: text.to_string(), - color, - })); + self.batch.push(( + z, + DrawCommand::PrintColorCentered { + y: y.try_into().ok().expect("Must be i32 convertible"), + text: text.to_string(), + color, + }, + )); self } @@ -409,13 +461,16 @@ impl DrawBatch { y: Y, text: S, color: ColorPair, - z: u32 + z: u32, ) -> &mut Self { - self.batch.push((z, DrawCommand::PrintColorCentered { - y: y.try_into().ok().expect("Must be i32 convertible"), - text: text.to_string(), - color, - })); + self.batch.push(( + z, + DrawCommand::PrintColorCentered { + y: y.try_into().ok().expect("Must be i32 convertible"), + text: text.to_string(), + color, + }, + )); self.needs_sort = true; self } @@ -423,19 +478,30 @@ impl DrawBatch { /// Prints text, centered to the whole console width, at vertical location y. pub fn print_centered_at(&mut self, pos: Point, text: S) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::PrintCenteredAt { - pos, - text: text.to_string(), - })); + self.batch.push(( + z, + DrawCommand::PrintCenteredAt { + pos, + text: text.to_string(), + }, + )); self } /// Prints text, centered to the whole console width, at vertical location y with render order. - pub fn print_centered_at_with_z(&mut self, pos: Point, text: S, z: u32) -> &mut Self { - self.batch.push((z, DrawCommand::PrintCenteredAt { - pos, - text: text.to_string(), - })); + pub fn print_centered_at_with_z( + &mut self, + pos: Point, + text: S, + z: u32, + ) -> &mut Self { + self.batch.push(( + z, + DrawCommand::PrintCenteredAt { + pos, + text: text.to_string(), + }, + )); self.needs_sort = true; self } @@ -448,11 +514,14 @@ impl DrawBatch { color: ColorPair, ) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::PrintColorCenteredAt { - pos, - text: text.to_string(), - color, - })); + self.batch.push(( + z, + DrawCommand::PrintColorCenteredAt { + pos, + text: text.to_string(), + color, + }, + )); self } @@ -464,11 +533,14 @@ impl DrawBatch { color: ColorPair, z: u32, ) -> &mut Self { - self.batch.push((z, DrawCommand::PrintColorCenteredAt { - pos, - text: text.to_string(), - color, - })); + self.batch.push(( + z, + DrawCommand::PrintColorCenteredAt { + pos, + text: text.to_string(), + color, + }, + )); self.needs_sort = true; self } @@ -476,19 +548,25 @@ impl DrawBatch { /// Prints right aligned text pub fn print_right(&mut self, pos: Point, text: S) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::PrintRight { - pos, - text: text.to_string(), - })); + self.batch.push(( + z, + DrawCommand::PrintRight { + pos, + text: text.to_string(), + }, + )); self } /// Prints right aligned text with render order pub fn print_right_z(&mut self, pos: Point, text: S, z: u32) -> &mut Self { - self.batch.push((z, DrawCommand::PrintRight { - pos, - text: text.to_string(), - })); + self.batch.push(( + z, + DrawCommand::PrintRight { + pos, + text: text.to_string(), + }, + )); self.needs_sort = true; self } @@ -501,11 +579,14 @@ impl DrawBatch { color: ColorPair, ) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::PrintColorRight { - pos, - text: text.to_string(), - color, - })); + self.batch.push(( + z, + DrawCommand::PrintColorRight { + pos, + text: text.to_string(), + color, + }, + )); self } @@ -517,11 +598,14 @@ impl DrawBatch { color: ColorPair, z: u32, ) -> &mut Self { - self.batch.push((z, DrawCommand::PrintColorRight { - pos, - text: text.to_string(), - color, - })); + self.batch.push(( + z, + DrawCommand::PrintColorRight { + pos, + text: text.to_string(), + color, + }, + )); self.needs_sort = true; self } @@ -571,13 +655,20 @@ impl DrawBatch { /// Draws a non-filled (hollow) double-lined box, starting at x/y with the extents width/height using CP437 line characters pub fn draw_hollow_double_box(&mut self, pos: Rect, color: ColorPair) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::HollowDoubleBox { pos, color })); + self.batch + .push((z, DrawCommand::HollowDoubleBox { pos, color })); self } /// Draws a non-filled (hollow) double-lined box, starting at x/y with the extents width/height using CP437 line characters - pub fn draw_hollow_double_box_with_z(&mut self, pos: Rect, color: ColorPair, z: u32) -> &mut Self { - self.batch.push((z, DrawCommand::HollowDoubleBox { pos, color })); + pub fn draw_hollow_double_box_with_z( + &mut self, + pos: Rect, + color: ColorPair, + z: u32, + ) -> &mut Self { + self.batch + .push((z, DrawCommand::HollowDoubleBox { pos, color })); self.needs_sort = true; self } @@ -590,11 +681,14 @@ impl DrawBatch { glyph: G, ) -> &mut Self { let z = self.next_z(); - self.batch.push((z, DrawCommand::FillRegion { - pos, - color, - glyph: glyph.try_into().ok().expect("Must be u16 convertible"), - })); + self.batch.push(( + z, + DrawCommand::FillRegion { + pos, + color, + glyph: glyph.try_into().ok().expect("Must be u16 convertible"), + }, + )); self } @@ -606,11 +700,14 @@ impl DrawBatch { glyph: G, z: u32, ) -> &mut Self { - self.batch.push((z, DrawCommand::FillRegion { - pos, - color, - glyph: glyph.try_into().ok().expect("Must be u16 convertible"), - })); + self.batch.push(( + z, + DrawCommand::FillRegion { + pos, + color, + glyph: glyph.try_into().ok().expect("Must be u16 convertible"), + }, + )); self.needs_sort = true; self } @@ -630,13 +727,16 @@ impl DrawBatch { MAX: TryInto, { let z = self.next_z(); - self.batch.push((z, DrawCommand::BarHorizontal { - pos, - width: width.try_into().ok().expect("Must be i32 convertible"), - n: n.try_into().ok().expect("Must be i32 convertible"), - max: max.try_into().ok().expect("Must be i32 convertible"), - color, - })); + self.batch.push(( + z, + DrawCommand::BarHorizontal { + pos, + width: width.try_into().ok().expect("Must be i32 convertible"), + n: n.try_into().ok().expect("Must be i32 convertible"), + max: max.try_into().ok().expect("Must be i32 convertible"), + color, + }, + )); self } @@ -655,13 +755,16 @@ impl DrawBatch { N: TryInto, MAX: TryInto, { - self.batch.push((z, DrawCommand::BarHorizontal { - pos, - width: width.try_into().ok().expect("Must be i32 convertible"), - n: n.try_into().ok().expect("Must be i32 convertible"), - max: max.try_into().ok().expect("Must be i32 convertible"), - color, - })); + self.batch.push(( + z, + DrawCommand::BarHorizontal { + pos, + width: width.try_into().ok().expect("Must be i32 convertible"), + n: n.try_into().ok().expect("Must be i32 convertible"), + max: max.try_into().ok().expect("Must be i32 convertible"), + color, + }, + )); self.needs_sort = true; self } @@ -681,13 +784,16 @@ impl DrawBatch { MAX: TryInto, { let z = self.next_z(); - self.batch.push((z, DrawCommand::BarVertical { - pos, - height: height.try_into().ok().expect("Must be i32 convertible"), - n: n.try_into().ok().expect("Must be i32 convertible"), - max: max.try_into().ok().expect("Must be i32 convertible"), - color, - })); + self.batch.push(( + z, + DrawCommand::BarVertical { + pos, + height: height.try_into().ok().expect("Must be i32 convertible"), + n: n.try_into().ok().expect("Must be i32 convertible"), + max: max.try_into().ok().expect("Must be i32 convertible"), + color, + }, + )); self } @@ -699,20 +805,23 @@ impl DrawBatch { n: N, max: MAX, color: ColorPair, - z: u32 + z: u32, ) -> &mut Self where H: TryInto, N: TryInto, MAX: TryInto, { - self.batch.push((z, DrawCommand::BarVertical { - pos, - height: height.try_into().ok().expect("Must be i32 convertible"), - n: n.try_into().ok().expect("Must be i32 convertible"), - max: max.try_into().ok().expect("Must be i32 convertible"), - color, - })); + self.batch.push(( + z, + DrawCommand::BarVertical { + pos, + height: height.try_into().ok().expect("Must be i32 convertible"), + n: n.try_into().ok().expect("Must be i32 convertible"), + max: max.try_into().ok().expect("Must be i32 convertible"), + color, + }, + )); self.needs_sort = true; self } diff --git a/bracket-terminal/src/consoles/flexible_console.rs b/bracket-terminal/src/consoles/flexible_console.rs index 20f7520d..76ed3433 100755 --- a/bracket-terminal/src/consoles/flexible_console.rs +++ b/bracket-terminal/src/consoles/flexible_console.rs @@ -5,6 +5,8 @@ use crate::prelude::{ use bracket_color::prelude::RGBA; use bracket_geometry::prelude::{PointF, Rect}; use bracket_rex::prelude::XpColor; +use ultraviolet::Vec2; + use std::any::Any; /// Internal storage structure for sparse tiles. @@ -107,12 +109,26 @@ impl Console for FlexiConsole { fn cls(&mut self) { self.is_dirty = true; self.tiles.clear(); + + self.tiles.push(FlexiTile { + glyph: 32, + fg: RGBA::from_u8(255, 255, 255, 255), + bg: RGBA::from_u8(0, 0, 0, 255), + rotation: 0., + scale: Vec2::new(0., 0.), + z_order: 0, + position: Vec2::new(0., 0.), + }); } /// Clear the screen. Since we don't HAVE a background, it doesn't use it. fn cls_bg(&mut self, _background: RGBA) { self.is_dirty = true; - self.tiles.clear(); + for tile in &mut self.tiles { + tile.glyph = 32; + tile.fg = RGBA::from_u8(255, 255, 255, 255); + tile.bg = RGBA::from_u8(0, 0, 0, 255); + } } /// Prints a string to an x/y position. diff --git a/bracket-terminal/src/hal/crossterm_be/init.rs b/bracket-terminal/src/hal/crossterm_be/init.rs index 31af261d..9a235574 100755 --- a/bracket-terminal/src/hal/crossterm_be/init.rs +++ b/bracket-terminal/src/hal/crossterm_be/init.rs @@ -47,6 +47,7 @@ pub fn init_raw( post_scanlines: false, post_screenburn: false, screen_burn_color: bracket_color::prelude::RGB::from_f32(0.0, 1.0, 1.0), + mouse_visible: true, }; Ok(bterm) } diff --git a/bracket-terminal/src/hal/crossterm_be/main_loop.rs b/bracket-terminal/src/hal/crossterm_be/main_loop.rs index 42451672..94444252 100755 --- a/bracket-terminal/src/hal/crossterm_be/main_loop.rs +++ b/bracket-terminal/src/hal/crossterm_be/main_loop.rs @@ -65,20 +65,14 @@ pub fn main_loop(mut bterm: BTerm, mut gamestate: GS) -> BResult< crossterm::event::MouseEventKind::Down(button) => { bterm.left_click = true; bterm.mouse_pos = (event.column as i32, event.row as i32); - bterm.on_mouse_position( - event.column as f64, - event.row as f64, - ); + bterm.on_mouse_position(event.column as f64, event.row as f64); bterm.on_mouse_button(button as usize, true); } crossterm::event::MouseEventKind::Up(button) => { bterm.on_mouse_button(button as usize, false); } crossterm::event::MouseEventKind::Drag(..) => { - bterm.on_mouse_position( - event.column as f64, - event.row as f64, - ); + bterm.on_mouse_position(event.column as f64, event.row as f64); } _ => { //eprintln!("{:?}", event); diff --git a/bracket-terminal/src/hal/crossterm_be/mod.rs b/bracket-terminal/src/hal/crossterm_be/mod.rs index ef55f367..f78fe028 100755 --- a/bracket-terminal/src/hal/crossterm_be/mod.rs +++ b/bracket-terminal/src/hal/crossterm_be/mod.rs @@ -18,6 +18,7 @@ pub struct InitHints { pub vsync: bool, pub fullscreen: bool, pub frame_sleep_time: Option, + pub fitscreen: bool, } impl InitHints { @@ -26,6 +27,7 @@ impl InitHints { vsync: true, fullscreen: false, frame_sleep_time: None, + fitscreen: false, } } } diff --git a/bracket-terminal/src/hal/curses/init.rs b/bracket-terminal/src/hal/curses/init.rs index 3a065a9b..b80abc74 100755 --- a/bracket-terminal/src/hal/curses/init.rs +++ b/bracket-terminal/src/hal/curses/init.rs @@ -57,6 +57,7 @@ pub fn init_raw( post_scanlines: false, post_screenburn: false, screen_burn_color: bracket_color::prelude::RGB::from_f32(0.0, 1.0, 1.0), + mouse_visible: true, }; Ok(bterm) } diff --git a/bracket-terminal/src/hal/dummy/mod.rs b/bracket-terminal/src/hal/dummy/mod.rs index 50ca82de..75f18d92 100755 --- a/bracket-terminal/src/hal/dummy/mod.rs +++ b/bracket-terminal/src/hal/dummy/mod.rs @@ -8,6 +8,7 @@ pub struct InitHints { pub vsync: bool, pub fullscreen: bool, pub frame_sleep_time: Option, + pub fitscreen: bool, } impl InitHints { @@ -16,6 +17,7 @@ impl InitHints { vsync: true, fullscreen: false, frame_sleep_time: None, + fitscreen: false, } } } diff --git a/bracket-terminal/src/hal/gl_common/backing/shared_main_loop.rs b/bracket-terminal/src/hal/gl_common/backing/shared_main_loop.rs index e998c723..ced858ee 100755 --- a/bracket-terminal/src/hal/gl_common/backing/shared_main_loop.rs +++ b/bracket-terminal/src/hal/gl_common/backing/shared_main_loop.rs @@ -165,7 +165,8 @@ pub(crate) fn render_consoles() -> BResult<()> { backing.gl_draw(font, shader)?; } ConsoleBacking::Sprite { backing } => { - backing.gl_draw(bi.sprite_sheets[0].backing.as_ref().unwrap(), shader)?; + let sprite_sheet = cons.console.as_any().downcast_ref::().unwrap().sprite_sheet; + backing.gl_draw(bi.sprite_sheets[sprite_sheet].backing.as_ref().unwrap(), shader)?; } } } diff --git a/bracket-terminal/src/hal/gl_common/backing/simple_console_backing.rs b/bracket-terminal/src/hal/gl_common/backing/simple_console_backing.rs index 8c737c1b..f02f4090 100755 --- a/bracket-terminal/src/hal/gl_common/backing/simple_console_backing.rs +++ b/bracket-terminal/src/hal/gl_common/backing/simple_console_backing.rs @@ -8,7 +8,7 @@ pub struct SimpleConsoleBackend { vao: VertexArray, vertex_counter: usize, index_counter: usize, - previous_console : Option>, + previous_console: Option>, } impl SimpleConsoleBackend { @@ -91,7 +91,7 @@ impl SimpleConsoleBackend { if !needs_resize { if let Some(old) = &self.previous_console { if old.len() == tiles.len() { - let no_change = tiles.iter().zip(old.iter()).all(|(a, b)| *a==*b); + let no_change = tiles.iter().zip(old.iter()).all(|(a, b)| *a == *b); if no_change { return; } diff --git a/bracket-terminal/src/hal/gl_common/backing/sparse_console_backing.rs b/bracket-terminal/src/hal/gl_common/backing/sparse_console_backing.rs index f17e0294..5e2ea438 100755 --- a/bracket-terminal/src/hal/gl_common/backing/sparse_console_backing.rs +++ b/bracket-terminal/src/hal/gl_common/backing/sparse_console_backing.rs @@ -6,13 +6,16 @@ use bracket_color::prelude::RGBA; pub struct SparseConsoleBackend { vao: VertexArray, - previous_console : Option>, + previous_console: Option>, } impl SparseConsoleBackend { pub fn new(_width: usize, _height: usize, gl: &glow::Context) -> SparseConsoleBackend { let vao = SparseConsoleBackend::init_gl_for_console(gl, 1000, 1000); - SparseConsoleBackend { vao, previous_console: None } + SparseConsoleBackend { + vao, + previous_console: None, + } } fn init_gl_for_console( @@ -65,7 +68,7 @@ impl SparseConsoleBackend { if !needs_resize { if let Some(old) = &self.previous_console { if old.len() == tiles.len() { - let no_change = tiles.iter().zip(old.iter()).all(|(a, b)| *a==*b); + let no_change = tiles.iter().zip(old.iter()).all(|(a, b)| *a == *b); if no_change { return; } diff --git a/bracket-terminal/src/hal/gl_common/backing/sprite_console_backing.rs b/bracket-terminal/src/hal/gl_common/backing/sprite_console_backing.rs index 1910eae7..0260d165 100755 --- a/bracket-terminal/src/hal/gl_common/backing/sprite_console_backing.rs +++ b/bracket-terminal/src/hal/gl_common/backing/sprite_console_backing.rs @@ -76,8 +76,8 @@ impl SpriteConsoleBackend { let sprite_pos = sprite_sheet.sprites[s.index].sheet_location; let sprite_left = sprite_pos.x1 as f32 * ss_x; let sprite_bottom = sprite_pos.y1 as f32 * ss_y; - let sprite_right = (sprite_pos.x2-1) as f32 * ss_x; - let sprite_top = (sprite_pos.y2-1) as f32 * ss_y; + let sprite_right = (sprite_pos.x2 - 1) as f32 * ss_x; + let sprite_top = (sprite_pos.y2 - 1) as f32 * ss_y; let render_width = s.destination.width() as f32; let sprite_width = sprite_pos.width() as f32; diff --git a/bracket-terminal/src/hal/gl_common/font.rs b/bracket-terminal/src/hal/gl_common/font.rs index 8a51827d..1f37eb90 100755 --- a/bracket-terminal/src/hal/gl_common/font.rs +++ b/bracket-terminal/src/hal/gl_common/font.rs @@ -1,7 +1,7 @@ use super::{gl_error, TextureId}; -use bracket_embedding::prelude::EMBED; use crate::BResult; use bracket_color::prelude::RGB; +use bracket_embedding::prelude::EMBED; use glow::HasContext; #[derive(PartialEq, Clone)] @@ -31,7 +31,10 @@ impl Font { tile_size, explicit_background: None, font_dimensions_glyphs: (tile_size.0 / width, tile_size.1 / height), - font_dimensions_texture: ( tile_size.0 as f32 / width as f32, tile_size.1 as f32 / height as f32 ), + font_dimensions_texture: ( + tile_size.0 as f32 / width as f32, + tile_size.1 as f32 / height as f32, + ), } } @@ -59,7 +62,10 @@ impl Font { tile_size, explicit_background, font_dimensions_glyphs: (img.width() / tile_size.0, img.height() / tile_size.1), - font_dimensions_texture: ( tile_size.0 as f32 / img.width() as f32, tile_size.1 as f32 / img.height() as f32), + font_dimensions_texture: ( + tile_size.0 as f32 / img.width() as f32, + tile_size.1 as f32 / img.height() as f32, + ), } } diff --git a/bracket-terminal/src/hal/gl_common/framebuffer.rs b/bracket-terminal/src/hal/gl_common/framebuffer.rs index 5a555db5..9986fd69 100755 --- a/bracket-terminal/src/hal/gl_common/framebuffer.rs +++ b/bracket-terminal/src/hal/gl_common/framebuffer.rs @@ -2,10 +2,12 @@ use crate::BResult; use glow::HasContext; +use super::{FramebufferId, TextureId}; + #[cfg(not(target_arch = "wasm32"))] pub struct Framebuffer { - fbo: u32, - pub texture: u32, + fbo: FramebufferId, + pub texture: TextureId, } #[cfg(target_arch = "wasm32")] diff --git a/bracket-terminal/src/hal/gl_common/quadrender.rs b/bracket-terminal/src/hal/gl_common/quadrender.rs index 9524e4cd..31fe027d 100755 --- a/bracket-terminal/src/hal/gl_common/quadrender.rs +++ b/bracket-terminal/src/hal/gl_common/quadrender.rs @@ -50,7 +50,13 @@ pub fn setup_quad(gl: &glow::Context) -> VertexArrayId { /// Sets up a simple VAO/VBO to render a single quad /// Used for presenting the backing buffer and in post-process chains. -pub fn setup_quad_gutter(gl: &glow::Context, left: f32, right: f32, top: f32, bottom: f32) -> VertexArrayId { +pub fn setup_quad_gutter( + gl: &glow::Context, + left: f32, + right: f32, + top: f32, + bottom: f32, +) -> VertexArrayId { #[rustfmt::skip] let quad_vertices: [f32; 24] = [ // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. @@ -93,4 +99,4 @@ pub fn setup_quad_gutter(gl: &glow::Context, left: f32, right: f32, top: f32, bo } vertex_array -} \ No newline at end of file +} diff --git a/bracket-terminal/src/hal/gl_common/types_native.rs b/bracket-terminal/src/hal/gl_common/types_native.rs index 2e10d676..50dff54d 100755 --- a/bracket-terminal/src/hal/gl_common/types_native.rs +++ b/bracket-terminal/src/hal/gl_common/types_native.rs @@ -1,4 +1,7 @@ -pub type TextureId = u32; -pub type BufferId = u32; -pub type VertexArrayId = u32; -pub type ShaderId = u32; +use glow::{NativeTexture, NativeBuffer, NativeVertexArray, NativeProgram, NativeFramebuffer}; + +pub type TextureId = NativeTexture; +pub type BufferId = NativeBuffer; +pub type VertexArrayId = NativeVertexArray; +pub type ShaderId = NativeProgram; +pub type FramebufferId = NativeFramebuffer; diff --git a/bracket-terminal/src/hal/gl_common/types_wasm.rs b/bracket-terminal/src/hal/gl_common/types_wasm.rs index 1db96f05..0cf64b83 100755 --- a/bracket-terminal/src/hal/gl_common/types_wasm.rs +++ b/bracket-terminal/src/hal/gl_common/types_wasm.rs @@ -2,3 +2,4 @@ pub type TextureId = glow::WebTextureKey; pub type BufferId = glow::WebBufferKey; pub type VertexArrayId = glow::WebVertexArrayKey; pub type ShaderId = glow::WebProgramKey; +pub type FramebufferId = glow::WebFramebufferKey; diff --git a/bracket-terminal/src/hal/native/init.rs b/bracket-terminal/src/hal/native/init.rs index 22ac229c..51e05f76 100755 --- a/bracket-terminal/src/hal/native/init.rs +++ b/bracket-terminal/src/hal/native/init.rs @@ -15,10 +15,13 @@ pub fn init_raw( ) -> BResult { let mut scaler = ScreenScaler::new(platform_hints.desired_gutter, width_pixels, height_pixels); let el = EventLoop::new(); + let window_size = scaler.new_window_size(); + let window_size = glutin::dpi::LogicalSize::new(window_size.width, window_size.height); let wb = WindowBuilder::new() .with_title(window_title.to_string()) - .with_min_inner_size(scaler.new_window_size()) - .with_inner_size(scaler.new_window_size()); + .with_resizable(platform_hints.fitscreen) + .with_min_inner_size(window_size) + .with_inner_size(window_size); let windowed_context = ContextBuilder::new() .with_gl(platform_hints.gl_version) .with_gl_profile(platform_hints.gl_profile) @@ -48,7 +51,10 @@ pub fn init_raw( unsafe { let gl_version = gl.get_parameter_string(glow::VERSION); let shader_version = gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION); - println!("Initialized OpenGL with: {}, Shader Language Version: {}", gl_version, shader_version); + println!( + "Initialized OpenGL with: {}, Shader Language Version: {}", + gl_version, shader_version + ); } // Load our basic shaders @@ -130,6 +136,7 @@ pub fn init_raw( post_scanlines: false, post_screenburn: false, screen_burn_color: bracket_color::prelude::RGB::from_f32(0.0, 1.0, 1.0), + mouse_visible: true, }; Ok(bterm) } diff --git a/bracket-terminal/src/hal/native/mainloop.rs b/bracket-terminal/src/hal/native/mainloop.rs index a7ee625d..f77d39e3 100755 --- a/bracket-terminal/src/hal/native/mainloop.rs +++ b/bracket-terminal/src/hal/native/mainloop.rs @@ -37,7 +37,12 @@ fn on_resize( //println!("{:#?}", physical_size); INPUT.lock().set_scale_factor(dpi_scale_factor); let mut be = BACKEND.lock(); - be.screen_scaler.change_physical_size_smooth(physical_size.width, physical_size.height, dpi_scale_factor as f32, font_max_size); + be.screen_scaler.change_physical_size_smooth( + physical_size.width, + physical_size.height, + dpi_scale_factor as f32, + font_max_size, + ); let (l, r, t, b) = be.screen_scaler.get_backing_buffer_output_coordinates(); be.quad_vao = Some(setup_quad_gutter(be.gl.as_ref().unwrap(), l, r, t, b)); if send_event { @@ -60,13 +65,16 @@ fn on_resize( ); } /*let new_fb = Framebuffer::build_fbo( - gl, - physical_size.width as i32, + gl, + physical_size.width as i32, physical_size.height as i32 )?; be.backing_buffer = Some(new_fb);*/ bterm.on_event(BEvent::Resized { - new_size: Point::new(be.screen_scaler.available_width, be.screen_scaler.available_height), + new_size: Point::new( + be.screen_scaler.available_width, + be.screen_scaler.available_height, + ), dpi_scale_factor: dpi_scale_factor as f32, }); @@ -76,7 +84,7 @@ fn on_resize( let new_fb = Framebuffer::build_fbo( gl, be.screen_scaler.available_width as i32, - be.screen_scaler.available_height as i32 + be.screen_scaler.available_height as i32, )?; be.backing_buffer = Some(new_fb); be.screen_scaler.logical_size.0 = be.screen_scaler.available_width; @@ -149,6 +157,8 @@ pub fn main_loop(mut bterm: BTerm, mut gamestate: GS) -> BResult< *control_flow = ControlFlow::Exit; } + wc.window().set_cursor_visible(bterm.mouse_visible); + match &event { Event::RedrawEventsCleared => { let frame_timer = Instant::now(); @@ -191,10 +201,13 @@ pub fn main_loop(mut bterm: BTerm, mut gamestate: GS) -> BResult< if time_since_last_frame < wait_time { // We're wrapping the spin sleeper in a feature now. If you want to use it, // enable "low_cpu". Otherwise, it was causing input lag. - #[cfg(feature = "low_cpu")] let delay = u64::min(33, wait_time - time_since_last_frame); //println!("Frame time: {}ms, Delay: {}ms", time_since_last_frame, delay); - //*control_flow = ControlFlow::WaitUntil(Instant::now() + std::time::Duration::from_millis(delay)); + #[cfg(not(feature = "low_cpu"))] + { + std::thread::sleep(std::time::Duration::from_millis(delay)); + //*control_flow = ControlFlow::WaitUntil(Instant::now() + std::time::Duration::from_micros(delay)); + } #[cfg(feature = "low_cpu")] spin_sleeper.sleep(std::time::Duration::from_millis(delay)); } else { @@ -347,7 +360,12 @@ fn tock( .unwrap() .bind(be.gl.as_ref().unwrap()); unsafe { - be.gl.as_ref().unwrap().viewport(0, 0, be.screen_scaler.logical_size.0 as i32, be.screen_scaler.logical_size.1 as i32); + be.gl.as_ref().unwrap().viewport( + 0, + 0, + be.screen_scaler.logical_size.0 as i32, + be.screen_scaler.logical_size.1 as i32, + ); } } @@ -382,7 +400,12 @@ fn tock( .default(be.gl.as_ref().unwrap()); unsafe { // And clear it, resetting the viewport - be.gl.as_ref().unwrap().viewport(0, 0, be.screen_scaler.physical_size.0 as i32, be.screen_scaler.physical_size.1 as i32); + be.gl.as_ref().unwrap().viewport( + 0, + 0, + be.screen_scaler.physical_size.0 as i32, + be.screen_scaler.physical_size.1 as i32, + ); be.gl.as_ref().unwrap().clear_color(0.0, 0.0, 0.0, 1.0); be.gl.as_ref().unwrap().clear(glow::COLOR_BUFFER_BIT); diff --git a/bracket-terminal/src/hal/native/mod.rs b/bracket-terminal/src/hal/native/mod.rs index 26b396c2..39fc1df7 100755 --- a/bracket-terminal/src/hal/native/mod.rs +++ b/bracket-terminal/src/hal/native/mod.rs @@ -1,12 +1,13 @@ mod init; pub mod shader_strings; +use glow::NativeVertexArray; pub use init::*; mod mainloop; +use crate::hal::scaler::{default_gutter_size, ScreenScaler}; use crate::hal::ConsoleBacking; pub use mainloop::*; use parking_lot::Mutex; use std::any::Any; -use crate::hal::scaler::{ScreenScaler, default_gutter_size}; pub type GlCallback = fn(&mut dyn Any, &glow::Context); @@ -31,7 +32,7 @@ lazy_static! { pub struct PlatformGL { pub gl: Option, - pub quad_vao: Option, + pub quad_vao: Option, pub context_wrapper: Option, pub backing_buffer: Option, pub frame_sleep_time: Option, @@ -60,6 +61,7 @@ pub struct InitHints { pub frame_sleep_time: Option, pub resize_scaling: bool, pub desired_gutter: u32, + pub fitscreen: bool, } impl InitHints { @@ -74,6 +76,7 @@ impl InitHints { frame_sleep_time: None, resize_scaling: false, desired_gutter: default_gutter_size(), + fitscreen: false, } } } @@ -90,6 +93,7 @@ impl Default for InitHints { frame_sleep_time: None, resize_scaling: false, desired_gutter: default_gutter_size(), + fitscreen: false, } } } diff --git a/bracket-terminal/src/hal/scaler.rs b/bracket-terminal/src/hal/scaler.rs index 9dd9cef3..7013574b 100644 --- a/bracket-terminal/src/hal/scaler.rs +++ b/bracket-terminal/src/hal/scaler.rs @@ -14,7 +14,6 @@ pub(crate) fn default_gutter_size() -> u32 { 0 } - /// Provides a consistent font to texture coordinates mapping service. pub struct FontScaler { font_dimensions_glyphs: (u16, u16), @@ -35,9 +34,9 @@ impl FontScaler { font_dimensions_texture: (f32, f32), ) -> Self { Self { - font_dimensions_glyphs : ( + font_dimensions_glyphs: ( font_dimensions_glyphs.0 as u16, - font_dimensions_glyphs.1 as u16 + font_dimensions_glyphs.1 as u16, ), font_dimensions_texture, } @@ -54,7 +53,10 @@ impl FontScaler { let glyph_bottom = f32::from(glyph_y - 1) * self.font_dimensions_texture.1; GlyphPosition { - glyph_left, glyph_right, glyph_top, glyph_bottom + glyph_left, + glyph_right, + glyph_top, + glyph_bottom, } } } @@ -118,7 +120,8 @@ impl ScreenScaler { } pub fn new_window_size(&mut self) -> LogicalSize { - self.aspect_ratio = (self.physical_size.1 + self.desired_gutter) as f32 / (self.physical_size.0 + self.desired_gutter) as f32; + self.aspect_ratio = (self.physical_size.1 + self.desired_gutter) as f32 + / (self.physical_size.0 + self.desired_gutter) as f32; self.logical_size = self.physical_size; LogicalSize::new( self.physical_size.0 + self.desired_gutter, @@ -140,7 +143,13 @@ impl ScreenScaler { self.recalculate_coordinates(); } - pub fn change_physical_size_smooth(&mut self, width: u32, height: u32, scale: f32, max_font: (u32, u32)) { + pub fn change_physical_size_smooth( + &mut self, + width: u32, + height: u32, + scale: f32, + max_font: (u32, u32), + ) { self.scale_factor = scale; self.physical_size.0 = width; self.physical_size.1 = height; @@ -164,14 +173,14 @@ impl ScreenScaler { let half_gutter = total_gutter / 2; let (extra_left, extra_right) = if self.smooth_gutter_x % 2 == 0 { - (self.smooth_gutter_x/2, self.smooth_gutter_x/2) + (self.smooth_gutter_x / 2, self.smooth_gutter_x / 2) } else { - ((self.smooth_gutter_x/2)+1, self.smooth_gutter_x/2) + ((self.smooth_gutter_x / 2) + 1, self.smooth_gutter_x / 2) }; let (extra_top, extra_bottom) = if self.smooth_gutter_y % 2 == 0 { - (self.smooth_gutter_y/2, self.smooth_gutter_y/2) + (self.smooth_gutter_y / 2, self.smooth_gutter_y / 2) } else { - ((self.smooth_gutter_y/2)+1, self.smooth_gutter_y/2) + ((self.smooth_gutter_y / 2) + 1, self.smooth_gutter_y / 2) }; if total_gutter % 2 == 0 { @@ -181,9 +190,9 @@ impl ScreenScaler { self.gutter_bottom = half_gutter + extra_bottom; } else { self.gutter_left = half_gutter + extra_left; - self.gutter_right = half_gutter+1 + extra_right; + self.gutter_right = half_gutter + 1 + extra_right; self.gutter_top = half_gutter + extra_top; - self.gutter_bottom = half_gutter+1 + extra_bottom; + self.gutter_bottom = half_gutter + 1 + extra_bottom; } self.available_width = self.physical_size.0 - (total_gutter + extra_left + extra_right); @@ -203,10 +212,7 @@ impl ScreenScaler { } pub fn bottom_right_pixel(&self) -> (f32, f32) { - self.pixel_to_screen( - self.logical_size.0, - self.logical_size.1 - ) + self.pixel_to_screen(self.logical_size.0, self.logical_size.1) } pub fn calc_step(&self, width: u32, height: u32, scale: f32) -> (f32, f32) { @@ -232,10 +238,7 @@ impl ScreenScaler { } pub fn get_backing_buffer_output_coordinates(&self) -> (f32, f32, f32, f32) { - let (left, bottom) = self.pixel_to_screen_physical( - self.gutter_left, - self.gutter_top, - ); + let (left, bottom) = self.pixel_to_screen_physical(self.gutter_left, self.gutter_top); let (right, top) = self.pixel_to_screen_physical( self.physical_size.0 - self.gutter_right, self.physical_size.1 - self.gutter_bottom, diff --git a/bracket-terminal/src/hal/wasm/init.rs b/bracket-terminal/src/hal/wasm/init.rs index 348b1712..26f86451 100755 --- a/bracket-terminal/src/hal/wasm/init.rs +++ b/bracket-terminal/src/hal/wasm/init.rs @@ -77,7 +77,8 @@ pub fn init_raw( be.gl = Some(gl); be.quad_vao = Some(quad_vao); be.backing_buffer = Some(backing_fbo); - be.screen_scaler = ScreenScaler::new(platform_hints.desired_gutter, width_pixels, height_pixels); + be.screen_scaler = + ScreenScaler::new(platform_hints.desired_gutter, width_pixels, height_pixels); BACKEND_INTERNAL.lock().shaders = shaders; @@ -100,5 +101,6 @@ pub fn init_raw( post_scanlines: false, post_screenburn: false, screen_burn_color: bracket_color::prelude::RGB::from_f32(0.0, 1.0, 1.0), + mouse_visible: true, }) } diff --git a/bracket-terminal/src/hal/wasm/mod.rs b/bracket-terminal/src/hal/wasm/mod.rs index c2f3fa32..24d0d6cc 100755 --- a/bracket-terminal/src/hal/wasm/mod.rs +++ b/bracket-terminal/src/hal/wasm/mod.rs @@ -5,11 +5,11 @@ pub use init::*; mod events; pub use events::*; mod mainloop; +use crate::hal::scaler::{default_gutter_size, ScreenScaler}; use crate::hal::ConsoleBacking; pub use mainloop::*; use parking_lot::Mutex; use std::any::Any; -use crate::hal::scaler::{ScreenScaler, default_gutter_size}; pub type GlCallback = fn(&mut dyn Any, &glow::Context); @@ -18,6 +18,7 @@ pub struct InitHints { pub fullscreen: bool, pub frame_sleep_time: Option, pub desired_gutter: u32, + pub fitscreen: bool, } impl InitHints { @@ -27,6 +28,7 @@ impl InitHints { fullscreen: false, frame_sleep_time: None, desired_gutter: 0, + fitscreen: false, } } } diff --git a/bracket-terminal/src/hal/webgpu/backend.rs b/bracket-terminal/src/hal/webgpu/backend.rs index 59800fe0..734c1786 100644 --- a/bracket-terminal/src/hal/webgpu/backend.rs +++ b/bracket-terminal/src/hal/webgpu/backend.rs @@ -1,6 +1,6 @@ //! Defines the BACKEND static used by wgpu. -use crate::hal::{ConsoleBacking, PlatformGL, scaler::ScreenScaler}; +use crate::hal::{scaler::ScreenScaler, ConsoleBacking, PlatformGL}; use lazy_static::*; use parking_lot::Mutex; diff --git a/bracket-terminal/src/hal/webgpu/backing/fancy_console_backing.rs b/bracket-terminal/src/hal/webgpu/backing/fancy_console_backing.rs index 5790339a..dde16d4d 100644 --- a/bracket-terminal/src/hal/webgpu/backing/fancy_console_backing.rs +++ b/bracket-terminal/src/hal/webgpu/backing/fancy_console_backing.rs @@ -2,7 +2,10 @@ use super::index_array_helper::IndexBuffer; use super::vertex_array_helper::FloatBuffer; -use crate::hal::{Font, Shader, WgpuLink, scaler::{FontScaler, ScreenScaler}}; +use crate::hal::{ + scaler::{FontScaler, ScreenScaler}, + Font, Shader, WgpuLink, +}; use crate::prelude::FlexiTile; use crate::BResult; use bracket_color::prelude::RGBA; diff --git a/bracket-terminal/src/hal/webgpu/backing/simple_console_backing.rs b/bracket-terminal/src/hal/webgpu/backing/simple_console_backing.rs index c7445118..e1bae9e7 100644 --- a/bracket-terminal/src/hal/webgpu/backing/simple_console_backing.rs +++ b/bracket-terminal/src/hal/webgpu/backing/simple_console_backing.rs @@ -2,7 +2,10 @@ use super::index_array_helper::IndexBuffer; use super::vertex_array_helper::FloatBuffer; -use crate::hal::{Font, Shader, WgpuLink, scaler::{FontScaler, ScreenScaler}}; +use crate::hal::{ + scaler::{FontScaler, ScreenScaler}, + Font, Shader, WgpuLink, +}; use crate::prelude::Tile; use crate::BResult; use bracket_color::prelude::RGBA; diff --git a/bracket-terminal/src/hal/webgpu/backing/sparse_console_backing.rs b/bracket-terminal/src/hal/webgpu/backing/sparse_console_backing.rs index 4ca3a3af..dc897996 100644 --- a/bracket-terminal/src/hal/webgpu/backing/sparse_console_backing.rs +++ b/bracket-terminal/src/hal/webgpu/backing/sparse_console_backing.rs @@ -1,7 +1,10 @@ //! Provides a wgpu mapping to the sparse consoele use super::index_array_helper::IndexBuffer; use super::vertex_array_helper::FloatBuffer; -use crate::hal::{Font, Shader, WgpuLink, scaler::{FontScaler, ScreenScaler}}; +use crate::hal::{ + scaler::{FontScaler, ScreenScaler}, + Font, Shader, WgpuLink, +}; use crate::prelude::SparseTile; use crate::BResult; use bracket_color::prelude::RGBA; @@ -16,7 +19,7 @@ pub struct SparseConsoleBackend { /// WGPU Render Pipeline to use render_pipeline: RenderPipeline, /// No change optimization - previous_console : Option>, + previous_console: Option>, } impl SparseConsoleBackend { @@ -122,7 +125,7 @@ impl SparseConsoleBackend { if !must_resize { if let Some(old) = &self.previous_console { if old.len() == tiles.len() { - let no_change = tiles.iter().zip(old.iter()).all(|(a, b)| *a==*b); + let no_change = tiles.iter().zip(old.iter()).all(|(a, b)| *a == *b); if no_change { return; } diff --git a/bracket-terminal/src/hal/webgpu/font.rs b/bracket-terminal/src/hal/webgpu/font.rs index b2a1c6c2..4c8396ad 100644 --- a/bracket-terminal/src/hal/webgpu/font.rs +++ b/bracket-terminal/src/hal/webgpu/font.rs @@ -1,7 +1,7 @@ //! WGPU Definition of a font -use bracket_embedding::prelude::EMBED; use crate::BResult; use bracket_color::prelude::RGB; +use bracket_embedding::prelude::EMBED; use image::GenericImageView; use wgpu::{BindGroup, BindGroupLayout, Sampler, TextureView}; @@ -38,7 +38,10 @@ impl Font { tile_size, explicit_background: None, font_dimensions_glyphs: (tile_size.0 / width, tile_size.1 / height), - font_dimensions_texture: ( tile_size.0 as f32 / width as f32, tile_size.1 as f32 / height as f32 ), + font_dimensions_texture: ( + tile_size.0 as f32 / width as f32, + tile_size.1 as f32 / height as f32, + ), view: None, sampler: None, bind_group: None, @@ -70,7 +73,10 @@ impl Font { tile_size, explicit_background, font_dimensions_glyphs: (img.width() / tile_size.0, img.height() / tile_size.1), - font_dimensions_texture: ( tile_size.0 as f32 / img.width() as f32, tile_size.1 as f32 / img.height() as f32), + font_dimensions_texture: ( + tile_size.0 as f32 / img.width() as f32, + tile_size.1 as f32 / img.height() as f32, + ), view: None, sampler: None, bind_group: None, @@ -167,10 +173,10 @@ impl Font { wgpu::BindGroupLayoutEntry { binding: 1, visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), //wgpu::BindingType::Sampler { - //comparison: false, - //filtering: true, + //comparison: false, + //filtering: true, //}, count: None, }, diff --git a/bracket-terminal/src/hal/webgpu/framebuffer.rs b/bracket-terminal/src/hal/webgpu/framebuffer.rs index 6a941393..877d75c1 100644 --- a/bracket-terminal/src/hal/webgpu/framebuffer.rs +++ b/bracket-terminal/src/hal/webgpu/framebuffer.rs @@ -1,6 +1,6 @@ //! Provides a wgpu implementation of a backing buffer. -use wgpu::{Device, Sampler, TextureFormat, TextureView, Texture}; +use wgpu::{Device, Sampler, Texture, TextureFormat, TextureView}; pub struct Framebuffer { pub texture: Texture, @@ -22,7 +22,9 @@ impl Framebuffer { sample_count: 1, dimension: wgpu::TextureDimension::D2, format, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC, + usage: wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::RENDER_ATTACHMENT + | wgpu::TextureUsages::COPY_SRC, }); let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); let sampler = device.create_sampler(&wgpu::SamplerDescriptor { @@ -40,7 +42,11 @@ impl Framebuffer { ..Default::default() }); - Self { view, sampler, texture } + Self { + view, + sampler, + texture, + } } pub fn view(&self) -> &TextureView { diff --git a/bracket-terminal/src/hal/webgpu/init.rs b/bracket-terminal/src/hal/webgpu/init.rs index a8243cc1..095ea868 100644 --- a/bracket-terminal/src/hal/webgpu/init.rs +++ b/bracket-terminal/src/hal/webgpu/init.rs @@ -1,7 +1,10 @@ //! WGPU Initialization Service use super::{InitHints, Shader, WgpuLink, WrappedContext, BACKEND}; -use crate::{gamestate::BTerm, hal::Framebuffer, prelude::BACKEND_INTERNAL, BResult, hal::scaler::ScreenScaler}; +use crate::{ + gamestate::BTerm, hal::scaler::ScreenScaler, hal::Framebuffer, prelude::BACKEND_INTERNAL, + BResult, +}; use wgpu::{Adapter, Device, Instance, Queue, Surface, SurfaceConfiguration}; use winit::{ dpi::LogicalSize, @@ -99,6 +102,7 @@ pub fn init_raw( post_scanlines: false, post_screenburn: false, screen_burn_color: bracket_color::prelude::RGB::from_f32(0.0, 1.0, 1.0), + mouse_visible: true, }; Ok(bterm) } diff --git a/bracket-terminal/src/hal/webgpu/mainloop.rs b/bracket-terminal/src/hal/webgpu/mainloop.rs index 793d671e..8cbfb9ce 100644 --- a/bracket-terminal/src/hal/webgpu/mainloop.rs +++ b/bracket-terminal/src/hal/webgpu/mainloop.rs @@ -6,12 +6,12 @@ use super::{ }; use crate::{ gamestate::{BTerm, GameState}, + hal::scaler::FontScaler, input::{clear_input_state, BEvent}, prelude::{ FlexiConsole, SimpleConsole, SparseConsole, SpriteConsole, BACKEND, BACKEND_INTERNAL, INPUT, }, BResult, - hal::scaler::FontScaler, }; use bracket_geometry::prelude::Point; use std::mem::size_of; @@ -67,6 +67,7 @@ pub fn main_loop(mut bterm: BTerm, mut gamestate: GS) -> BResult< )?; // Additional resize to handle some X11 cases let mut queued_resize_event: Option = None; + #[cfg(feature = "low_cpu")] let spin_sleeper = spin_sleep::SpinSleeper::default(); let my_window_id = window.id(); @@ -119,6 +120,7 @@ pub fn main_loop(mut bterm: BTerm, mut gamestate: GS) -> BResult< let time_since_last_frame = frame_timer.elapsed().as_millis() as u64; if time_since_last_frame < wait_time { let delay = u64::min(33, wait_time - time_since_last_frame); + #[cfg(feature = "low_cpu")] spin_sleeper.sleep(std::time::Duration::from_millis(delay)); } } @@ -191,7 +193,14 @@ pub fn main_loop(mut bterm: BTerm, mut gamestate: GS) -> BResult< let scale_factor = window.scale_factor(); let physical_size = window.inner_size(); //wc.resize(physical_size); - on_resize(&mut bterm, physical_size, scale_factor, false, &mut backing_flip,).unwrap(); + on_resize( + &mut bterm, + physical_size, + scale_factor, + false, + &mut backing_flip, + ) + .unwrap(); bterm.on_event(BEvent::ScaleFactorChanged { new_size: Point::new(new_inner_size.width, new_inner_size.height), dpi_scale_factor: scale_factor as f32, @@ -250,7 +259,12 @@ fn on_resize( INPUT.lock().set_scale_factor(dpi_scale_factor); let mut be = BACKEND.lock(); let (l, r, t, b) = be.screen_scaler.get_backing_buffer_output_coordinates(); - be.screen_scaler.change_physical_size_smooth(physical_size.width, physical_size.height, dpi_scale_factor as f32, font_max_size); + be.screen_scaler.change_physical_size_smooth( + physical_size.width, + physical_size.height, + dpi_scale_factor as f32, + font_max_size, + ); if send_event { bterm.resize_pixels( physical_size.width as u32, @@ -269,7 +283,10 @@ fn on_resize( // Messaging bterm.on_event(BEvent::Resized { - new_size: Point::new(be.screen_scaler.available_width, be.screen_scaler.available_height), + new_size: Point::new( + be.screen_scaler.available_width, + be.screen_scaler.available_height, + ), dpi_scale_factor: dpi_scale_factor as f32, }); diff --git a/bracket-terminal/src/hal/webgpu/platform.rs b/bracket-terminal/src/hal/webgpu/platform.rs index aa8419ce..f546583c 100644 --- a/bracket-terminal/src/hal/webgpu/platform.rs +++ b/bracket-terminal/src/hal/webgpu/platform.rs @@ -1,9 +1,9 @@ //! WGPU Platform definition +use super::Framebuffer; +use crate::hal::scaler::{default_gutter_size, ScreenScaler}; use wgpu::{Adapter, Device, Instance, Queue, Surface, SurfaceConfiguration}; use winit::{event_loop::EventLoop, window::Window}; -use super::Framebuffer; -use crate::hal::scaler::{ ScreenScaler, default_gutter_size }; /// Defines the WGPU platform pub struct PlatformGL { @@ -48,6 +48,7 @@ pub struct InitHints { pub frame_sleep_time: Option, pub resize_scaling: bool, pub desired_gutter: u32, + pub fitscreen: bool, } impl InitHints { @@ -58,6 +59,7 @@ impl InitHints { frame_sleep_time: None, resize_scaling: false, desired_gutter: default_gutter_size(), + fitscreen: false, } } } diff --git a/bracket-terminal/src/hal/webgpu/quadrender.rs b/bracket-terminal/src/hal/webgpu/quadrender.rs index 0ac8b766..cdedbea3 100644 --- a/bracket-terminal/src/hal/webgpu/quadrender.rs +++ b/bracket-terminal/src/hal/webgpu/quadrender.rs @@ -47,12 +47,8 @@ impl QuadRender { // Build the vertex buffer let mut quad_buffer = FloatBuffer::new(&[2, 2], 24, BufferUsages::VERTEX); quad_buffer.data = vec![ - -1.0, 1.0, 0.0, 0.0, - -1.0, -1.0, 0.0, 1.0, - 1.0, -1.0, 1.0, 1.0, - -1.0, 1.0, 0.0, 0.0, - 1.0, -1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 0.0, + -1.0, 1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, + 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, ]; quad_buffer.build(wgpu); @@ -228,14 +224,17 @@ impl QuadRender { Ok(()) } - pub fn update_buffer_with_gutter(&mut self, wgpu: &WgpuLink, left: f32, right: f32, top: f32, bottom: f32) { + pub fn update_buffer_with_gutter( + &mut self, + wgpu: &WgpuLink, + left: f32, + right: f32, + top: f32, + bottom: f32, + ) { self.quad_buffer.data = vec![ - left, top, 0.0, 0.0, - left, bottom ,0.0, 1.0, - right, bottom, 1.0, 1.0, - left, top, 0.0, 0.0, - right, bottom, 1.0, 1.0, - right, top, 1.0, 0.0, + left, top, 0.0, 0.0, left, bottom, 0.0, 1.0, right, bottom, 1.0, 1.0, left, top, 0.0, + 0.0, right, bottom, 1.0, 1.0, right, top, 1.0, 0.0, ]; self.quad_buffer.build(wgpu); } diff --git a/bracket-terminal/src/initializer.rs b/bracket-terminal/src/initializer.rs index 6b85ce37..d3773f7e 100755 --- a/bracket-terminal/src/initializer.rs +++ b/bracket-terminal/src/initializer.rs @@ -450,6 +450,12 @@ impl BTermBuilder { self } + /// Enables you to auto adjust the window to fit the screen. + pub fn with_fitscreen(mut self, fitscreen: bool) -> Self { + self.platform_hints.fitscreen = fitscreen; + self + } + /// Push platform-specific initialization hints to the builder. THIS REMOVES CROSS-PLATFORM COMPATIBILITY pub fn with_platform_specific(mut self, hints: InitHints) -> Self { self.platform_hints = hints; @@ -491,7 +497,7 @@ impl BTermBuilder { pub fn with_gutter(mut self, desired_gutter: u32) -> Self { #[cfg(any(feature = "opengl", feature = "webgpu"))] { - self.platform_hints.desired_gutter = desired_gutter; + self.platform_hints.desired_gutter = desired_gutter; } self } diff --git a/bracket-terminal/src/lib.rs b/bracket-terminal/src/lib.rs index 7061e58c..7a241fe2 100755 --- a/bracket-terminal/src/lib.rs +++ b/bracket-terminal/src/lib.rs @@ -7,7 +7,7 @@ mod hal; mod initializer; mod input; pub mod rex; -pub use bracket_embedding::prelude::{EMBED, link_resource, embedded_resource}; +pub use bracket_embedding::prelude::{embedded_resource, link_resource, EMBED}; pub type BResult = anyhow::Result>; pub(crate) use input::clear_input_state; @@ -24,7 +24,6 @@ pub mod prelude { pub use crate::bterm::*; pub use crate::consoles::*; - pub use bracket_embedding::prelude::{EMBED, link_resource, embedded_resource}; pub use crate::gamestate::GameState; pub use crate::hal::{init_raw, BTermPlatform, Font, InitHints, Shader, BACKEND}; pub use crate::initializer::*; @@ -34,6 +33,7 @@ pub mod prelude { pub use crate::BResult; pub use crate::FontCharType; pub use bracket_color::prelude::*; + pub use bracket_embedding::prelude::{embedded_resource, link_resource, EMBED}; pub use bracket_geometry::prelude::*; pub type BError = std::result::Result<(), Box>; diff --git a/bracket-terminal/src/rex.rs b/bracket-terminal/src/rex.rs index 2ddfde19..ff029c1b 100755 --- a/bracket-terminal/src/rex.rs +++ b/bracket-terminal/src/rex.rs @@ -1,7 +1,7 @@ use crate::prelude::{Console, DrawBatch, FontCharType}; use bracket_color::prelude::{ColorPair, RGBA}; use bracket_geometry::prelude::Point; -pub use bracket_rex::prelude::{ XpCell, XpLayer, XpFile, XpColor }; +pub use bracket_rex::prelude::{XpCell, XpColor, XpFile, XpLayer}; /// Applies an XpFile to a given console, with 0,0 offset by offset_x and offset-y. pub fn xp_to_console( diff --git a/rltk/Cargo.toml b/rltk/Cargo.toml index b1ec767e..e453b42f 100755 --- a/rltk/Cargo.toml +++ b/rltk/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "rltk" -version = "0.8.1" +version = "0.8.7" authors = ["Herbert Wolverson "] -edition = "2018" +edition = "2021" publish = true description = "A CP437/ASCII terminal library and helpers to make creating roguelike games in Rust easy. Similar to libtcod, but aiming to be Rust-native." homepage = "https://github.com/thebracket/bracket-lib" @@ -11,19 +11,20 @@ readme = "README.md" keywords = ["roguelike", "cp437", "ascii", "virtual-terminal", "gamedev"] categories = ["game-engines", "graphics"] license = "MIT" -resolver = "2" # Enables the new Cargo resolution engine +resolver = "2" # Enables the new Cargo resolution engine [features] -default = [ "opengl" ] -specs = [ "bracket-lib/specs" ] -serde = [ "bracket-lib/serde" ] -threaded = [ "bracket-lib/threaded" ] -opengl = [ "bracket-lib/opengl" ] -curses = [ "bracket-lib/curses" ] -crossterm = [ "bracket-lib/crossterm" ] -webgpu = [ "bracket-lib/webgpu" ] +default = ["opengl"] +bevy = ["bracket-lib/bevy"] +specs = ["bracket-lib/specs"] +serde = ["bracket-lib/serde"] +threaded = ["bracket-lib/threaded"] +opengl = ["bracket-lib/opengl"] +curses = ["bracket-lib/curses"] +crossterm = ["bracket-lib/crossterm"] +webgpu = ["bracket-lib/webgpu"] [dependencies] -bracket-lib = { path = "../", version = "~0.8.1", default-features = false } +bracket-lib = { path = "../", version = "~0.8", default-features = false } [dev-dependencies] diff --git a/rltk/src/lib.rs b/rltk/src/lib.rs index 1afbafd3..fad329bd 100755 --- a/rltk/src/lib.rs +++ b/rltk/src/lib.rs @@ -20,4 +20,4 @@ pub mod prelude { pub mod embedding { pub use bracket_lib::prelude::EMBED; -} \ No newline at end of file +}