How to add a window icon in Bevy? - rust

I'm making a game in rust and I want it to be legit. Bevy ECS is great. I have been following tutorials and reading documentation, but there is this one thing I want to know. Can I change the window icon? If so, how?

It is not easy to do. You may see discussion of the problem here, and pr here and here. I am sure it will be solved in a nice standard way soon, meanwhile there is hacky way to do it described here
use bevy::window::WindowId;
use bevy::winit::WinitWindows;
use winit::window::Icon;
fn set_window_icon(
// we have to use `NonSend` here
windows: NonSend<WinitWindows>,
) {
let primary = windows.get_window(WindowId::primary()).unwrap();
// here we use the `image` crate to load our icon data from a png file
// this is not a very bevy-native solution, but it will do
let (icon_rgba, icon_width, icon_height) = {
let image = image::open("my_icon.png")
.expect("Failed to open icon path")
.into_rgba8();
let (width, height) = image.dimensions();
let rgba = image.into_raw();
(rgba, width, height)
};
let icon = Icon::from_rgba(icon_rgba, icon_width, icon_height).unwrap();
primary.set_window_icon(Some(icon));
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(set_window_icon)
.run();
}

Related

Access bevy asset right after loading via AssetServer

Is it possible to access a bevy asset right after it was loaded from the AssetServer?
I've read actual loading happens in the background but couldn't find in either official documentation or the bevy cheat book if it is possible to wait for the actual loading to happen inside the same function?
Example of what I'm trying to do
fn f(asset_server: Res<AssetServer>, image_assets: Res<Assets<Image>>,) {
let image: Handle<Image> = assert_server.load("img.png");
// wait for `image` to be loaded...
// NOTE: that this doesn't work - it just goes into an infinite loop
while asset_server.get_load_state(&image) != LoadState::Loaded { }
let image_asset = image_assets.get(&image).unwrap();
}
The reason I need this is to check some of the image's data, for example it's size.
As you probably shouldn't be halting the function for the asynchronous load of the file. Maybe you can create some Entity with the handle. You could have another system running a query for this entity and consume the entity when the handle shows the image is loaded.
Looking it up this appears to be a suggested pattern in the unoffical bevy book.
#[derive(Resource)]
struct AssetsLoading(Vec<HandleUntyped>);
fn setup(server: Res<AssetServer>, mut loading: ResMut<AssetsLoading>) {
// we can have different asset types
let font: Handle<Font> = server.load("my_font.ttf");
let menu_bg: Handle<Image> = server.load("menu.png");
let scene: Handle<Scene> = server.load("level01.gltf#Scene0");
// add them all to our collection for tracking
loading.0.push(font.clone_untyped());
loading.0.push(menu_bg.clone_untyped());
loading.0.push(scene.clone_untyped());
}
fn check_assets_ready(
mut commands: Commands,
server: Res<AssetServer>,
loading: Res<AssetsLoading>
) {
use bevy::asset::LoadState;
match server.get_group_load_state(loading.0.iter().map(|h| h.id)) {
LoadState::Failed => {
// one of our assets had an error
}
LoadState::Loaded => {
// all assets are now ready
// this might be a good place to transition into your in-game state
// remove the resource to drop the tracking handles
commands.remove_resource::<AssetsLoading>();
// (note: if you don't have any other handles to the assets
// elsewhere, they will get unloaded after this)
}
_ => {
// NotLoaded/Loading: not fully ready yet
}
}
}

Using nannou.rs, how can I provide the correct parameters to the load_from_image_buffer method?

I am currently trying to learn Nannou.rs. I generate a Luma8 image (corresponding to a Perlin heightmap) and I am trying to display it in my app's window using the function load_from_image_buffer implemented by nannou::wgpu::Texture in the model function as follow:
fn model(app: &App) -> Model {
let img_buf = NoiseBuilder::generate_image(256, 8, 8, None);
let texture = wgpu::Texture::load_from_image_buffer(device, queue, usage, &img_buf).unwrap();
Model { texture }
}
As you can see, in this snippet I am not defining the device, queue and usage parameters. I tried multiple things but nothing worked, and online resources are rather scarce.
So my question really is how can I provide this parameters?
I played around first with the from_image function and it worked, but as I am trying to learn my way around the library I am interested in the use of this specific function. Also this parameters are required by many other methods and I ll need to understand it anyway.
The wgpu module imported in the snippet above is the nannou::wgpu and not directly the wgpu crate.
The NoiseBuilder::generate_image return an ImageBuffer<Luma<u8>, Vec<u8>> variable.
You can use the trait method with_device_queue_pair which is defined in the trait WithDeviceQueuePair and implemented for either App or Window.
The usage is just the normal wgpu::TextureUsages.
So if you would like to mimic the from_path function of the texture you could do something like this (untested):
fn model(app: &App) -> Model {
let img_buf = NoiseBuilder::generate_image(256, 8, 8, None);
let usage = nannou::wgpu::TextureUsages::COPY_SRC |
nannou::wgpu::TextureUsages::COPY_DST |
nannou::wgpu::TextureUsages::RENDER_ATTACHMENT;
src.with_device_queue_pair(|device, queue| {
let texture = wgpu::Texture::load_from_image_buffer(device, queue, usage, &img_buf).unwrap();
Model { texture }
})
}

How do you use a teensy 4 pin via the teensy4-bsp Rust crate as an input with the pull-up resistor enabled?

I am trying to figure out how to do the Rust equivalent of
pinMode(PIN_D7, INPUT_PULLUP); // Pushbutton
(from https://www.pjrc.com/teensy/td_digital.html)
I have created a project using the template https://github.com/mciantyre/teensy4-rs-template as outlined in the Getting Started section of https://github.com/mciantyre/teensy4-rs .
Unfortunately, the Rust arduino code is a rabbit hole that IntelliJ IDEA can not fully navigate (they use macros to generate structs and impls), so I do not get any helpful completion results that would help me figure out what methods and fields are available.
I'm not sure what to do with pins.p7 to activate the pull-up resistor, or even sample it. Chasing the docs from p7 to P7 to B1_01 to Pad leaves me still confused.
(documenting some failure here)
I did some experiments and some text searches across the crates and found the Config structure.
Unfortunately, when I used it like this, the results were not reliable.
// pull-down resistor. Switch drags to 3.3v
fn mission1(mut switch_pin: B0_10, led: &mut LED, systick: &mut SysTick) -> !
{
let cfg = teensy4_bsp::hal::iomuxc::Config::zero().set_pullupdown(PullUpDown::Pulldown100k);
iomuxc::configure(&mut switch_pin, cfg);
let bacon = GPIO::new(switch_pin);
loop {
if bacon.is_set() {
led.toggle()
}
systick.delay(300);
}
}
It still picked up spurious button clicks. I turned things around and tried to rig it for pull-up
// pull-up resistor. Switch drags to ground
fn mission2(mut switch_pin: B0_10, led: &mut LED, systick: &mut SysTick) -> !
{
let pull_up = match 22
{
100 => PullUpDown::Pullup100k, // unreliable
47 => PullUpDown::Pullup47k, // unreliable
_ => PullUpDown::Pullup22k,
};
let cfg = teensy4_bsp::hal::iomuxc::Config::zero().set_pullupdown(pull_up);
iomuxc::configure(&mut switch_pin, cfg);
let bacon = GPIO::new(switch_pin);
loop {
if ! bacon.is_set() {
led.toggle()
}
systick.delay(300);
}
}
All 3 of the pull-up options were not useful. I attached a multimeter and it was reading about 0.67v between the pin and ground with the switch open and the 22k pull-up resistor option.
When I wire up a physical 10K resistor it behaves like I expect and the multimeter measures 3.23V. If I wire two 10Ks in series for pull-up, it measures 3.20V.
I am going to say that this is not the proper technique for a Teensy 4.0.
Based on the response to https://github.com/mciantyre/teensy4-rs/issues/107 and the code at https://github.com/imxrt-rs/imxrt-hal/issues/112 I was able to create the following example that seems to work on my teensy 4.0
let cfg = Config::zero()
.set_hysteresis(Hysteresis::Enabled)
.set_pull_keep(PullKeep::Enabled)
.set_pull_keep_select(PullKeepSelect::Pull)
.set_pullupdown(PullUpDown::Pulldown100k);
iomuxc::configure(&mut switch_pin, cfg);
let switch_gpio = GPIO::new(switch_pin);
loop {
if switch_gpio.is_set() {
led.toggle()
}
systick.delay(LED_PERIOD_MS);
}
Full code at https://github.com/mciantyre/teensy4-rs/blob/997d92cc880185f22272d1cfd54de54732154bb5/examples/pull_down_pin.rs .

Depending on Build Target, use fltk::osxMenuBar or MenuBar in fltk-rs

I'm creating a cross-platform GUI App with fltk-rs. Depending on which platform I'm targeting (OSX or Windows), I'd like to use a different struct for my menu bar. If I'm targeting OSX, for my menu bar I'd like to use fltk::menu::SysMenuBar and for Windows, I'd like to use fltk::menu::MenuBar.
I don't want to keep to separate versions of my code, one for Windows, and one for OSX, just so I can use different a different Struct for my menu.
What are some approaches to changing which struct is used based on the build target without creating different codebases?
use fltk::{app::*, frame::*, image::*, window::*, menu::*};
fn main() {
let app = App::default().with_scheme(Scheme::Gleam);
let mut wind = Window::new(100, 100, 400, 300, "Hello from rust");
//if target is Windows
let menubar = MenuBar::default()
//if target is OSX
let menubar = SysMenuBar::default()
wind.end();
wind.show();
app.run().unwrap();
}
Consulting the Rust Reference on Conditional Compilation. You would use the #[cfg(...)] attribute with the target_os option:
#[cfg(target_os = "windows")]
let menubar = MenuBar::default();
#[cfg(target_os = "macos")]
let menubar = SysMenuBar::default();

Calling getBBox for a SVG text element in a Seed Rust application

I just made my first steps with WASM and Seed which was a very smooth experience so far. I was able to create SVG using svg!, circle!, text!, ... and similar macros. To generate my SVG in the proper way, I have to measure text. My idea is to generate SVG text nodes and call getBBox on the node. I figured out that Seed is using web_sys and that getBBox is implemented there.
My problem is how to get from the Node created by text! to the SvgTextElement. I tried to access the node_ws field, but it seems to be "empty". It might not yet been created, but I don't now enough about the Seed internals.
So how do I create a SVG text node so that I can call getBBox on it before generating the "main" SVG nodes?
You can use el_ref to get a reference to the DOM element. Something like this ought to work:
struct Model {
element: ElRef<web_sys::SvgTextElement>,
}
fn view(model: &Model) -> Node<Msg> {
svg!![
text![
el_ref(&model.element),
// ...
],
// ...
]
}
fn init(orders: &mut impl Orders<Msg>) -> Model {
orders.after_next_render(|_| Msg::Rendered);
// ...
}
fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg {
Msg::Rendered => {
let element = model.element.get().expect("no svg text element");
let b_box = element.get_b_box();
// ...
}
// ...
}
}

Resources