From 606ae6c1385b21cdc48a8104e73f10e50e4f54ce Mon Sep 17 00:00:00 2001 From: Andreas Hempel Date: Thu, 10 Feb 2022 14:26:08 +0100 Subject: [PATCH 01/41] Derive Debug trait for enums used in fastnoise module This allows using these types in structs that want to derive Debug themselves --- bracket-noise/src/fastnoise.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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, From 0bb5980082f3adc453b7b1d61baf71555c14b716 Mon Sep 17 00:00:00 2001 From: joe Date: Fri, 29 Apr 2022 20:34:22 -0700 Subject: [PATCH 02/41] Added ability for the user to enable or disable the mouse cursor when using the native gl backend --- bracket-terminal/src/bterm.rs | 6 ++++++ bracket-terminal/src/hal/crossterm_be/init.rs | 1 + bracket-terminal/src/hal/curses/init.rs | 1 + bracket-terminal/src/hal/native/init.rs | 1 + bracket-terminal/src/hal/native/mainloop.rs | 2 ++ bracket-terminal/src/hal/wasm/init.rs | 1 + bracket-terminal/src/hal/webgpu/init.rs | 1 + 7 files changed, 13 insertions(+) diff --git a/bracket-terminal/src/bterm.rs b/bracket-terminal/src/bterm.rs index 8e269c97..c694e87b 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 { @@ -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/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/curses/init.rs b/bracket-terminal/src/hal/curses/init.rs index 7ba97de2..21f0207c 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/native/init.rs b/bracket-terminal/src/hal/native/init.rs index 22ac229c..d2759a58 100755 --- a/bracket-terminal/src/hal/native/init.rs +++ b/bracket-terminal/src/hal/native/init.rs @@ -130,6 +130,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 4535fb7a..86668ab6 100755 --- a/bracket-terminal/src/hal/native/mainloop.rs +++ b/bracket-terminal/src/hal/native/mainloop.rs @@ -148,6 +148,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(); diff --git a/bracket-terminal/src/hal/wasm/init.rs b/bracket-terminal/src/hal/wasm/init.rs index 348b1712..3da604c2 100755 --- a/bracket-terminal/src/hal/wasm/init.rs +++ b/bracket-terminal/src/hal/wasm/init.rs @@ -100,5 +100,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/webgpu/init.rs b/bracket-terminal/src/hal/webgpu/init.rs index 5e385cc7..adbdbd6f 100644 --- a/bracket-terminal/src/hal/webgpu/init.rs +++ b/bracket-terminal/src/hal/webgpu/init.rs @@ -99,6 +99,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) } From f75d0419db3c636986d9829a1d4ff4708002f84d Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Mon, 1 Aug 2022 13:14:17 -0500 Subject: [PATCH 03/41] Cargo fmt run on everything. --- bracket-bevy/src/builder/bterm_builder.rs | 2 +- bracket-bevy/src/builder/image_fixer.rs | 20 +- bracket-bevy/src/builder/loader_system.rs | 4 +- bracket-bevy/src/builder/mod.rs | 2 +- bracket-color/src/rgb.rs | 6 +- bracket-embedding/src/embedding.rs | 7 +- .../examples/dijkstra_weighted/main.rs | 2 +- bracket-pathfinding/src/dijkstra.rs | 8 +- bracket-pathfinding/src/field_of_view/mod.rs | 4 +- bracket-random/src/lib.rs | 2 +- bracket-rex/src/lib.rs | 2 +- bracket-rex/src/rex.rs | 4 +- bracket-rex/src/xpcolor.rs | 2 +- bracket-terminal/examples/batch_z_order.rs | 9 +- bracket-terminal/src/bterm.rs | 4 +- .../src/consoles/command_buffer.rs | 413 +++++++++++------- .../src/hal/crossterm_be/main_loop.rs | 10 +- .../backing/simple_console_backing.rs | 4 +- .../backing/sparse_console_backing.rs | 9 +- .../backing/sprite_console_backing.rs | 4 +- bracket-terminal/src/hal/gl_common/font.rs | 12 +- .../src/hal/gl_common/quadrender.rs | 10 +- bracket-terminal/src/hal/native/init.rs | 5 +- bracket-terminal/src/hal/native/mainloop.rs | 32 +- bracket-terminal/src/hal/native/mod.rs | 2 +- bracket-terminal/src/hal/scaler.rs | 43 +- bracket-terminal/src/hal/wasm/init.rs | 5 +- bracket-terminal/src/hal/wasm/mod.rs | 2 +- bracket-terminal/src/hal/webgpu/backend.rs | 2 +- .../webgpu/backing/fancy_console_backing.rs | 5 +- .../webgpu/backing/simple_console_backing.rs | 5 +- .../webgpu/backing/sparse_console_backing.rs | 9 +- bracket-terminal/src/hal/webgpu/font.rs | 18 +- .../src/hal/webgpu/framebuffer.rs | 12 +- bracket-terminal/src/hal/webgpu/init.rs | 5 +- bracket-terminal/src/hal/webgpu/mainloop.rs | 23 +- bracket-terminal/src/hal/webgpu/platform.rs | 4 +- bracket-terminal/src/hal/webgpu/quadrender.rs | 25 +- bracket-terminal/src/initializer.rs | 2 +- bracket-terminal/src/lib.rs | 4 +- bracket-terminal/src/rex.rs | 2 +- rltk/src/lib.rs | 2 +- 42 files changed, 471 insertions(+), 276 deletions(-) diff --git a/bracket-bevy/src/builder/bterm_builder.rs b/bracket-bevy/src/builder/bterm_builder.rs index 38a7ad35..378984ad 100644 --- a/bracket-bevy/src/builder/bterm_builder.rs +++ b/bracket-bevy/src/builder/bterm_builder.rs @@ -3,7 +3,7 @@ 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}, diff --git a/bracket-bevy/src/builder/image_fixer.rs b/bracket-bevy/src/builder/image_fixer.rs index a1d4d952..a423aac4 100644 --- a/bracket-bevy/src/builder/image_fixer.rs +++ b/bracket-bevy/src/builder/image_fixer.rs @@ -1,11 +1,11 @@ -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); +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; } @@ -13,7 +13,7 @@ pub(crate) fn fix_images( 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{ + 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 +25,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..d66a1fe4 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, }; 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-color/src/rgb.rs b/bracket-color/src/rgb.rs index ed361022..c1dd1bc8 100755 --- a/bracket-color/src/rgb.rs +++ b/bracket-color/src/rgb.rs @@ -258,11 +258,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-embedding/src/embedding.rs b/bracket-embedding/src/embedding.rs index ac9b5c6d..07c4e514 100644 --- a/bracket-embedding/src/embedding.rs +++ b/bracket-embedding/src/embedding.rs @@ -1,8 +1,9 @@ -use std::collections::HashMap; -use parking_lot::Mutex; use lazy_static::*; +use parking_lot::Mutex; +use std::collections::HashMap; -const TERMINAL_8_8_BYTES: &[u8] = include_bytes!("../../bracket-terminal/resources/terminal8x8.png"); +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"); lazy_static! { 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/dijkstra.rs b/bracket-pathfinding/src/dijkstra.rs index 238fd0e3..92a68e6d 100755 --- a/bracket-pathfinding/src/dijkstra.rs +++ b/bracket-pathfinding/src/dijkstra.rs @@ -136,7 +136,11 @@ impl DijkstraMap { } #[cfg(feature = "threaded")] - fn build_helper_weighted(dm: &mut DijkstraMap, starts: &[(usize, f32)], map: &dyn BaseMap) -> RunThreaded { + 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; @@ -265,7 +269,7 @@ impl DijkstraMap { } } - #[cfg(feature = "threaded")] + #[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()); 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/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/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/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/src/bterm.rs b/bracket-terminal/src/bterm.rs index c694e87b..e7af4efb 100755 --- a/bracket-terminal/src/bterm.rs +++ b/bracket-terminal/src/bterm.rs @@ -250,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(); 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/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/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/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/native/init.rs b/bracket-terminal/src/hal/native/init.rs index d2759a58..a165e052 100755 --- a/bracket-terminal/src/hal/native/init.rs +++ b/bracket-terminal/src/hal/native/init.rs @@ -48,7 +48,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 diff --git a/bracket-terminal/src/hal/native/mainloop.rs b/bracket-terminal/src/hal/native/mainloop.rs index d1235013..eabc0b50 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; @@ -349,7 +357,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, + ); } } @@ -384,7 +397,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..6d951f1b 100755 --- a/bracket-terminal/src/hal/native/mod.rs +++ b/bracket-terminal/src/hal/native/mod.rs @@ -2,11 +2,11 @@ mod init; pub mod shader_strings; 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); 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 3da604c2..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,6 +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 + mouse_visible: true, }) } diff --git a/bracket-terminal/src/hal/wasm/mod.rs b/bracket-terminal/src/hal/wasm/mod.rs index c2f3fa32..29cbbc67 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); 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 5f7910db..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, diff --git a/bracket-terminal/src/hal/webgpu/mainloop.rs b/bracket-terminal/src/hal/webgpu/mainloop.rs index 793d671e..6a447814 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; @@ -191,7 +191,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 +257,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 +281,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..9a303e10 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 { 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..a876a9cd 100755 --- a/bracket-terminal/src/initializer.rs +++ b/bracket-terminal/src/initializer.rs @@ -491,7 +491,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/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 +} From 71b8b3a4011eb17b5632f4850a149334c026fbae Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Mon, 1 Aug 2022 15:45:12 -0500 Subject: [PATCH 04/41] Improve bracket-color documentation. --- bracket-color/README.md | 1 + bracket-color/src/color_pair.rs | 7 ++++ bracket-color/src/hsv.rs | 27 ++++++++++++++ bracket-color/src/lerpit.rs | 18 +++++++++- bracket-color/src/named.rs | 2 ++ bracket-color/src/palette.rs | 27 +++++++++++++- bracket-color/src/rgb.rs | 60 +++++++++++++++++++++++++++++++ bracket-color/src/rgba.rs | 62 +++++++++++++++++++++++++++++++++ 8 files changed, 202 insertions(+), 2 deletions(-) diff --git a/bracket-color/README.md b/bracket-color/README.md index 0cce1b0a..199f2ce2 100755 --- a/bracket-color/README.md +++ b/bracket-color/README.md @@ -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/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/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 c1dd1bc8..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(); diff --git a/bracket-color/src/rgba.rs b/bracket-color/src/rgba.rs index 756fdb11..ab592662 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,6 +294,7 @@ 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] { From 3ab871dbeab395933bd91209d690d2727ab9f5cd Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Mon, 1 Aug 2022 15:58:00 -0500 Subject: [PATCH 05/41] Fix WGPU spin sleeper --- bracket-terminal/src/hal/webgpu/mainloop.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bracket-terminal/src/hal/webgpu/mainloop.rs b/bracket-terminal/src/hal/webgpu/mainloop.rs index 6a447814..8cbfb9ce 100644 --- a/bracket-terminal/src/hal/webgpu/mainloop.rs +++ b/bracket-terminal/src/hal/webgpu/mainloop.rs @@ -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)); } } From 6a8e09118ad4e238e2e19fbd77387c1817c4dce4 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Mon, 1 Aug 2022 16:02:00 -0500 Subject: [PATCH 06/41] Revert winit bump; going above 0.26 breaks wgpu support. --- bracket-terminal/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bracket-terminal/Cargo.toml b/bracket-terminal/Cargo.toml index 23f40932..153b9fee 100755 --- a/bracket-terminal/Cargo.toml +++ b/bracket-terminal/Cargo.toml @@ -37,7 +37,7 @@ 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" } +winit = { version = "0.26" } spin_sleep = { version = "1.0.0", optional = true } [features] @@ -62,7 +62,7 @@ wasm-bindgen = "0.2" wasm-timer = "0.1.0" rand = { version = "0.8.3", default-features = false } console_error_panic_hook = "0.1.6" -winit = { version = "0.27" } +winit = { version = "0.26" } [[bench]] name = "batching_benchmark" From 83273b55d116b54aadb94fba1750993aa1103140 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Mon, 1 Aug 2022 16:07:21 -0500 Subject: [PATCH 07/41] Roll back glutin also, for winit compatibility. --- bracket-terminal/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bracket-terminal/Cargo.toml b/bracket-terminal/Cargo.toml index 153b9fee..218d6ceb 100755 --- a/bracket-terminal/Cargo.toml +++ b/bracket-terminal/Cargo.toml @@ -36,7 +36,7 @@ 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 } +glutin = {version = "0.28", optional = true } winit = { version = "0.26" } spin_sleep = { version = "1.0.0", optional = true } From 10f2b9d3c237125e6a456dae0f291a4b6f18a5dc Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Mon, 1 Aug 2022 16:24:50 -0500 Subject: [PATCH 08/41] Better documentation for bracket-embedding. --- bracket-embedding/src/embedding.rs | 5 +++ bracket-embedding/src/lib.rs | 64 ++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/bracket-embedding/src/embedding.rs b/bracket-embedding/src/embedding.rs index 07c4e514..be68b0d2 100644 --- a/bracket-embedding/src/embedding.rs +++ b/bracket-embedding/src/embedding.rs @@ -2,6 +2,7 @@ use lazy_static::*; use parking_lot::Mutex; use std::collections::HashMap; +// These are included by default in `bracket-terminal`. 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"); @@ -10,12 +11,14 @@ 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. pub fn new() -> Dictionary { let mut dict = Dictionary { entries: HashMap::new(), @@ -25,6 +28,7 @@ impl Dictionary { dict } + /// Request a resource, returning either a byte array or `None`. pub fn get_resource(&self, path: String) -> Option<&'static [u8]> { let fixed_path = if std::path::MAIN_SEPARATOR != '/' { path.replace(std::path::MAIN_SEPARATOR, "/") @@ -38,6 +42,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..f2afb4d2 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)] +#![warn(clippy::missing_docs)] 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) => { From d607395a84666bbed19aca684e74c7d5e01dc52d Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Mon, 1 Aug 2022 16:35:43 -0500 Subject: [PATCH 09/41] Clippy and docs for embedding --- bracket-embedding/Cargo.toml | 2 +- bracket-embedding/src/embedding.rs | 10 ++++++---- bracket-embedding/src/lib.rs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bracket-embedding/Cargo.toml b/bracket-embedding/Cargo.toml index 5376efa6..3ce8682d 100644 --- a/bracket-embedding/Cargo.toml +++ b/bracket-embedding/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-embedding" version = "0.8.0" edition = "2018" -publish = false +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/src/embedding.rs b/bracket-embedding/src/embedding.rs index be68b0d2..57398d0a 100644 --- a/bracket-embedding/src/embedding.rs +++ b/bracket-embedding/src/embedding.rs @@ -1,4 +1,4 @@ -use lazy_static::*; +use lazy_static::lazy_static; use parking_lot::Mutex; use std::collections::HashMap; @@ -19,6 +19,7 @@ pub struct Dictionary { impl Dictionary { /// Create a new, empty dictionary. + #[must_use] pub fn new() -> Dictionary { let mut dict = Dictionary { entries: HashMap::new(), @@ -29,11 +30,12 @@ impl Dictionary { } /// 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) { diff --git a/bracket-embedding/src/lib.rs b/bracket-embedding/src/lib.rs index f2afb4d2..7f105f98 100644 --- a/bracket-embedding/src/lib.rs +++ b/bracket-embedding/src/lib.rs @@ -18,7 +18,7 @@ //! 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)] -#![warn(clippy::missing_docs)] +#![allow(clippy::needless_doctest_main)] mod embedding; pub mod prelude { From b554132014f465dd7eecaa381f958e85f8bf357d Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 2 Aug 2022 07:57:10 -0500 Subject: [PATCH 10/41] Starting on docs for bracket-geometry --- bracket-geometry/src/angle.rs | 10 ++++++++ bracket-geometry/src/circle_bresenham.rs | 12 +++++++++ bracket-geometry/src/distance.rs | 5 ++++ bracket-geometry/src/lib.rs | 4 +++ bracket-geometry/src/line_bresenham.rs | 8 +++--- bracket-geometry/src/line_vector.rs | 3 +++ bracket-geometry/src/lines.rs | 2 ++ bracket-geometry/src/point.rs | 20 ++++++++++++--- bracket-geometry/src/point3.rs | 4 +++ bracket-geometry/src/rect.rs | 31 ++++++++++++++++-------- bracket-geometry/src/rectf.rs | 27 +++++++++++++++------ 11 files changed, 100 insertions(+), 26 deletions(-) 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..bc21ad15 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) 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..17e42b07 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, } @@ -32,18 +35,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 +57,7 @@ impl Point { #[inline] /// Helper for map index conversion + #[must_use] pub fn to_index(self, width: T) -> usize where T: TryInto, @@ -64,11 +69,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 +88,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 +101,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..aabda62d 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, } @@ -30,6 +33,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) } From 669c6b54e5210c638897433047d6e646fdde73a9 Mon Sep 17 00:00:00 2001 From: Jacob LeCoq Date: Fri, 5 Aug 2022 21:10:27 -0500 Subject: [PATCH 11/41] remove duplicate parellel function --- bracket-pathfinding/src/dijkstra.rs | 54 ----------------------------- 1 file changed, 54 deletions(-) diff --git a/bracket-pathfinding/src/dijkstra.rs b/bracket-pathfinding/src/dijkstra.rs index 92a68e6d..6ebc17db 100755 --- a/bracket-pathfinding/src/dijkstra.rs +++ b/bracket-pathfinding/src/dijkstra.rs @@ -269,60 +269,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. From e9b0be10501a6324262379cbea50f95cd040c4ce Mon Sep 17 00:00:00 2001 From: Jacob LeCoq Date: Fri, 5 Aug 2022 21:17:38 -0500 Subject: [PATCH 12/41] remove unused function --- bracket-pathfinding/src/dijkstra.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/bracket-pathfinding/src/dijkstra.rs b/bracket-pathfinding/src/dijkstra.rs index 6ebc17db..11a98797 100755 --- a/bracket-pathfinding/src/dijkstra.rs +++ b/bracket-pathfinding/src/dijkstra.rs @@ -135,19 +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. From a56154930108eae3904f1f0024fce6463bfafb8b Mon Sep 17 00:00:00 2001 From: Jacob LeCoq Date: Fri, 5 Aug 2022 21:20:51 -0500 Subject: [PATCH 13/41] add point to bevy component ecs --- Cargo.toml | 1 + bracket-bevy/Cargo.toml | 2 +- bracket-geometry/Cargo.toml | 9 +++++---- bracket-geometry/src/point.rs | 5 +++++ bracket-geometry/src/point3.rs | 5 +++++ rltk/Cargo.toml | 19 ++++++++++--------- 6 files changed, 27 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 992aa165..cc8869e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ resolver = "2" # Enables the new Cargo resolution engine [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" ] diff --git a/bracket-bevy/Cargo.toml b/bracket-bevy/Cargo.toml index 45626125..7fdeeff3 100644 --- a/bracket-bevy/Cargo.toml +++ b/bracket-bevy/Cargo.toml @@ -18,7 +18,7 @@ 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.3", features = [ "bevy" ] } [dev-dependencies] bracket-pathfinding = { path = "../bracket-pathfinding", version = "~0.8.4" } diff --git a/bracket-geometry/Cargo.toml b/bracket-geometry/Cargo.toml index 729cb8cb..381d1113 100755 --- a/bracket-geometry/Cargo.toml +++ b/bracket-geometry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-geometry" -version = "0.8.3" +version = "0.8.4" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -13,9 +13,10 @@ 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.8.0", optional = true } +ultraviolet = "~0.9.0" [dev-dependencies] crossterm = "~0.24" diff --git a/bracket-geometry/src/point.rs b/bracket-geometry/src/point.rs index d885d55b..e1f1140c 100755 --- a/bracket-geometry/src/point.rs +++ b/bracket-geometry/src/point.rs @@ -17,6 +17,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] diff --git a/bracket-geometry/src/point3.rs b/bracket-geometry/src/point3.rs index 095ac8ff..84be004a 100755 --- a/bracket-geometry/src/point3.rs +++ b/bracket-geometry/src/point3.rs @@ -16,6 +16,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 diff --git a/rltk/Cargo.toml b/rltk/Cargo.toml index b1ec767e..36a60692 100755 --- a/rltk/Cargo.toml +++ b/rltk/Cargo.toml @@ -11,17 +11,18 @@ 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 } From 6a41cdb519b57283c0c166c1483e9cb6b666bf86 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Wed, 10 Aug 2022 08:10:30 -0500 Subject: [PATCH 14/41] #255 #278 (thanks for patchfx) Correctly clears fancy/flexible consoles after CLS --- bracket-terminal/src/consoles/flexible_console.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bracket-terminal/src/consoles/flexible_console.rs b/bracket-terminal/src/consoles/flexible_console.rs index 20f7520d..5ab79571 100755 --- a/bracket-terminal/src/consoles/flexible_console.rs +++ b/bracket-terminal/src/consoles/flexible_console.rs @@ -106,13 +106,21 @@ impl Console for FlexiConsole { /// Clear the screen. fn cls(&mut self) { 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); + } } /// 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. From 2c074c4a6db162758000b577e0edc84eb6452404 Mon Sep 17 00:00:00 2001 From: Richard Patching Date: Wed, 10 Aug 2022 14:33:10 +0100 Subject: [PATCH 15/41] Remove duplicate call to post scanlines processing (#285) --- bracket-terminal/examples/flexible.rs | 1 - 1 file changed, 1 deletion(-) 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, From 34ba81211c8583d29dca8decef57a2ecd8269a8b Mon Sep 17 00:00:00 2001 From: bilowik Date: Wed, 10 Aug 2022 11:39:55 -0400 Subject: [PATCH 16/41] Get SpriteConsole's sprite sheet when rendering sprite (#287) --- bracket-terminal/src/hal/gl_common/backing/shared_main_loop.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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)?; } } } From ee721465991f25abab91a85255a6269a4b2f95d8 Mon Sep 17 00:00:00 2001 From: Jacob LeCoq Date: Tue, 4 Oct 2022 07:45:18 -0500 Subject: [PATCH 17/41] properly clear screen (#297) --- bracket-bevy/src/consoles/simple_console/front_end.rs | 4 +++- bracket-bevy/src/consoles/virtual_console.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) 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/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) { From 9cd209ef52708ef9837b68879324397b3c4e8316 Mon Sep 17 00:00:00 2001 From: Richard Patching Date: Tue, 4 Oct 2022 13:47:17 +0100 Subject: [PATCH 18/41] Fix tiles incrementing each frame (#295) --- .../src/consoles/flexible_console.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/bracket-terminal/src/consoles/flexible_console.rs b/bracket-terminal/src/consoles/flexible_console.rs index 5ab79571..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. @@ -106,11 +108,17 @@ impl Console for FlexiConsole { /// Clear the screen. fn cls(&mut self) { self.is_dirty = true; - 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); - } + 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. From 0660ce853122af5c9a4d57e3b9c2c629fd3c0d7e Mon Sep 17 00:00:00 2001 From: indubitablement2 <62550921+indubitablement2@users.noreply.github.com> Date: Tue, 4 Oct 2022 09:00:58 -0400 Subject: [PATCH 19/41] Add new bresenham iterator that yield end point (#292) --- bracket-geometry/src/line_bresenham.rs | 162 ++++++++++++++++++------- 1 file changed, 119 insertions(+), 43 deletions(-) diff --git a/bracket-geometry/src/line_bresenham.rs b/bracket-geometry/src/line_bresenham.rs index bc21ad15..7a5c6a15 100755 --- a/bracket-geometry/src/line_bresenham.rs +++ b/bracket-geometry/src/line_bresenham.rs @@ -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] From 564bd033976ca25242e8abb65bf37ba11d4044fd Mon Sep 17 00:00:00 2001 From: nedondev <38292480+nedondev@users.noreply.github.com> Date: Tue, 4 Oct 2022 20:06:40 +0700 Subject: [PATCH 20/41] Add option to set screen resize (#291) --- bracket-terminal/src/hal/crossterm_be/mod.rs | 2 ++ bracket-terminal/src/hal/dummy/mod.rs | 2 ++ bracket-terminal/src/hal/native/init.rs | 1 + bracket-terminal/src/hal/native/mod.rs | 3 +++ bracket-terminal/src/hal/webgpu/platform.rs | 2 ++ bracket-terminal/src/initializer.rs | 6 ++++++ 6 files changed, 16 insertions(+) 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/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/native/init.rs b/bracket-terminal/src/hal/native/init.rs index a165e052..47ba97be 100755 --- a/bracket-terminal/src/hal/native/init.rs +++ b/bracket-terminal/src/hal/native/init.rs @@ -17,6 +17,7 @@ pub fn init_raw( let el = EventLoop::new(); let wb = WindowBuilder::new() .with_title(window_title.to_string()) + .with_resizable(platform_hints.fitscreen) .with_min_inner_size(scaler.new_window_size()) .with_inner_size(scaler.new_window_size()); let windowed_context = ContextBuilder::new() diff --git a/bracket-terminal/src/hal/native/mod.rs b/bracket-terminal/src/hal/native/mod.rs index 6d951f1b..2ff9f620 100755 --- a/bracket-terminal/src/hal/native/mod.rs +++ b/bracket-terminal/src/hal/native/mod.rs @@ -60,6 +60,7 @@ pub struct InitHints { pub frame_sleep_time: Option, pub resize_scaling: bool, pub desired_gutter: u32, + pub fitscreen: bool, } impl InitHints { @@ -74,6 +75,7 @@ impl InitHints { frame_sleep_time: None, resize_scaling: false, desired_gutter: default_gutter_size(), + fitscreen: false, } } } @@ -90,6 +92,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/webgpu/platform.rs b/bracket-terminal/src/hal/webgpu/platform.rs index 9a303e10..f546583c 100644 --- a/bracket-terminal/src/hal/webgpu/platform.rs +++ b/bracket-terminal/src/hal/webgpu/platform.rs @@ -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/initializer.rs b/bracket-terminal/src/initializer.rs index a876a9cd..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; From ab957c28c6ffe50207b15dcc70911f5285c021c0 Mon Sep 17 00:00:00 2001 From: Funnisimo Date: Tue, 4 Oct 2022 07:20:59 -0600 Subject: [PATCH 21/41] re-export color mods separately (#289) * export colors mods separately to aid precise imports * use updated bracket-color --- Cargo.toml | 2 +- bracket-color/Cargo.toml | 6 +++--- bracket-color/examples/util/mod.rs | 2 +- bracket-color/src/lib.rs | 14 +++++++------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 992aa165..c1bc8267 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ 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-color = { path = "./bracket-color", version = "~0.8.3", 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" } diff --git a/bracket-color/Cargo.toml b/bracket-color/Cargo.toml index 3c5122c0..564d5439 100755 --- a/bracket-color/Cargo.toml +++ b/bracket-color/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-color" -version = "0.8.2" +version = "0.8.3" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -17,13 +17,13 @@ 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 } [dev-dependencies] -crossterm = "~0.24" +crossterm = "~0.25" [[example]] name = "colors" 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/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 { From e195fe14fcf9563e67dd091a8fbd5987cbae11d3 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 09:39:31 -0500 Subject: [PATCH 22/41] Update Criterion dependency version in random. --- bracket-random/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bracket-random/Cargo.toml b/bracket-random/Cargo.toml index 0e730092..b975a9fe 100755 --- a/bracket-random/Cargo.toml +++ b/bracket-random/Cargo.toml @@ -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]] From cb27aca16b7085bcf397c12cfc4dbbb8eec3ed57 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 09:50:02 -0500 Subject: [PATCH 23/41] Update crossterm to 0.25 in bracket-geometry --- bracket-geometry/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bracket-geometry/Cargo.toml b/bracket-geometry/Cargo.toml index 381d1113..90c2c94d 100755 --- a/bracket-geometry/Cargo.toml +++ b/bracket-geometry/Cargo.toml @@ -19,4 +19,4 @@ bevy = { version = "~0.8.0", optional = true } ultraviolet = "~0.9.0" [dev-dependencies] -crossterm = "~0.24" +crossterm = "~0.25" From 5a43d9eefdbe0e5cb3223d29fa8e47c1ec3d6b10 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 09:51:39 -0500 Subject: [PATCH 24/41] Update crossterm for bracket-noise --- bracket-noise/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bracket-noise/Cargo.toml b/bracket-noise/Cargo.toml index 58261eb7..95a57202 100755 --- a/bracket-noise/Cargo.toml +++ b/bracket-noise/Cargo.toml @@ -18,5 +18,5 @@ license = "MIT" bracket-random = { path = "../bracket-random", version = "~0.8.2" } [dev-dependencies] -crossterm = "~0.24" +crossterm = "~0.25" bracket-color = { path = "../bracket-color", version = "~0.8.2", features = [ "palette" ] } From ac42fc2d2d988d4eaa41541fd9283e994a1508fc Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 10:22:39 -0500 Subject: [PATCH 25/41] Fix up dependency versions in bracket-pathfinding. Fix the a-star calculations, the astar example actually finds a path now (updates logic from #268) --- bracket-pathfinding/Cargo.toml | 4 ++-- bracket-pathfinding/examples/astar/common.rs | 23 +++++--------------- bracket-pathfinding/examples/astar/main.rs | 2 ++ bracket-pathfinding/src/astar.rs | 2 +- 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/bracket-pathfinding/Cargo.toml b/bracket-pathfinding/Cargo.toml index 877bbb1c..f13b1fc1 100755 --- a/bracket-pathfinding/Cargo.toml +++ b/bracket-pathfinding/Cargo.toml @@ -25,10 +25,10 @@ rayon = { version = "1.5.0", optional = true } smallvec = "~1" [dev-dependencies] -crossterm = "~0.24" +crossterm = "~0.25" bracket-random = { path = "../bracket-random", version = "0.8.2" } bracket-color = { path = "../bracket-color", version = "~0.8.2", features = [ "palette" ] } -criterion = "0.3.4" +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/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 From 880579b00032525443c53c2bee4c0d7cd59ce70d Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 10:54:05 -0500 Subject: [PATCH 26/41] Update to latest Glutin, including the various type changes it required. --- bracket-terminal/Cargo.toml | 4 ++-- bracket-terminal/examples/native_gl.rs | 5 +++-- bracket-terminal/src/hal/gl_common/framebuffer.rs | 6 +++--- bracket-terminal/src/hal/gl_common/types_native.rs | 10 ++++++---- bracket-terminal/src/hal/native/mod.rs | 3 ++- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/bracket-terminal/Cargo.toml b/bracket-terminal/Cargo.toml index 218d6ceb..45fe37a9 100755 --- a/bracket-terminal/Cargo.toml +++ b/bracket-terminal/Cargo.toml @@ -22,10 +22,10 @@ bracket-rex = { path = "../bracket-rex", version = "~0.8.0" } bracket-embedding = { path = "../bracket-embedding", version = "~0.8.0" } 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" } 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/src/hal/gl_common/framebuffer.rs b/bracket-terminal/src/hal/gl_common/framebuffer.rs index 5a555db5..9b876c15 100755 --- a/bracket-terminal/src/hal/gl_common/framebuffer.rs +++ b/bracket-terminal/src/hal/gl_common/framebuffer.rs @@ -1,11 +1,11 @@ #[allow(unused_imports)] use crate::BResult; -use glow::HasContext; +use glow::{HasContext, NativeFramebuffer, NativeTexture}; #[cfg(not(target_arch = "wasm32"))] pub struct Framebuffer { - fbo: u32, - pub texture: u32, + fbo: NativeFramebuffer, + pub texture: NativeTexture, } #[cfg(target_arch = "wasm32")] diff --git a/bracket-terminal/src/hal/gl_common/types_native.rs b/bracket-terminal/src/hal/gl_common/types_native.rs index 2e10d676..2306ce67 100755 --- a/bracket-terminal/src/hal/gl_common/types_native.rs +++ b/bracket-terminal/src/hal/gl_common/types_native.rs @@ -1,4 +1,6 @@ -pub type TextureId = u32; -pub type BufferId = u32; -pub type VertexArrayId = u32; -pub type ShaderId = u32; +use glow::{NativeTexture, NativeBuffer, NativeVertexArray, NativeProgram}; + +pub type TextureId = NativeTexture; +pub type BufferId = NativeBuffer; +pub type VertexArrayId = NativeVertexArray; +pub type ShaderId = NativeProgram; diff --git a/bracket-terminal/src/hal/native/mod.rs b/bracket-terminal/src/hal/native/mod.rs index 2ff9f620..39fc1df7 100755 --- a/bracket-terminal/src/hal/native/mod.rs +++ b/bracket-terminal/src/hal/native/mod.rs @@ -1,5 +1,6 @@ mod init; pub mod shader_strings; +use glow::NativeVertexArray; pub use init::*; mod mainloop; use crate::hal::scaler::{default_gutter_size, ScreenScaler}; @@ -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, From 02bc1be0875499032f71e404937433ebc466ce2e Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 11:03:11 -0500 Subject: [PATCH 27/41] Update bracket-terminal dependencies --- bracket-terminal/Cargo.toml | 6 +++--- bracket-terminal/src/hal/native/init.rs | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bracket-terminal/Cargo.toml b/bracket-terminal/Cargo.toml index 45fe37a9..cbf384cb 100755 --- a/bracket-terminal/Cargo.toml +++ b/bracket-terminal/Cargo.toml @@ -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.28", optional = true } -winit = { version = "0.26" } +glutin = {version = "~0.29", optional = true } +winit = { version = "~0.27" } spin_sleep = { version = "1.0.0", optional = true } [features] @@ -52,7 +52,7 @@ webgpu = [ "wgpu", "pollster", "image", "bytemuck", "png" ] 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" +criterion = "~0.4" [target.wasm32-unknown-unknown.dependencies] web-sys = { version = "0.3", features=["console", "Attr", "CanvasRenderingContext2d", "Document", "Element", "Event", diff --git a/bracket-terminal/src/hal/native/init.rs b/bracket-terminal/src/hal/native/init.rs index 47ba97be..51e05f76 100755 --- a/bracket-terminal/src/hal/native/init.rs +++ b/bracket-terminal/src/hal/native/init.rs @@ -15,11 +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_resizable(platform_hints.fitscreen) - .with_min_inner_size(scaler.new_window_size()) - .with_inner_size(scaler.new_window_size()); + .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) From bb6cc1f17133e75f2c0db9e72d2bac1fd94a9623 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 11:24:16 -0500 Subject: [PATCH 28/41] Update internal version numbers ready for a release (once we've finished testing and some more issues), relax dependency versions to make releases easier. --- .gitignore | 1 + Cargo.toml | 27 ++++++++------------------- bracket-algorithm-traits/Cargo.toml | 4 ++-- bracket-bevy/Cargo.toml | 6 +++--- bracket-color/Cargo.toml | 2 +- bracket-color/README.md | 2 +- bracket-embedding/Cargo.toml | 2 +- bracket-geometry/Cargo.toml | 4 ++-- bracket-geometry/README.md | 2 +- bracket-noise/Cargo.toml | 6 +++--- bracket-noise/README.md | 2 +- bracket-pathfinding/Cargo.toml | 10 +++++----- bracket-random/Cargo.toml | 4 ++-- bracket-rex/Cargo.toml | 4 ++-- bracket-terminal/Cargo.toml | 18 +++++++++--------- rltk/Cargo.toml | 4 ++-- 16 files changed, 44 insertions(+), 54 deletions(-) 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 84309eac..948817c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-lib" -version = "0.8.2" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -36,13 +36,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.3", 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 = [ @@ -58,14 +58,3 @@ members = [ "bracket-embedding", "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/bracket-algorithm-traits/Cargo.toml b/bracket-algorithm-traits/Cargo.toml index 16afbb48..2ca66c9c 100755 --- a/bracket-algorithm-traits/Cargo.toml +++ b/bracket-algorithm-traits/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-algorithm-traits" -version = "0.8.2" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -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 7fdeeff3..d623f328 100644 --- a/bracket-bevy/Cargo.toml +++ b/bracket-bevy/Cargo.toml @@ -18,8 +18,8 @@ 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", features = [ "bevy" ] } +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" } \ No newline at end of file diff --git a/bracket-color/Cargo.toml b/bracket-color/Cargo.toml index 564d5439..5cc20526 100755 --- a/bracket-color/Cargo.toml +++ b/bracket-color/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-color" -version = "0.8.3" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true diff --git a/bracket-color/README.md b/bracket-color/README.md index 199f2ce2..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 diff --git a/bracket-embedding/Cargo.toml b/bracket-embedding/Cargo.toml index 3ce8682d..a400d2fb 100644 --- a/bracket-embedding/Cargo.toml +++ b/bracket-embedding/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-embedding" -version = "0.8.0" +version = "0.8.7" edition = "2018" publish = true description = "Provides resource embedding services for bracket-lib" diff --git a/bracket-geometry/Cargo.toml b/bracket-geometry/Cargo.toml index 90c2c94d..e0f25c28 100755 --- a/bracket-geometry/Cargo.toml +++ b/bracket-geometry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-geometry" -version = "0.8.4" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -15,7 +15,7 @@ license = "MIT" [dependencies] serde = { version = "~1.0.139", features = ["derive"], optional = true } specs = { version = "~0.18.0", optional = true } -bevy = { version = "~0.8.0", optional = true } +bevy = { version = "~0.8", optional = true } ultraviolet = "~0.9.0" [dev-dependencies] 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-noise/Cargo.toml b/bracket-noise/Cargo.toml index 95a57202..ec00a455 100755 --- a/bracket-noise/Cargo.toml +++ b/bracket-noise/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-noise" -version = "0.8.2" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -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.25" -bracket-color = { path = "../bracket-color", version = "~0.8.2", features = [ "palette" ] } +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-pathfinding/Cargo.toml b/bracket-pathfinding/Cargo.toml index f13b1fc1..ca31ef29 100755 --- a/bracket-pathfinding/Cargo.toml +++ b/bracket-pathfinding/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-pathfinding" -version = "0.8.4" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -18,16 +18,16 @@ 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.25" -bracket-random = { path = "../bracket-random", version = "0.8.2" } -bracket-color = { path = "../bracket-color", version = "~0.8.2", features = [ "palette" ] } +bracket-random = { path = "../bracket-random", version = "0.8" } +bracket-color = { path = "../bracket-color", version = "~0.8", features = [ "palette" ] } criterion = "~0.4" [[bench]] diff --git a/bracket-random/Cargo.toml b/bracket-random/Cargo.toml index b975a9fe..3202c76a 100755 --- a/bracket-random/Cargo.toml +++ b/bracket-random/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-random" -version = "0.8.3" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -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" } diff --git a/bracket-rex/Cargo.toml b/bracket-rex/Cargo.toml index 790c4cb8..2d7060da 100644 --- a/bracket-rex/Cargo.toml +++ b/bracket-rex/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-rex" -version = "0.8.0" +version = "0.8.7" edition = "2018" publish = false description = "Load/save REX Paint files and utilize them in bracket-terminal projects." @@ -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-terminal/Cargo.toml b/bracket-terminal/Cargo.toml index cbf384cb..d90afe8a 100755 --- a/bracket-terminal/Cargo.toml +++ b/bracket-terminal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-terminal" -version = "0.8.5" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -16,10 +16,10 @@ 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.11", optional = true } @@ -49,9 +49,9 @@ 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" } +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] @@ -60,7 +60,7 @@ 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.26" } diff --git a/rltk/Cargo.toml b/rltk/Cargo.toml index 36a60692..73a71d91 100755 --- a/rltk/Cargo.toml +++ b/rltk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rltk" -version = "0.8.1" +version = "0.8.7" authors = ["Herbert Wolverson "] edition = "2018" publish = true @@ -25,6 +25,6 @@ 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] From ef27da05f262080f218790f936e03bbfcd43b9e7 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 11:33:10 -0500 Subject: [PATCH 29/41] Add example referencing issue #296 - not seeing tearing on my system? --- bracket-terminal/examples/twelve_by_twelve.rs | 248 ++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 bracket-terminal/examples/twelve_by_twelve.rs 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) +} From c72aabd950054067584bda06cfe474f1d0681de5 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 11:51:05 -0500 Subject: [PATCH 30/41] Disable incremental linking due to Windows build issues. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 948817c0..0b4051b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ exclude = [ "screenshots" ] resolver = "2" # Enables the new Cargo resolution engine +incremental = false # Causing issues with Windows builds [features] default = [ "opengl" ] @@ -56,5 +57,4 @@ members = [ "rltk", "bracket-rex", "bracket-embedding", - "bracket-bevy" ] From 095fbd46d4723488edc4df74cadacb8b26003f29 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 12:15:40 -0500 Subject: [PATCH 31/41] Update to Rust 2021 --- Cargo.toml | 2 +- bracket-algorithm-traits/Cargo.toml | 2 +- bracket-color/Cargo.toml | 2 +- bracket-embedding/Cargo.toml | 2 +- bracket-geometry/Cargo.toml | 2 +- bracket-noise/Cargo.toml | 2 +- bracket-pathfinding/Cargo.toml | 2 +- bracket-random/Cargo.toml | 2 +- bracket-rex/Cargo.toml | 4 ++-- bracket-terminal/Cargo.toml | 2 +- rltk/Cargo.toml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0b4051b8..a8411d89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-lib" 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" diff --git a/bracket-algorithm-traits/Cargo.toml b/bracket-algorithm-traits/Cargo.toml index 2ca66c9c..ab4ede58 100755 --- a/bracket-algorithm-traits/Cargo.toml +++ b/bracket-algorithm-traits/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-algorithm-traits" 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" diff --git a/bracket-color/Cargo.toml b/bracket-color/Cargo.toml index 5cc20526..55a6b029 100755 --- a/bracket-color/Cargo.toml +++ b/bracket-color/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-color" version = "0.8.7" 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" diff --git a/bracket-embedding/Cargo.toml b/bracket-embedding/Cargo.toml index a400d2fb..ccbce62f 100644 --- a/bracket-embedding/Cargo.toml +++ b/bracket-embedding/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bracket-embedding" version = "0.8.7" -edition = "2018" +edition = "2021" publish = true description = "Provides resource embedding services for bracket-lib" homepage = "https://github.com/thebracket/bracket-lib" diff --git a/bracket-geometry/Cargo.toml b/bracket-geometry/Cargo.toml index e0f25c28..ca229a86 100755 --- a/bracket-geometry/Cargo.toml +++ b/bracket-geometry/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-geometry" version = "0.8.7" 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" diff --git a/bracket-noise/Cargo.toml b/bracket-noise/Cargo.toml index ec00a455..fce36069 100755 --- a/bracket-noise/Cargo.toml +++ b/bracket-noise/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-noise" 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" diff --git a/bracket-pathfinding/Cargo.toml b/bracket-pathfinding/Cargo.toml index ca31ef29..50f631c1 100755 --- a/bracket-pathfinding/Cargo.toml +++ b/bracket-pathfinding/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-pathfinding" 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" diff --git a/bracket-random/Cargo.toml b/bracket-random/Cargo.toml index 3202c76a..17ae6003 100755 --- a/bracket-random/Cargo.toml +++ b/bracket-random/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-random" 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" diff --git a/bracket-rex/Cargo.toml b/bracket-rex/Cargo.toml index 2d7060da..54d3f286 100644 --- a/bracket-rex/Cargo.toml +++ b/bracket-rex/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bracket-rex" version = "0.8.7" -edition = "2018" -publish = false +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" diff --git a/bracket-terminal/Cargo.toml b/bracket-terminal/Cargo.toml index d90afe8a..064fc37d 100755 --- a/bracket-terminal/Cargo.toml +++ b/bracket-terminal/Cargo.toml @@ -2,7 +2,7 @@ name = "bracket-terminal" 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" diff --git a/rltk/Cargo.toml b/rltk/Cargo.toml index 73a71d91..e453b42f 100755 --- a/rltk/Cargo.toml +++ b/rltk/Cargo.toml @@ -2,7 +2,7 @@ name = "rltk" 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" From 51973d59e846c9419ed6efabee75d5ea8539b780 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 12:45:33 -0500 Subject: [PATCH 32/41] Embed fonts inside the embedding crate, to avoid cross-crate paths --- bracket-embedding/resources/terminal8x8.png | Bin 0 -> 43114 bytes bracket-embedding/resources/vga8x16.png | Bin 0 -> 35939 bytes bracket-embedding/src/embedding.rs | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 bracket-embedding/resources/terminal8x8.png create mode 100644 bracket-embedding/resources/vga8x16.png diff --git a/bracket-embedding/resources/terminal8x8.png b/bracket-embedding/resources/terminal8x8.png new file mode 100644 index 0000000000000000000000000000000000000000..4e405544b81adf49a95eb3e8195433ba77fe8171 GIT binary patch literal 43114 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 a;Qs-{pADMEQDff#0000 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
ks)9OOeS$5zR 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 z zAk?G9C0n#}T8mHXK*E*H&(N9TqGT9qj&?NsE{|vc-cdmVz^A~DxAl5GA+r1q4qxDq zJy#(6!&*T1u`L6jQ0U}lr1Mf=*h(il;&3?3qKeYu#{o>s=b&`}NU`%M3PwdW5NCWn zGWhC8;L#AKe?rKY}k{Eca65!sT~k`v@o;SO-l6v7wS%3raZH>R0<@S z0~?|pMuO78PycqC^gGaX`$hXc65fD%Vz{gO3qKZ9$ZK_Efo81qsvtp}?%R?nF?%PkeK+G}z49DmRD@jTNY=?`#REop&m}`@}2_Us7BGItQ0=aL_s zw-M#ovZ@~XT^0|};wXw7CXcS+Exvu1K!R8UXai03_~^m?!pi_p=4K~_^CN4rhl@&q zY9EH7AVATDX}`U_O_(~j1F-J^008kxL_t)SZL1l1Sv)|?KHWK>nmuI=+rZj+bvV7f zy_HX^*OMTX&AR|>{djxkKnmBvJd-(rAzEti8%FIi0jR|T)Sjn?lZzN?*&#*mUpw!7 z2CuKLpH3jfaUBst`;dC$ePqoQx+q0P&Wb3n&uzO}i%M}kKnt3todHO>RS0VDpPg5M z_%ydIJv&nO%|gI4-&xj?Z{KaFoZnyZfk(D^wRiya_+@acOTKI!{0Izc0gGIM>1UB~ zE9Sx5-6k#LeiUW$Mg)<%Y&bu?`m9?uKubJ8mRsipI9pCywu7}?zQ~grg}!};A?W-T bEyw=>)*qVc4$g}a00000NkvXXu0mjfzU(si literal 0 HcmV?d00001 diff --git a/bracket-embedding/src/embedding.rs b/bracket-embedding/src/embedding.rs index 57398d0a..749027cf 100644 --- a/bracket-embedding/src/embedding.rs +++ b/bracket-embedding/src/embedding.rs @@ -4,8 +4,8 @@ use std::collections::HashMap; // These are included by default in `bracket-terminal`. 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"); + 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()); From 99f48fe730c2b890b31284e65aa943947fca678d Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 12:51:41 -0500 Subject: [PATCH 33/41] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From f94c86e1b5af7d65d52323a8ac8b93197f422e23 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 12:56:27 -0500 Subject: [PATCH 34/41] Add embedding readme --- bracket-embedding/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 bracket-embedding/README.md 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"); +} +``` From 15ec23aba4ec0c147f9ec54d2429a59c1bb6319c Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 4 Oct 2022 12:57:54 -0500 Subject: [PATCH 35/41] Add rex readme --- bracket-rex/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 bracket-rex/README.md 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. + From 4e4427648e7f7afb54f448ebd997823a925280c6 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Fri, 7 Oct 2022 09:27:23 -0500 Subject: [PATCH 36/41] Change color conversion to linear RGBA rather than sRGBA. Bracket terminal colors look right now. --- bracket-color/src/rgba.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bracket-color/src/rgba.rs b/bracket-color/src/rgba.rs index ab592662..1247c71e 100755 --- a/bracket-color/src/rgba.rs +++ b/bracket-color/src/rgba.rs @@ -298,7 +298,7 @@ impl RGBA { #[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 From 851f6f08675444fb6fa088b9e67bee9fd75554c6 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Sat, 8 Oct 2022 07:48:55 -0500 Subject: [PATCH 37/41] #301 Fixes wasm32-unknown-unknown build --- bracket-terminal/src/hal/gl_common/framebuffer.rs | 8 +++++--- bracket-terminal/src/hal/gl_common/types_native.rs | 3 ++- bracket-terminal/src/hal/gl_common/types_wasm.rs | 1 + bracket-terminal/src/hal/wasm/mod.rs | 2 ++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bracket-terminal/src/hal/gl_common/framebuffer.rs b/bracket-terminal/src/hal/gl_common/framebuffer.rs index 9b876c15..9986fd69 100755 --- a/bracket-terminal/src/hal/gl_common/framebuffer.rs +++ b/bracket-terminal/src/hal/gl_common/framebuffer.rs @@ -1,11 +1,13 @@ #[allow(unused_imports)] use crate::BResult; -use glow::{HasContext, NativeFramebuffer, NativeTexture}; +use glow::HasContext; + +use super::{FramebufferId, TextureId}; #[cfg(not(target_arch = "wasm32"))] pub struct Framebuffer { - fbo: NativeFramebuffer, - pub texture: NativeTexture, + fbo: FramebufferId, + pub texture: TextureId, } #[cfg(target_arch = "wasm32")] diff --git a/bracket-terminal/src/hal/gl_common/types_native.rs b/bracket-terminal/src/hal/gl_common/types_native.rs index 2306ce67..50dff54d 100755 --- a/bracket-terminal/src/hal/gl_common/types_native.rs +++ b/bracket-terminal/src/hal/gl_common/types_native.rs @@ -1,6 +1,7 @@ -use glow::{NativeTexture, NativeBuffer, NativeVertexArray, NativeProgram}; +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/wasm/mod.rs b/bracket-terminal/src/hal/wasm/mod.rs index 29cbbc67..24d0d6cc 100755 --- a/bracket-terminal/src/hal/wasm/mod.rs +++ b/bracket-terminal/src/hal/wasm/mod.rs @@ -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, } } } From 0a7fcbcd6eb537723272906ebd88382e6a69d483 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 15 Nov 2022 10:11:14 -0600 Subject: [PATCH 38/41] Minimum required to get bracket_bevy compiling without error/warning on Bevy 0.9. There are some issues left to resolve, particularly why is it spawning continuous Resize messages on Windows? --- Cargo.toml | 1 + bracket-bevy/Cargo.toml | 2 +- bracket-bevy/examples/bevy_a_star_mouse.rs | 1 + bracket-bevy/examples/bevy_alpha.rs | 4 ++-- bracket-bevy/examples/bevy_colorfont.rs | 4 ++-- bracket-bevy/examples/bevy_hello_terminal.rs | 1 + bracket-bevy/examples/bevy_roguelike_tutorial_4/main.rs | 8 ++++---- bracket-bevy/examples/bevy_roguelike_tutorial_4/map.rs | 8 ++++++-- bracket-bevy/examples/bevy_tiles.rs | 1 + bracket-bevy/examples/bevy_two_layers_two_fonts.rs | 1 + bracket-bevy/examples/bevy_walking.rs | 1 + bracket-bevy/src/builder/bterm_builder.rs | 4 ++-- bracket-bevy/src/builder/image_fixer.rs | 1 + bracket-bevy/src/builder/loader_system.rs | 2 +- bracket-bevy/src/consoles/scaler.rs | 3 +++ .../simple_console/back_end/simple_no_background.rs | 2 +- .../simple_console/back_end/simple_with_background.rs | 2 +- .../sparse_console/back_end/sparse_no_background.rs | 2 +- .../sparse_console/back_end/sparse_with_background.rs | 2 +- bracket-bevy/src/consoles/update_system.rs | 4 ++-- bracket-bevy/src/context.rs | 3 ++- bracket-bevy/src/random_resource/mod.rs | 2 ++ bracket-color/Cargo.toml | 2 +- bracket-geometry/Cargo.toml | 2 +- 24 files changed, 40 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a8411d89..d5e3f4ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,4 +57,5 @@ members = [ "rltk", "bracket-rex", "bracket-embedding", + "bracket-bevy", ] diff --git a/bracket-bevy/Cargo.toml b/bracket-bevy/Cargo.toml index d623f328..06b57de3 100644 --- a/bracket-bevy/Cargo.toml +++ b/bracket-bevy/Cargo.toml @@ -13,7 +13,7 @@ categories = ["game-engines", "graphics"] license = "MIT" [dependencies] -bevy = "0.8" +bevy = "0.9" parking_lot = "0.12" lazy_static = "1.4" bracket-random = { path = "../bracket-random" } 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 378984ad..aaf0edec 100644 --- a/bracket-bevy/src/builder/bterm_builder.rs +++ b/bracket-bevy/src/builder/bterm_builder.rs @@ -7,7 +7,7 @@ use crate::{ }; use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, - prelude::{CoreStage, Plugin, SystemStage}, + prelude::{CoreStage, Plugin, SystemStage, Resource}, utils::HashMap, }; use bracket_color::prelude::RGBA; @@ -19,7 +19,7 @@ pub enum TerminalScalingMode { ResizeTerminals, } -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct BTermBuilder { pub(crate) fonts: Vec, pub(crate) layers: Vec, diff --git a/bracket-bevy/src/builder/image_fixer.rs b/bracket-bevy/src/builder/image_fixer.rs index a423aac4..22353dda 100644 --- a/bracket-bevy/src/builder/image_fixer.rs +++ b/bracket-bevy/src/builder/image_fixer.rs @@ -3,6 +3,7 @@ use bevy::{ render::{render_resource::SamplerDescriptor, texture::ImageSampler}, }; +#[derive(Resource)] pub(crate) struct ImagesToLoad(pub(crate) Vec); pub(crate) fn fix_images(mut fonts: ResMut, mut images: ResMut>) { diff --git a/bracket-bevy/src/builder/loader_system.rs b/bracket-bevy/src/builder/loader_system.rs index d66a1fe4..d24f7ac3 100644 --- a/bracket-bevy/src/builder/loader_system.rs +++ b/bracket-bevy/src/builder/loader_system.rs @@ -23,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/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/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..e02936a0 100644 --- a/bracket-bevy/src/consoles/update_system.rs +++ b/bracket-bevy/src/consoles/update_system.rs @@ -43,9 +43,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(); } }); 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/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 55a6b029..20c92d9a 100755 --- a/bracket-color/Cargo.toml +++ b/bracket-color/Cargo.toml @@ -20,7 +20,7 @@ serde = { version = "~1.0.110", features = ["derive"], 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.9", optional = true } [dev-dependencies] crossterm = "~0.25" diff --git a/bracket-geometry/Cargo.toml b/bracket-geometry/Cargo.toml index ca229a86..24d7588e 100755 --- a/bracket-geometry/Cargo.toml +++ b/bracket-geometry/Cargo.toml @@ -15,7 +15,7 @@ license = "MIT" [dependencies] serde = { version = "~1.0.139", features = ["derive"], optional = true } specs = { version = "~0.18.0", optional = true } -bevy = { version = "~0.8", optional = true } +bevy = { version = "~0.9", optional = true } ultraviolet = "~0.9.0" [dev-dependencies] From 0d2d5e6a9a8e7c7ae3710cfef85be4cab0109a27 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Tue, 10 Jan 2023 19:56:59 +0000 Subject: [PATCH 39/41] #318 - This solves the Wayland crash on my system. More testing required. --- bracket-terminal/src/hal/native/mainloop.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bracket-terminal/src/hal/native/mainloop.rs b/bracket-terminal/src/hal/native/mainloop.rs index eabc0b50..f77d39e3 100755 --- a/bracket-terminal/src/hal/native/mainloop.rs +++ b/bracket-terminal/src/hal/native/mainloop.rs @@ -201,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 { From e5854d19ef9b7b2344937f70797706a410165bf8 Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 2 Jun 2023 14:53:41 -0700 Subject: [PATCH 40/41] Updated to Bevy 0.10.1 Replaced stages with stageless sets. Replaced the function body of update_mouse_position to handle Window entities. --- bracket-bevy/Cargo.toml | 5 +- bracket-bevy/src/builder/bterm_builder.rs | 41 ++++++------ bracket-bevy/src/builder/image_fixer.rs | 4 +- bracket-bevy/src/consoles/update_system.rs | 67 +++++++++++++------ bracket-bevy/src/lib.rs | 1 + .../bracket_term_diagnostics.rs | 9 +++ .../src/stageless_sets/bracket_term_update.rs | 7 ++ bracket-bevy/src/stageless_sets/mod.rs | 2 + bracket-color/Cargo.toml | 3 +- bracket-geometry/Cargo.toml | 3 +- 10 files changed, 96 insertions(+), 46 deletions(-) create mode 100644 bracket-bevy/src/stageless_sets/bracket_term_diagnostics.rs create mode 100644 bracket-bevy/src/stageless_sets/bracket_term_update.rs create mode 100644 bracket-bevy/src/stageless_sets/mod.rs diff --git a/bracket-bevy/Cargo.toml b/bracket-bevy/Cargo.toml index 06b57de3..addbc7e1 100644 --- a/bracket-bevy/Cargo.toml +++ b/bracket-bevy/Cargo.toml @@ -13,7 +13,8 @@ categories = ["game-engines", "graphics"] license = "MIT" [dependencies] -bevy = "0.9" + +bevy = "0.10.1" parking_lot = "0.12" lazy_static = "1.4" bracket-random = { path = "../bracket-random" } @@ -22,4 +23,4 @@ bracket-geometry = { path = "../bracket-geometry", version = "~0.8", features = [dev-dependencies] bracket-pathfinding = { path = "../bracket-pathfinding", version = "~0.8" } -bracket-noise = { path = "../bracket-noise", version = "~0.8" } \ No newline at end of file +bracket-noise = { path = "../bracket-noise", version = "~0.8" } diff --git a/bracket-bevy/src/builder/bterm_builder.rs b/bracket-bevy/src/builder/bterm_builder.rs index aaf0edec..36392ee4 100644 --- a/bracket-bevy/src/builder/bterm_builder.rs +++ b/bracket-bevy/src/builder/bterm_builder.rs @@ -7,11 +7,15 @@ use crate::{ }; use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, - prelude::{CoreStage, Plugin, SystemStage, Resource}, + + prelude::{CoreSet, Plugin, Resource, Msaa, IntoSystemConfig, IntoSystemSetConfig}, + utils::HashMap, }; use bracket_color::prelude::RGBA; use std::collections::HashSet; +use bevy::prelude::Schedule; +use crate::stageless_sets::{bracket_term_diagnostics::BracketTermDiagnostics, bracket_term_update::BracketTermUpdate}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TerminalScalingMode { @@ -176,8 +180,10 @@ impl BTermBuilder { impl Plugin for BTermBuilder { fn build(&self, app: &mut bevy::prelude::App) { - app.insert_resource(bevy::prelude::Msaa { samples: 1 }); + app.insert_resource(Msaa::Off); if self.with_diagnostics { + app.configure_set(BracketTermDiagnostics::BeforeCoreFixedUpdate.before(CoreSet::FixedUpdate).after(CoreSet::StateTransitions)); + app.add_schedule(BracketTermDiagnostics::BeforeCoreFixedUpdate, Schedule::new()); app.add_plugin(FrameTimeDiagnosticsPlugin); } if self.log_diagnostics { @@ -187,26 +193,23 @@ impl Plugin for BTermBuilder { app.insert_resource(ScreenScaler::new(self.gutter)); app.add_startup_system(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_system(update_timing.in_base_set(BracketTermDiagnostics::BeforeCoreFixedUpdate)); + app.add_system(update_mouse_position.in_base_set(BracketTermDiagnostics::BeforeCoreFixedUpdate)); } - app.add_stage_after( - CoreStage::Update, - "bracket_term_update", - SystemStage::single_threaded(), - ); + + app.configure_set(BracketTermUpdate.after(CoreSet::Update)); + app.add_schedule(BracketTermUpdate, Schedule::new()); + if self.auto_apply_batches { - app.add_system(apply_all_batches); + + app.add_system(apply_all_batches.in_base_set(BracketTermUpdate)); } - app.add_system(update_consoles); - app.add_system(replace_meshes); - app.add_system(window_resize); - app.add_system(fix_images); + + app.add_system(update_consoles.in_base_set(BracketTermUpdate)); + app.add_system(replace_meshes.in_base_set(BracketTermUpdate)); + app.add_system(window_resize.in_base_set(BracketTermUpdate)); + app.add_system(fix_images.in_base_set(BracketTermUpdate)); + 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 22353dda..1a4ebb20 100644 --- a/bracket-bevy/src/builder/image_fixer.rs +++ b/bracket-bevy/src/builder/image_fixer.rs @@ -13,8 +13,10 @@ pub(crate) fn fix_images(mut fonts: ResMut, mut images: 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!") } + } + + 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); - context.set_mouse_pixel_position(result, &scaler); + context.set_mouse_pixel_position(result, &scaler); + } } } diff --git a/bracket-bevy/src/lib.rs b/bracket-bevy/src/lib.rs index 35d4a576..68162045 100644 --- a/bracket-bevy/src/lib.rs +++ b/bracket-bevy/src/lib.rs @@ -11,6 +11,7 @@ mod random_resource; pub use consoles::{DrawBatch, VirtualConsole}; pub use random_resource::*; mod textblock; +mod stageless_sets; pub type FontCharType = u16; diff --git a/bracket-bevy/src/stageless_sets/bracket_term_diagnostics.rs b/bracket-bevy/src/stageless_sets/bracket_term_diagnostics.rs new file mode 100644 index 00000000..cf42e4d5 --- /dev/null +++ b/bracket-bevy/src/stageless_sets/bracket_term_diagnostics.rs @@ -0,0 +1,9 @@ +use bevy::ecs::schedule::ScheduleLabel; +// Bevy 0.10, no command flush +use bevy::prelude::SystemSet; +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet, ScheduleLabel)] +#[system_set(base)] +pub enum BracketTermDiagnostics { + BeforeCoreFixedUpdate, +} + diff --git a/bracket-bevy/src/stageless_sets/bracket_term_update.rs b/bracket-bevy/src/stageless_sets/bracket_term_update.rs new file mode 100644 index 00000000..5f645407 --- /dev/null +++ b/bracket-bevy/src/stageless_sets/bracket_term_update.rs @@ -0,0 +1,7 @@ +use bevy::ecs::schedule::ScheduleLabel; + +use bevy::prelude::SystemSet; + +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet, ScheduleLabel)] +#[system_set(base)] +pub struct BracketTermUpdate; \ No newline at end of file diff --git a/bracket-bevy/src/stageless_sets/mod.rs b/bracket-bevy/src/stageless_sets/mod.rs new file mode 100644 index 00000000..8c10d230 --- /dev/null +++ b/bracket-bevy/src/stageless_sets/mod.rs @@ -0,0 +1,2 @@ +pub mod bracket_term_diagnostics; +pub mod bracket_term_update; \ No newline at end of file diff --git a/bracket-color/Cargo.toml b/bracket-color/Cargo.toml index 20c92d9a..66a0bb8d 100755 --- a/bracket-color/Cargo.toml +++ b/bracket-color/Cargo.toml @@ -20,7 +20,8 @@ serde = { version = "~1.0.110", features = ["derive"], 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.9", optional = true } + +bevy = { version = "~0.10.1", optional = true } [dev-dependencies] crossterm = "~0.25" diff --git a/bracket-geometry/Cargo.toml b/bracket-geometry/Cargo.toml index 24d7588e..93dd8d21 100755 --- a/bracket-geometry/Cargo.toml +++ b/bracket-geometry/Cargo.toml @@ -15,7 +15,8 @@ license = "MIT" [dependencies] serde = { version = "~1.0.139", features = ["derive"], optional = true } specs = { version = "~0.18.0", optional = true } -bevy = { version = "~0.9", optional = true } + +bevy = { version = "~0.10.1", optional = true } ultraviolet = "~0.9.0" [dev-dependencies] From c21365ba639daed3f5a603120e8f81345cb950ce Mon Sep 17 00:00:00 2001 From: Joe Date: Wed, 9 Aug 2023 01:29:55 -0700 Subject: [PATCH 41/41] Updated bracket-bevy to Bevy 0.11.0 Updated systems initialized by bterm_builder to use the new simplified system scheduler in Bevy 0.11.0. Bumped up Bevy dependencies in bracket-color and bracket-geometry to Bevy 0.11.0. Fixed bug with inverted y-coordinates for the mouse's world space position in fn update_mouse_position. --- bracket-bevy/Cargo.toml | 4 +- bracket-bevy/src/builder/bterm_builder.rs | 38 ++++++++----------- bracket-bevy/src/consoles/update_system.rs | 8 ++-- bracket-bevy/src/lib.rs | 2 - .../bracket_term_diagnostics.rs | 9 ----- .../src/stageless_sets/bracket_term_update.rs | 7 ---- bracket-bevy/src/stageless_sets/mod.rs | 2 - bracket-color/Cargo.toml | 4 +- bracket-geometry/Cargo.toml | 4 +- 9 files changed, 26 insertions(+), 52 deletions(-) delete mode 100644 bracket-bevy/src/stageless_sets/bracket_term_diagnostics.rs delete mode 100644 bracket-bevy/src/stageless_sets/bracket_term_update.rs delete mode 100644 bracket-bevy/src/stageless_sets/mod.rs diff --git a/bracket-bevy/Cargo.toml b/bracket-bevy/Cargo.toml index addbc7e1..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 @@ -14,7 +14,7 @@ license = "MIT" [dependencies] -bevy = "0.10.1" +bevy = "0.11.0" parking_lot = "0.12" lazy_static = "1.4" bracket-random = { path = "../bracket-random" } diff --git a/bracket-bevy/src/builder/bterm_builder.rs b/bracket-bevy/src/builder/bterm_builder.rs index 36392ee4..7615fc0c 100644 --- a/bracket-bevy/src/builder/bterm_builder.rs +++ b/bracket-bevy/src/builder/bterm_builder.rs @@ -8,14 +8,12 @@ use crate::{ use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, - prelude::{CoreSet, Plugin, Resource, Msaa, IntoSystemConfig, IntoSystemSetConfig}, + prelude::{Plugin, Resource, Msaa, Startup, PostUpdate, PreUpdate, First}, utils::HashMap, }; use bracket_color::prelude::RGBA; use std::collections::HashSet; -use bevy::prelude::Schedule; -use crate::stageless_sets::{bracket_term_diagnostics::BracketTermDiagnostics, bracket_term_update::BracketTermUpdate}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TerminalScalingMode { @@ -181,34 +179,30 @@ impl BTermBuilder { impl Plugin for BTermBuilder { fn build(&self, app: &mut bevy::prelude::App) { app.insert_resource(Msaa::Off); - if self.with_diagnostics { - app.configure_set(BracketTermDiagnostics::BeforeCoreFixedUpdate.before(CoreSet::FixedUpdate).after(CoreSet::StateTransitions)); - app.add_schedule(BracketTermDiagnostics::BeforeCoreFixedUpdate, Schedule::new()); - app.add_plugin(FrameTimeDiagnosticsPlugin); + + 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_system(update_timing.in_base_set(BracketTermDiagnostics::BeforeCoreFixedUpdate)); - app.add_system(update_mouse_position.in_base_set(BracketTermDiagnostics::BeforeCoreFixedUpdate)); + app.add_systems(First, update_timing); + app.add_systems(PreUpdate,update_mouse_position); } - - app.configure_set(BracketTermUpdate.after(CoreSet::Update)); - app.add_schedule(BracketTermUpdate, Schedule::new()); - - if self.auto_apply_batches { - - app.add_system(apply_all_batches.in_base_set(BracketTermUpdate)); + + if self.auto_apply_batches { + app.add_systems(PostUpdate, apply_all_batches); } - app.add_system(update_consoles.in_base_set(BracketTermUpdate)); - app.add_system(replace_meshes.in_base_set(BracketTermUpdate)); - app.add_system(window_resize.in_base_set(BracketTermUpdate)); - app.add_system(fix_images.in_base_set(BracketTermUpdate)); + //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/consoles/update_system.rs b/bracket-bevy/src/consoles/update_system.rs index 54e459e6..948a0139 100644 --- a/bracket-bevy/src/consoles/update_system.rs +++ b/bracket-bevy/src/consoles/update_system.rs @@ -1,13 +1,12 @@ 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::utils::petgraph::visit::NodeRef; use bevy::window::{PrimaryWindow, WindowRef}; use super::{BracketMesh, ScreenScaler}; @@ -63,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(); @@ -127,6 +126,7 @@ pub(crate) fn update_mouse_position( } // 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() { @@ -144,7 +144,7 @@ pub(crate) fn update_mouse_position( 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); } diff --git a/bracket-bevy/src/lib.rs b/bracket-bevy/src/lib.rs index 68162045..99d1936c 100644 --- a/bracket-bevy/src/lib.rs +++ b/bracket-bevy/src/lib.rs @@ -11,8 +11,6 @@ mod random_resource; pub use consoles::{DrawBatch, VirtualConsole}; pub use random_resource::*; mod textblock; -mod stageless_sets; - pub type FontCharType = u16; pub mod prelude { diff --git a/bracket-bevy/src/stageless_sets/bracket_term_diagnostics.rs b/bracket-bevy/src/stageless_sets/bracket_term_diagnostics.rs deleted file mode 100644 index cf42e4d5..00000000 --- a/bracket-bevy/src/stageless_sets/bracket_term_diagnostics.rs +++ /dev/null @@ -1,9 +0,0 @@ -use bevy::ecs::schedule::ScheduleLabel; -// Bevy 0.10, no command flush -use bevy::prelude::SystemSet; -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet, ScheduleLabel)] -#[system_set(base)] -pub enum BracketTermDiagnostics { - BeforeCoreFixedUpdate, -} - diff --git a/bracket-bevy/src/stageless_sets/bracket_term_update.rs b/bracket-bevy/src/stageless_sets/bracket_term_update.rs deleted file mode 100644 index 5f645407..00000000 --- a/bracket-bevy/src/stageless_sets/bracket_term_update.rs +++ /dev/null @@ -1,7 +0,0 @@ -use bevy::ecs::schedule::ScheduleLabel; - -use bevy::prelude::SystemSet; - -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet, ScheduleLabel)] -#[system_set(base)] -pub struct BracketTermUpdate; \ No newline at end of file diff --git a/bracket-bevy/src/stageless_sets/mod.rs b/bracket-bevy/src/stageless_sets/mod.rs deleted file mode 100644 index 8c10d230..00000000 --- a/bracket-bevy/src/stageless_sets/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod bracket_term_diagnostics; -pub mod bracket_term_update; \ No newline at end of file diff --git a/bracket-color/Cargo.toml b/bracket-color/Cargo.toml index 66a0bb8d..0ae96f52 100755 --- a/bracket-color/Cargo.toml +++ b/bracket-color/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-color" -version = "0.8.7" +version = "0.8.8" authors = ["Herbert Wolverson "] edition = "2021" publish = true @@ -21,7 +21,7 @@ crossterm = { version = "~0.25", optional = true } lazy_static = { version = "1.4.0", optional = true } parking_lot = { version = "~0.12", optional = true } -bevy = { version = "~0.10.1", optional = true } +bevy = { version = "0.11.0", optional = true } [dev-dependencies] crossterm = "~0.25" diff --git a/bracket-geometry/Cargo.toml b/bracket-geometry/Cargo.toml index 93dd8d21..3e274a6e 100755 --- a/bracket-geometry/Cargo.toml +++ b/bracket-geometry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bracket-geometry" -version = "0.8.7" +version = "0.8.8" authors = ["Herbert Wolverson "] edition = "2021" publish = true @@ -16,7 +16,7 @@ license = "MIT" serde = { version = "~1.0.139", features = ["derive"], optional = true } specs = { version = "~0.18.0", optional = true } -bevy = { version = "~0.10.1", optional = true } +bevy = { version = "0.11.0", optional = true } ultraviolet = "~0.9.0" [dev-dependencies]