From 367e95c36cfb6c557531499eadbb3447d29ee1f2 Mon Sep 17 00:00:00 2001 From: StefanoIncardone Date: Mon, 29 Jan 2024 17:52:12 +0100 Subject: [PATCH] Improved examples --- Cargo.toml | 2 +- examples/char_callback.rs | 63 ++++++---- examples/drop.rs | 31 ++--- examples/{julia.rs => fractal.rs} | 29 ++--- examples/icon.rs | 19 ++- examples/image.rs | 76 +++++++----- examples/menu.rs | 33 ++--- examples/mouse.rs | 56 ++++----- examples/multi.rs | 64 ++++++---- examples/noise.rs | 29 ++--- {resources => examples/resources}/icon256.ico | Bin {resources => examples/resources}/planet.png | Bin {resources => examples/resources}/uv.png | Bin examples/text.rs | 53 ++++---- examples/title_cursor.rs | 116 +++++++++--------- examples/topmost.rs | 18 +-- examples/transparent.rs | 47 +++++-- rustfmt.toml | 2 +- 18 files changed, 340 insertions(+), 298 deletions(-) rename examples/{julia.rs => fractal.rs} (79%) rename {resources => examples/resources}/icon256.ico (100%) rename {resources => examples/resources}/planet.png (100%) rename {resources => examples/resources}/uv.png (100%) diff --git a/Cargo.toml b/Cargo.toml index b46bca67..e7d840b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ build = "build.rs" edition = "2018" readme = "README.md" -exclude = ["resources/"] +exclude = ["examples/resources/"] [badges] maintenance = { status = "actively-developed" } diff --git a/examples/char_callback.rs b/examples/char_callback.rs index 857213b4..719ace52 100644 --- a/examples/char_callback.rs +++ b/examples/char_callback.rs @@ -1,9 +1,8 @@ -use minifb::{Key, Window, WindowOptions}; -use std::cell::RefCell; -use std::rc::Rc; +use minifb::{InputCallback, Key, Window, WindowOptions}; +use std::{cell::RefCell, rc::Rc}; -const WIDTH: usize = 640; -const HEIGHT: usize = 360; +const WIDTH: usize = 1280; +const HEIGHT: usize = 720; type KeyVec = Rc>>; @@ -11,52 +10,64 @@ struct Input { keys: KeyVec, } -impl Input { - fn new(data: &KeyVec) -> Input { - Input { keys: data.clone() } - } -} - -impl minifb::InputCallback for Input { +impl InputCallback for Input { + /// Will be called every time a character key is pressed fn add_char(&mut self, uni_char: u32) { self.keys.borrow_mut().push(uni_char); } } fn main() { - let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; + let mut buffer = vec![0u32; WIDTH * HEIGHT]; let mut window = Window::new( - "Test - ESC to exit", + "char_callback example - press ESC to exit", WIDTH, HEIGHT, WindowOptions::default(), ) - .unwrap_or_else(|e| { - panic!("{:?}", e); - }); - - let keys_data = KeyVec::new(RefCell::new(Vec::new())); - - let input = Box::new(Input::new(&keys_data)); + .expect("Unable to create the window"); window.set_target_fps(60); - window.set_input_callback(input); + let keys = KeyVec::new(RefCell::new(Vec::new())); + window.set_input_callback(Box::new(Input { keys: keys.clone() })); + + // produces a wave pattern where the screen goes from red to blue, and vice-versa + let mut wave: u8 = 0; + let mut wave_direction: i8 = 1; while window.is_open() && !window.is_key_down(Key::Escape) { - for i in buffer.iter_mut() { - *i = 0; // write something more funny here! + let red: u32 = (wave as u32) << 16; + let green: u32 = 64 << 8; + let blue: u32 = (255 - wave) as u32; + let bg_color = red | green | blue; + + for pixel in buffer.iter_mut() { + *pixel = bg_color; } // We unwrap here as we want this code to exit if it fails. Real applications may want to handle this in a different way window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap(); - let mut keys = keys_data.borrow_mut(); + let mut keys = keys.borrow_mut(); for t in keys.iter() { - println!("Code point: {}, Character: {:?}", *t, char::from_u32(*t)); + println!("Code point: {}, Character: {:?}", *t, char::from_u32(*t)); } keys.clear(); + + // switch color wave directions + match wave.checked_add_signed(wave_direction) { + Some(new_wave) => wave = new_wave, + None => { + wave_direction = -wave_direction; + if wave_direction > 0 { + wave += 1; + } else { + wave -= 1; + } + } + } } } diff --git a/examples/drop.rs b/examples/drop.rs index a6a703b3..cea11773 100644 --- a/examples/drop.rs +++ b/examples/drop.rs @@ -1,30 +1,33 @@ use minifb::{Window, WindowOptions}; -use std::thread; -use std::time::{Duration, Instant}; +use std::{ + thread, + time::{Duration, Instant}, +}; -const WIDTH: usize = 640 / 2; -const HEIGHT: usize = 360 / 2; +const WIDTH: usize = 1280; +const HEIGHT: usize = 720; + +fn main() { + println!("Creating and showing a Window"); -fn show_window() { let mut window = Window::new( - "Drop Test - Window will close after 2 seconds.", + "Drop example - Window will close after 5 seconds", WIDTH, HEIGHT, WindowOptions::default(), ) - .expect("Unable to create window"); + .expect("Unable to create the window"); - let now = Instant::now(); + window.set_target_fps(60); - while window.is_open() && now.elapsed().as_secs() < 2 { + let now = Instant::now(); + while window.is_open() && now.elapsed().as_secs() < 5 { window.update(); } -} -fn main() { - println!("Showing Window"); - show_window(); + drop(window); println!("Dropped"); - thread::sleep(Duration::from_millis(2000)); + + thread::sleep(Duration::from_secs(2)); println!("Exiting"); } diff --git a/examples/julia.rs b/examples/fractal.rs similarity index 79% rename from examples/julia.rs rename to examples/fractal.rs index 62ed6c92..f068757f 100644 --- a/examples/julia.rs +++ b/examples/fractal.rs @@ -6,20 +6,20 @@ const FRACTAL_DEPTH: u32 = 64; const GENERATION_INFINITY: f64 = 16.; fn main() { - let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; + let mut buffer = vec![0u32; WIDTH * HEIGHT]; let mut window = Window::new( - "Fractal - ESC to exit", + "Fractal example - press ESC to exit", WIDTH, HEIGHT, WindowOptions { resize: true, - scale: Scale::X2, + scale: Scale::X4, scale_mode: ScaleMode::AspectRatioStretch, ..WindowOptions::default() }, ) - .expect("Unable to Open Window"); + .expect("Unable to create the window"); window.set_target_fps(60); @@ -39,9 +39,8 @@ fn main() { let mut real = map((i % WIDTH) as f64, 0., WIDTH as f64, x_min, x_max); let mut imag = map((i / HEIGHT) as f64, 0., HEIGHT as f64, y_min, y_max); - let mut n = 0; - - while n < FRACTAL_DEPTH { + let mut depth = 0; + while depth < FRACTAL_DEPTH { let re = real.powf(2.) - imag.powf(2.); let im = 2. * real * imag; @@ -51,10 +50,14 @@ fn main() { if (real + imag).abs() > GENERATION_INFINITY { break; // Leave when achieve infinity } - n += 1; + depth += 1; } - *pixel = fill(n); + *pixel = if depth == FRACTAL_DEPTH { + 0x00 + } else { + depth * 32 % 255 + }; } angle += 0.1; @@ -67,11 +70,3 @@ fn main() { fn map(val: f64, start1: f64, stop1: f64, start2: f64, stop2: f64) -> f64 { start2 + (stop2 - start2) * ((val - start1) / (stop1 - start1)) } - -fn fill(n: u32) -> u32 { - if FRACTAL_DEPTH == n { - 0x00 - } else { - n * 32 % 255 - } -} diff --git a/examples/icon.rs b/examples/icon.rs index 55da279c..e5c23190 100644 --- a/examples/icon.rs +++ b/examples/icon.rs @@ -5,20 +5,25 @@ use std::str::FromStr; use minifb::{Icon, Key, Window, WindowOptions}; +const WIDTH: usize = 1280; +const HEIGHT: usize = 720; + fn main() { let mut window = Window::new( - "Window Icon Test - Press ESC to exit", - 300, - 300, + "Window icon example - press ESC to exit", + WIDTH, + HEIGHT, WindowOptions { resize: true, ..WindowOptions::default() }, ) - .expect("Unable to open Window"); + .expect("Unable to create the window"); + + window.set_target_fps(60); #[cfg(target_os = "windows")] - window.set_icon(Icon::from_str("resources/icon256.ico").unwrap()); + window.set_icon(Icon::from_str("examples/resources/icon256.ico").unwrap()); #[cfg(target_os = "linux")] { @@ -170,7 +175,9 @@ fn main() { 1476329472, 1342111744, 1207894016, 1056899072, 939458560, 788463616, 654245888, 536281096, 385810432, 251592704, 134152192, ]; - window.set_icon(Icon::try_from(&test[..]).unwrap()); + + // NOTE(@StefanoIncardone): this does not work on wayland + window.set_icon(Icon::try_from(test.as_slice()).unwrap()); } while window.is_open() && !window.is_key_down(Key::Escape) { diff --git a/examples/image.rs b/examples/image.rs index 31b1ae67..7d005f0c 100644 --- a/examples/image.rs +++ b/examples/image.rs @@ -1,43 +1,53 @@ -use minifb::{Key, ScaleMode, Window, WindowOptions}; +use minifb::{Key, Window, WindowOptions}; +use png::{Decoder, Transformations}; +use std::fs::File; fn main() { - use std::fs::File; - // The decoder is a build for reader and can be used to set various decoding options - // via `Transformations`. The default output transformation is `Transformations::EXPAND - // | Transformations::STRIP_ALPHA`. - let decoder = png::Decoder::new(File::open("resources/uv.png").unwrap()); + let mut decoder = Decoder::new(File::open("examples/resources/planet.png").unwrap()); + + // Reading the image in RGBA format. + decoder.set_transformations(Transformations::ALPHA); let mut reader = decoder.read_info().unwrap(); - // Allocate the output buffer. - let mut buf = vec![0; reader.output_buffer_size()]; - // Read the next frame. Currently this function should only called once. - // The default options - reader.next_frame(&mut buf).unwrap(); - // convert buffer to u32 - - let u32_buffer: Vec = buf - .chunks(3) - .map(|v| ((v[0] as u32) << 16) | ((v[1] as u32) << 8) | v[2] as u32) - .collect(); + + let mut buffer = vec![0u32; reader.output_buffer_size()]; + + // View of pixels as individual subpixels (avoids allocating a second pixel buffer). + let mut u8_buffer = unsafe { + std::slice::from_raw_parts_mut( + buffer.as_mut_ptr() as *mut u8, + buffer.len() * std::mem::size_of::(), + ) + }; + + // Read the next frame. Currently this function should only be called once. + reader.next_frame(&mut u8_buffer).unwrap(); + + // convert RGBA buffer read by the reader to an ARGB buffer as expected by minifb. + for (rgba, argb) in u8_buffer.chunks_mut(4).zip(buffer.iter_mut()) { + // extracting the subpixels + let r = rgba[0] as u32; + let g = rgba[1] as u32; + let b = rgba[2] as u32; + let a = rgba[3] as u32; + + // merging the subpixels in ARGB format. + *argb = a << 24 | r << 16 | g << 8 | b; + } + + let width = reader.info().width as usize; + let height = reader.info().height as usize; let mut window = Window::new( - "Noise Test - Press ESC to exit", - reader.info().width as usize, - reader.info().height as usize, - WindowOptions { - resize: true, - scale_mode: ScaleMode::Center, - ..WindowOptions::default() - }, + "Image background example - Press ESC to exit", + width, + height, + WindowOptions::default(), ) - .expect("Unable to open Window"); + .expect("Unable to create the window"); + + window.set_target_fps(60); while window.is_open() && !window.is_key_down(Key::Escape) { - window - .update_with_buffer( - &u32_buffer, - reader.info().width as usize, - reader.info().height as usize, - ) - .unwrap(); + window.update_with_buffer(&buffer, width, height).unwrap(); } } diff --git a/examples/menu.rs b/examples/menu.rs index cf179748..a5f50a8a 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -1,8 +1,7 @@ -use minifb::MENU_KEY_CTRL; -use minifb::{InputCallback, Key, Menu, Scale, Window, WindowOptions}; +use minifb::{Key, Menu, Scale, Window, WindowOptions, MENU_KEY_CTRL}; -const WIDTH: usize = 640; -const HEIGHT: usize = 360; +const WIDTH: usize = 1280 / 2; +const HEIGHT: usize = 720 / 2; const MENU_TEST_ID: usize = 1; const OTHER_MENU_ID: usize = 2; @@ -11,19 +10,11 @@ const COLOR_1_ID: usize = 4; const COLOR_2_ID: usize = 5; const CLOSE_MENU_ID: usize = 6; -struct KeyCharCallback; - -impl InputCallback for KeyCharCallback { - fn add_char(&mut self, c: u32) { - println!("add_char {}", c); - } -} - fn main() { - let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; + let mut buffer = vec![0u32; WIDTH * HEIGHT]; let mut window = Window::new( - "Menu Test - Press ESC to exit", + "Menu example - press ESC to exit", WIDTH, HEIGHT, WindowOptions { @@ -32,9 +23,9 @@ fn main() { ..WindowOptions::default() }, ) - .expect("Unable to Open Window"); + .expect("Unable to open the window"); - window.set_input_callback(Box::new(KeyCharCallback {})); + window.set_target_fps(60); let mut menu = Menu::new("Test").unwrap(); let mut sub = Menu::new("Select Color").unwrap(); @@ -48,7 +39,6 @@ fn main() { sub.add_item("Color 2", COLOR_2_ID) .shortcut(Key::F7, 0) .build(); - menu.add_item("Menu Test", MENU_TEST_ID) .shortcut(Key::W, MENU_KEY_CTRL) .build(); @@ -91,7 +81,7 @@ fn main() { color_mul = 1; } CLOSE_MENU_ID => { - println!("remove menu"); + println!("Removed menu id {:?}", menu_handle); window.remove_menu(menu_handle); } _ => (), @@ -100,13 +90,6 @@ fn main() { println!("Menu id {} pressed", menu_id); } - window.get_keys().iter().for_each(|key| match key { - Key::W => println!("holding w!"), - Key::T => println!("holding t!"), - _ => (), - }); - - // We unwrap here as we want this code to exit if it fails window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap(); } } diff --git a/examples/mouse.rs b/examples/mouse.rs index 3445d96f..207f0b42 100644 --- a/examples/mouse.rs +++ b/examples/mouse.rs @@ -1,61 +1,59 @@ use minifb::{Key, MouseButton, MouseMode, Scale, Window, WindowOptions}; -const WIDTH: usize = 640; -const HEIGHT: usize = 360; +// Divided by 2 to account for the scale of the window +const WIDTH: usize = 1280 / 2; +const HEIGHT: usize = 720 / 2; fn main() { - let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; + let mut buffer = vec![0u32; WIDTH * HEIGHT]; - let mut window = match Window::new( - "Mouse Draw - Press ESC to exit", + let mut window = Window::new( + "Mouse drawing example - press ESC to exit", WIDTH, HEIGHT, WindowOptions { scale: Scale::X2, ..WindowOptions::default() }, - ) { - Ok(win) => win, - Err(err) => { - println!("Unable to create window {}", err); - return; - } - }; + ) + .expect("Unable to create the window"); + + window.set_target_fps(60); let (mut width, mut height) = (WIDTH, HEIGHT); while window.is_open() && !window.is_key_down(Key::Escape) { - { - let (new_width, new_height) = window.get_size(); - if new_width != width || new_height != height { - // Div by / 2 here as we use 2x scaling for the buffer - // copy valid bits of old buffer to new buffer - let mut new_buffer = vec![0; (new_width / 2) * (new_height / 2)]; - for y in 0..(height / 2).min(new_height / 2) { - for x in 0..(width / 2).min(new_width / 2) { - new_buffer[y * (new_width / 2) + x] = buffer[y * (width / 2) + x]; - } + let (new_width, new_height) = window.get_size(); + if new_width != width || new_height != height { + // Divide by / 2 here as we use 2x scaling for the buffer + let mut new_buffer = vec![0; (new_width / 2) * (new_height / 2)]; + + // copy valid bits of old buffer to new buffer + for y in 0..(height / 2).min(new_height / 2) { + for x in 0..(width / 2).min(new_width / 2) { + new_buffer[y * (new_width / 2) + x] = buffer[y * (width / 2) + x]; } - buffer = new_buffer; - width = new_width; - height = new_height; } + + buffer = new_buffer; + width = new_width; + height = new_height; } if let Some((x, y)) = window.get_mouse_pos(MouseMode::Discard) { let screen_pos = ((y as usize) * (width / 2)) + x as usize; if window.get_mouse_down(MouseButton::Left) { - buffer[screen_pos] = 0x00ffffff; + buffer[screen_pos] = 0x00ffffff; // white } if window.get_mouse_down(MouseButton::Right) { - buffer[screen_pos] = 0; + buffer[screen_pos] = 0x00000000; // black } } - if let Some(scroll) = window.get_scroll_wheel() { - println!("Scrolling {} - {}", scroll.0, scroll.1); + if let Some((scroll_x, scroll_y)) = window.get_scroll_wheel() { + println!("Scrolling {} - {}", scroll_x, scroll_y); } // We unwrap here as we want this code to exit if it fails diff --git a/examples/multi.rs b/examples/multi.rs index 6d7ff637..01b723aa 100644 --- a/examples/multi.rs +++ b/examples/multi.rs @@ -1,42 +1,58 @@ use minifb::{Key, Scale, Window, WindowOptions}; +// Size of the main window +const WIDTH: usize = 1280 / 2; +const HEIGHT: usize = 720 / 2; + fn main() { - let width = 640; - let height = 320; - let mut buffer = vec![0u32; width * height]; - let mut double = Window::new( - "Larger", - width, - height, + let mut buffer = vec![0u32; WIDTH * HEIGHT]; + + let mut larger_window = Window::new( + "Larger - press ESC to exit", + WIDTH, + HEIGHT, WindowOptions { scale: Scale::X2, ..WindowOptions::default() }, ) - .unwrap(); + .expect("Unable to create the larger window"); + + larger_window.set_target_fps(60); - let mut orig = Window::new( - "Smaller", - width, - height, + // Creating the smaller window after the larger one to make it appear on top + let mut smaller_window = Window::new( + "Smaller - press ESC to exit", + WIDTH, + HEIGHT, WindowOptions { + scale: Scale::X1, // Which is also the default ..WindowOptions::default() }, ) - .unwrap(); + .expect("Unable to create the smaller window"); - let mut pos = 13; + smaller_window.set_target_fps(60); - while orig.is_open() - && double.is_open() - && !orig.is_key_down(Key::Escape) - && !double.is_key_down(Key::Escape) + // Randomly drawing dots + let mut dot_position = 13; + + while smaller_window.is_open() + && larger_window.is_open() + && !smaller_window.is_key_down(Key::Escape) + && !larger_window.is_key_down(Key::Escape) { - orig.update_with_buffer(&buffer, width, height).unwrap(); - double.update_with_buffer(&buffer, width, height).unwrap(); - pos += 7; - pos *= 13; - pos %= buffer.len(); - buffer[pos] = 0xff_ff_ff; + smaller_window + .update_with_buffer(&buffer, WIDTH, HEIGHT) + .unwrap(); + larger_window + .update_with_buffer(&buffer, WIDTH, HEIGHT) + .unwrap(); + + dot_position += 7; + dot_position *= 13; + dot_position %= buffer.len(); + + buffer[dot_position] = 0x00_ff_ff_ff; } } diff --git a/examples/noise.rs b/examples/noise.rs index 9befcc3f..d557736a 100644 --- a/examples/noise.rs +++ b/examples/noise.rs @@ -1,13 +1,15 @@ use minifb::{Key, ScaleMode, Window, WindowOptions}; -const WIDTH: usize = 640 / 2; -const HEIGHT: usize = 360 / 2; +const WIDTH: usize = 1280; +const HEIGHT: usize = 720; fn main() { let mut noise; let mut carry; let mut seed = 0xbeefu32; + let mut buffer = vec![0u32; WIDTH * HEIGHT]; + let mut window = Window::new( "Noise Test - Press ESC to exit", WIDTH, @@ -18,22 +20,20 @@ fn main() { ..WindowOptions::default() }, ) - .expect("Unable to create window"); + .expect("Unable to create the window"); window.set_target_fps(60); - let mut buffer: Vec = Vec::with_capacity(WIDTH * HEIGHT); - let mut size = (0, 0); while window.is_open() && !window.is_key_down(Key::Escape) { - let new_size = (window.get_size().0, window.get_size().1); + let new_size = window.get_size(); if new_size != size { size = new_size; buffer.resize(size.0 * size.1, 0); } - for i in buffer.iter_mut() { + for pixel in buffer.iter_mut() { noise = seed; noise >>= 3; noise ^= seed; @@ -42,20 +42,9 @@ fn main() { seed >>= 1; seed |= carry << 30; noise &= 0xFF; - *i = (noise << 16) | (noise << 8) | noise; - } - window.get_keys().iter().for_each(|key| match key { - Key::W => println!("holding w!"), - Key::T => println!("holding t!"), - _ => (), - }); - - window.get_keys_released().iter().for_each(|key| match key { - Key::W => println!("released w!"), - Key::T => println!("released t!"), - _ => (), - }); + *pixel = (noise << 16) | (noise << 8) | noise; + } window .update_with_buffer(&buffer, new_size.0, new_size.1) diff --git a/resources/icon256.ico b/examples/resources/icon256.ico similarity index 100% rename from resources/icon256.ico rename to examples/resources/icon256.ico diff --git a/resources/planet.png b/examples/resources/planet.png similarity index 100% rename from resources/planet.png rename to examples/resources/planet.png diff --git a/resources/uv.png b/examples/resources/uv.png similarity index 100% rename from resources/uv.png rename to examples/resources/uv.png diff --git a/examples/text.rs b/examples/text.rs index e72294d3..8c4b188a 100644 --- a/examples/text.rs +++ b/examples/text.rs @@ -1,32 +1,31 @@ -use minifb::{Key, Scale, Window, WindowOptions}; +use minifb::{Key, Window, WindowOptions}; -const WIDTH: usize = 640; -const HEIGHT: usize = 360; +const WIDTH: usize = 1280; +const HEIGHT: usize = 720; fn main() { + let mut buffer = vec![0u32; WIDTH * HEIGHT]; + let mut window = Window::new( "Plasma + Text Example", WIDTH, HEIGHT, WindowOptions { resize: false, - scale: Scale::X1, ..WindowOptions::default() }, ) - .expect("Unable to create window"); + .expect("Unable to create the window"); window.set_target_fps(60); - let mut buffer: Vec = Vec::with_capacity(WIDTH * HEIGHT); - let mut size = (0, 0); let mut time = 0.0f32; - let status_text = StatusText::new(WIDTH, HEIGHT, 2); + let press_esc_text = Text::new(WIDTH, HEIGHT, 2); while window.is_open() && !window.is_key_down(Key::Escape) { - let new_size = (window.get_size().0, window.get_size().1); + let new_size = window.get_size(); if new_size != size { size = new_size; buffer.resize(size.0 * size.1, 0); @@ -34,22 +33,24 @@ fn main() { let y_step = 1.0 / HEIGHT as f32; let x_step = 1.0 / WIDTH as f32; - let mut y = 0.0; + let mut y = 0.0; for yi in 0..HEIGHT { - let buf = &mut buffer[yi * WIDTH..(yi + 1) * WIDTH]; - let mut x = 0.0f32; + let row = &mut buffer[yi * WIDTH..(yi + 1) * WIDTH]; - // So this code is really slow, but good enough as example :) + // So this code is really slow, but good enough as an example :) + let mut x = 0.0; for xi in 0..WIDTH { let k = 0.1 + (y + (0.148 - time).sin()).cos() + 2.4 * time; let w = 0.9 + (x + (0.628 + time).cos()).cos() - 0.7 * time; let d = (x * x + y * y).sqrt(); + let s = 7.0 * (d + w).cos() * (k + w).sin(); + let r = ((s + 0.2).cos() * 255.0) as u32; let g = ((s + 0.5).cos() * 255.0) as u32; let b = ((s + 0.7).cos() * 255.0) as u32; - buf[xi] = (r << 16) | (g << 8) | b; + row[xi] = (r << 16) | (g << 8) | b; x += x_step; } @@ -58,7 +59,7 @@ fn main() { } // Show some basic text at the bottom of the screen - status_text.draw(&mut buffer, (20, HEIGHT - 20), "Press ESC to exit"); + press_esc_text.draw(&mut buffer, (20, HEIGHT - 20), "Press ESC to exit"); window .update_with_buffer(&buffer, new_size.0, new_size.1) @@ -69,10 +70,10 @@ fn main() { } } -pub struct StatusText { +pub struct Text { texture: Vec, width: usize, - //height: usize, + // height: usize, scale: usize, } @@ -85,9 +86,9 @@ fn color_from_bit(bit: u8) -> u32 { } } -impl StatusText { +impl Text { pub fn new(width: usize, _height: usize, scale: usize) -> Self { - // unpack texture for easier drawing + // Unpack texture for easier drawing let mut texture = Vec::with_capacity(128 * 128); for t in MICROKNIGHT_FONT { @@ -104,22 +105,20 @@ impl StatusText { Self { texture, width, - //height, + // height, scale, } } - pub fn draw(&self, screen: &mut [u32], pos: (usize, usize), text: &str) { - let mut x = pos.0; - let y = pos.1; + pub fn draw(&self, screen: &mut [u32], (mut x, y): (usize, usize), text: &str) { for c in text.chars() { let mut index = c as usize - ' ' as usize; if index > MICROKNIGHT_LAYOUT.len() as usize { index = 0; } - let layout = MICROKNIGHT_LAYOUT[index]; - let texture_offset = (layout.1 as usize * 128) + layout.0 as usize; + let (layout_x, layout_y) = MICROKNIGHT_LAYOUT[index]; + let texture_offset = layout_x as usize + (layout_y as usize * 128); for fy in 0..8 * self.scale { let ty = fy / self.scale; @@ -139,7 +138,7 @@ impl StatusText { // Microknight font (128x128 packed with 1 bit per pixel) #[rustfmt::skip] -pub static MICROKNIGHT_FONT: &[u8] = &[ +static MICROKNIGHT_FONT: [u8; ((128 * 128) / u8::BITS) as usize] = [ 0x00, 0x0c, 0x1b, 0x0d, 0x81, 0x03, 0x01, 0xc0, 0x30, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1b, 0x0d, 0x87, 0xc4, 0xb3, 0x60, 0x30, 0x30, 0x0c, 0x1b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x09, 0x1f, 0xcd, 0x03, 0xe1, 0xc0, 0x10, 0x60, 0x06, 0x0e, 0x03, 0x00, 0x00, 0x00, @@ -272,7 +271,7 @@ pub static MICROKNIGHT_FONT: &[u8] = &[ // Font layout (generated from Angelcode Bitmap Font generator) #[rustfmt::skip] -pub static MICROKNIGHT_LAYOUT: &[(u8, u8)] = &[ +static MICROKNIGHT_LAYOUT: [(u8, u8); 224] = [ (0, 0), (9, 0), (18, 0), (27, 0), (36, 0), (45, 0), (54, 0), (63, 0), (72, 0), (81, 0), (90, 0), (99, 0), (108, 0), (117, 0), (0, 9), (9, 9), (18, 9), (27, 9), (36, 9), (45, 9), (54, 9), (63, 9), (72, 9), (81, 9), (90, 9), (99, 9), (108, 9), (117, 9), (0, 18), (9, 18), (18, 18), (27, 18), (36, 18), (45, 18), (54, 18), (63, 18), (72, 18), (81, 18), diff --git a/examples/title_cursor.rs b/examples/title_cursor.rs index e96050d7..6ca7a65d 100644 --- a/examples/title_cursor.rs +++ b/examples/title_cursor.rs @@ -1,11 +1,11 @@ -use minifb::{CursorStyle, Key, MouseMode, Scale, Window, WindowOptions}; +use minifb::{CursorStyle, Key, MouseMode, Window, WindowOptions}; -const WIDTH: usize = 640; -const HEIGHT: usize = 360; +const WIDTH: usize = 1280; +const HEIGHT: usize = 720; struct Rect { - x: usize, - y: usize, + top_left_x: usize, + top_left_y: usize, width: usize, height: usize, color: u32, @@ -13,99 +13,100 @@ struct Rect { } impl Rect { - pub fn is_inside(&self, xf: f32, yf: f32) -> bool { - let x = xf as usize; - let y = yf as usize; - let xe = self.x + self.width; - let ye = self.y + self.height; + const WIDTH: usize = WIDTH / 4; // Four rectangles per row + const HEIGHT: usize = HEIGHT / 2; // Two rectangles per column - (y >= self.y) && (y <= ye) && (x >= self.x) && (x <= xe) + pub fn is_inside(&self, top_left_x: usize, top_left_y: usize) -> bool { + let bottom_right_x = self.top_left_x + self.width; + let bottom_right_y = self.top_left_y + self.height; + + (top_left_y >= self.top_left_y) + && (top_left_y <= bottom_right_y) + && (top_left_x >= self.top_left_x) + && (top_left_x <= bottom_right_x) } } fn fill_rect(dest: &mut [u32], rect: &Rect) { for y in 0..rect.height { for x in 0..rect.width { - dest[((rect.y + y) * WIDTH) + rect.x + x] = rect.color; + dest[((rect.top_left_y + y) * WIDTH) + rect.top_left_x + x] = rect.color; } } } fn main() { - let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; + let mut buffer = vec![0u32; WIDTH * HEIGHT]; + + let mut window = Window::new("I haz no title :(", WIDTH, HEIGHT, WindowOptions::default()) + .expect("Unable to open the window"); + + window.set_target_fps(60); - let mut window = Window::new( - "I haz no title :(", - WIDTH, - HEIGHT, - WindowOptions { - scale: Scale::X2, - ..WindowOptions::default() - }, - ) - .expect("Unable to Open Window"); let rects = [ + // Top row Rect { - x: 0, - y: 0, - width: 160, - height: 180, + top_left_x: 0, + top_left_y: 0, + width: Rect::WIDTH, + height: Rect::HEIGHT, color: 0x00b27474, cursor_style: CursorStyle::Arrow, }, Rect { - x: 160, - y: 0, - width: 160, - height: 180, + top_left_x: Rect::WIDTH, + top_left_y: 0, + width: Rect::WIDTH, + height: Rect::HEIGHT, color: 0x00b28050, cursor_style: CursorStyle::Ibeam, }, Rect { - x: 320, - y: 0, - width: 160, - height: 180, + top_left_x: Rect::WIDTH * 2, + top_left_y: 0, + width: Rect::WIDTH, + height: Rect::HEIGHT, color: 0x00a9b250, cursor_style: CursorStyle::Crosshair, }, Rect { - x: 480, - y: 0, - width: 160, - height: 180, + top_left_x: Rect::WIDTH * 3, + top_left_y: 0, + width: Rect::WIDTH, + height: Rect::HEIGHT, color: 0x0060b250, cursor_style: CursorStyle::ClosedHand, }, + // Bottom row Rect { - x: 0, - y: 180, - width: 160, - height: 180, + top_left_x: 0, + top_left_y: Rect::HEIGHT, + width: Rect::WIDTH, + height: Rect::HEIGHT, color: 0x004fb292, cursor_style: CursorStyle::OpenHand, }, Rect { - x: 160, - y: 180, - width: 160, - height: 180, + top_left_x: Rect::WIDTH, + top_left_y: Rect::HEIGHT, + width: Rect::WIDTH, + height: Rect::HEIGHT, color: 0x004f71b2, cursor_style: CursorStyle::ResizeLeftRight, }, Rect { - x: 320, - y: 180, - width: 160, - height: 180, + top_left_x: Rect::WIDTH * 2, + top_left_y: Rect::HEIGHT, + width: Rect::WIDTH, + height: Rect::HEIGHT, color: 0x008850b2, cursor_style: CursorStyle::ResizeUpDown, }, Rect { - x: 480, - y: 180, - width: 160, - height: 180, + top_left_x: Rect::WIDTH * 3, + top_left_y: Rect::HEIGHT, + width: Rect::WIDTH, + height: Rect::HEIGHT, color: 0x00b25091, cursor_style: CursorStyle::ResizeAll, }, @@ -116,16 +117,15 @@ fn main() { for rect in &rects { fill_rect(&mut buffer, rect); - if rect.is_inside(mx, my) { + if rect.is_inside(mx as usize, my as usize) { window.set_cursor_style(rect.cursor_style); window.set_title(&format!( - "Different cursor on each color region: {:?}", + "Cursor of hovered rectangle: {:?}", rect.cursor_style )); } } - // We unwrap here as we want this code to exit if it fails window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap(); } } diff --git a/examples/topmost.rs b/examples/topmost.rs index 555de126..13aceacb 100644 --- a/examples/topmost.rs +++ b/examples/topmost.rs @@ -1,13 +1,15 @@ use minifb::{Key, ScaleMode, Window, WindowOptions}; +const WIDTH: usize = 1280; +const HEIGHT: usize = 720; + fn main() { - // Allocate the output buffer. - let buf = vec![0x00FFFF00; 320 * 480]; + let buffer = vec![0x00_FF_FF_00u32; WIDTH * HEIGHT]; let mut window = Window::new( - "Press ESC to exit", - 320, - 480, + "Topmost example - press ESC to exit", + WIDTH, + HEIGHT, WindowOptions { resize: true, scale_mode: ScaleMode::Center, @@ -15,9 +17,11 @@ fn main() { ..WindowOptions::default() }, ) - .expect("Unable to open Window"); + .expect("Unable to open the window"); + + window.set_target_fps(60); while window.is_open() && !window.is_key_down(Key::Escape) { - window.update_with_buffer(&buf, 320, 480).unwrap(); + window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap(); } } diff --git a/examples/transparent.rs b/examples/transparent.rs index e8c41566..4d8bb949 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -1,24 +1,51 @@ use minifb::{Key, ScaleMode, Window, WindowOptions}; +const WIDTH: usize = 1280; +const HEIGHT: usize = 720; + fn main() { - // Allocate the output buffer. - let buf = vec![0x00AAFF33; 320 * 480]; + let mut buffer = vec![0u32; WIDTH * HEIGHT]; let mut window = Window::new( - "Press ESC to exit", - 320, - 480, + "Transparent window example - press ESC to exit", + WIDTH, + HEIGHT, WindowOptions { - resize: true, - scale_mode: ScaleMode::Center, - borderless: true, transparency: true, ..WindowOptions::default() }, ) - .expect("Unable to open Window"); + .expect("Unable to create the window"); + + window.set_target_fps(60); + // produces a wave pattern where the screen goes from red to blue, and vice-versa + let mut wave: u8 = 0; + let mut wave_direction: i8 = 1; while window.is_open() && !window.is_key_down(Key::Escape) { - window.update_with_buffer(&buf, 320, 480).unwrap(); + let red: u32 = (wave as u32) << 16; + let green: u32 = 64 << 8; + let blue: u32 = (255 - wave) as u32; + let bg_color = red | green | blue; + + for pixel in buffer.iter_mut() { + *pixel = bg_color; + } + + // We unwrap here as we want this code to exit if it fails. Real applications may want to handle this in a different way + window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap(); + + // switch color wave directions + match wave.checked_add_signed(wave_direction) { + Some(new_wave) => wave = new_wave, + None => { + wave_direction = -wave_direction; + if wave_direction > 0 { + wave += 1; + } else { + wave -= 1; + } + } + } } } diff --git a/rustfmt.toml b/rustfmt.toml index 6bf96e6c..78df7d14 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -19,7 +19,7 @@ fn_single_line = false where_single_line = false imports_indent = "Block" imports_layout = "Mixed" -merge_imports = false +merge_imports = true reorder_imports = true reorder_modules = true reorder_impl_items = false