Zheoni / bevy_pixel_buffer

A library to draw pixels in bevy
MIT License
42 stars 7 forks source link

Unable to set Pixel without iterating over [Pixel] #10

Closed zanciks closed 9 months ago

zanciks commented 9 months ago

Perhaps I'm misunderstanding how some of these functions work, but it's hard to tell. Every example uses Frame::per_pixel().

None of these approaches work to set a single Pixel, and I'm not sure why.

fn update(mut pb: QueryPixelBuffer) {
    let mut frame = pb.frame();
    let pixels = frame.raw_mut();
    pixels[12] = Pixel::WHITE;
}
fn update(mut pb: QueryPixelBuffer) {
    let mut frame = pb.frame();
    frame.set(UVec2::new(3, 2), Pixel::WHITE)
        .expect("Error!");
}
fn update(mut pb: QueryPixelBuffer) {
    let mut frame = pb.frame();
    let pixels = frame.raw_mut();
    let pixel = &mut pixels[13];
    *pixel = Pixel::WHITE;
}

The only possible way I can find to set pixels without using Frame::per_pixel() is like this

fn update(mut pb: QueryPixelBuffer) {
    let mut frame = pb.frame();
    let pixels = frame.raw_mut();
    for pixel in pixels {
        // we can also do pixels.iter().enumerate() and make sure enumeration is some number
        *pixel = Pixel::WHITE;
    }
}

I include this, because it is very similar to my third code block above. In both of those, we are dereferencing a &mut Pixel, yet only the case inside of the loop works.

Testing on EndeavourOS, updated Rust version with bevy = "0.12.0" bevy_pixel_buffer = "0.6.0"

Zheoni commented 9 months ago

Hi! I'm on windows, bevy 0.12.1, and all your update functions work for me.

I've added a new single_pixel example, but it's just the second snippet you posted. Test if the new example works on your system before further investigation. Do it in a clean project or clone the repo and run cargo run --example single_pixel.

zanciks commented 9 months ago

Thanks for the speedy reply! The example actually works great. After running that and debugging my code, it would seem the error is actually coming from how I'm importing DefaultPlugins.

const WIDTH:  f32 = 128.0;
const HEIGHT: f32 = 128.0;

fn main() {
    let size = PixelBufferSize {
        size: UVec2::new(WIDTH as u32, HEIGHT as u32),
        pixel_size: UVec2::new(16, 16),
    };

    App::new()
        .add_plugins(DefaultPlugins.set(
            WindowPlugin {
                primary_window: Some(Window {
                    resolution: WindowResolution::new(WIDTH, HEIGHT),
                    ..default()
                }),
                ..default()
            }
        ))
        .add_plugins(PixelBufferPlugin)
        .add_systems(Startup, pixel_buffer_setup(size))
        .add_systems(Update, update)
        .run();
}

fn update(mut pb: QueryPixelBuffer) {
    let mut frame = pb.frame();
    let mut rng = rand::thread_rng();
    let pos = (
        rng.gen_range(0..frame.size().x),
        rng.gen_range(0..frame.size().y),
    );
    frame.set(pos, Pixel::random()).expect("out of bounds");
}

I'm not getting any errors, but only a few pixels are being changed in frame, and it takes a while. Changing pos to (5, 5) for instance shows that, even though it SHOULD be in range, it isn't visible. Is there perhaps a better way to be setting my window resolution that works with this crate?

ie.

fn update(mut pb: QueryPixelBuffer) {
    let mut frame = pb.frame();
    frame.set((5, 5), Pixel::random()).expect("out of bounds");
}

Doesn't set any visible pixel to Pixel::random().

zanciks commented 9 months ago

Oh, I think I have found the issue! I think it was an issue of misunderstanding on my end. I had assumed that no matter what PixelBufferSize.pixel_size was, the first visible pixel would be at (0, 0), however, this isn't the case! In the code I posted in Comment 3 (just above), the center of the screen is pixel (256, 256) [which is coming from the 512, 512 size]. The area is then 32x32 pixels wide, so the first visible pixel is (256 - 16, 256 - 16) = (240, 240).

My code to change the FIRST pixel is as follows

const WIDTH:  f32 = 512.0;
const HEIGHT: f32 = 512.0;

fn main() {
    let size = PixelBufferSize {
        size: UVec2::new(WIDTH as u32, HEIGHT as u32),
        pixel_size: UVec2::new(16, 16),
    };

    App::new()
        .add_plugins(DefaultPlugins.set(
            WindowPlugin {
                primary_window: Some(Window {
                    resolution: WindowResolution::new(WIDTH, HEIGHT),
                    ..default()
                }),
                ..default()
            }
        ))
        .add_plugins(PixelBufferPlugin)
        .add_systems(Startup, pixel_buffer_setup(size))
        .add_systems(Update, update)
        .run();
}

fn update(mut pb: QueryPixelBuffer) {
    let mut frame = pb.frame();
    frame.set((240, 240), Pixel::random()).expect("No worky!");
}
zanciks commented 9 months ago

Simpler thing to do is to read the docs I guess lol

Just needed to not have PixelBufferSize be equal to my screen resolution...

    let size = PixelBufferSize {
        size: UVec2::new(WIDTH as u32 / 4, HEIGHT as u32 / 4),
        pixel_size: UVec2::new(4, 4),
    };

Fixes all problems!

Zheoni commented 9 months ago

Ok, so you were drawing outside of the window. Naming things is hard, but yes, size is not actual screen size, but the size of the buffer, and if the pixels are bigger, they won't fit.

I'm glad you found the solution, good luck with your project 😄