pixels icon indicating copy to clipboard operation
pixels copied to clipboard

Winit Examples outdated for use with new versions of winit / new api

Open allthetime opened this issue 1 year ago • 5 comments

Hi. I was following the basic winit example and noticed it is out of date / incompatible with new versions of winit.

I've made a new version of the minimal-example: https://github.com/allthetime/pixels-winit-minimal

allthetime avatar Jan 05 '25 21:01 allthetime

Thanks! There's also #403, which should probably be reopened.

parasyte avatar Jan 05 '25 22:01 parasyte

hello, thanks for the example update. I tried on my side with pixels (0.15) and I got a lifetime error

   |
28 |     pixels: Option<Pixels>,
   |                    ^^^^^^ expected named lifetime parameter
   |
help: consider introducing a named lifetime parameter
   |
26 ~ pub struct App<'a> {
27 |     window: Option<Arc<Window>>,
28 ~     pixels: Option<Pixels<'a>>,
   |

For more information about this error, try `rustc --explain E0106`.
error: could not compile `mypixels` (bin "mypixels") due to 1 previous error

~~I fix it this way.~~ the fix is #403

cargo.toml

[package]
name = "mypixels"
version = "0.1.0"
edition = "2021"


[dependencies]
pixels = {version = "0.15.0"}
winit = {version ="0.30.9", features =["x11" ]}

error-iter = "0.4.1"
dotenv = "0.15.0"

main.rs

use error_iter::ErrorIter as _;
use log::error;
use pixels::{Pixels, SurfaceTexture};
use std::sync::Arc;
use winit::{
    application::ApplicationHandler,
    error::EventLoopError,
    event::WindowEvent,
    event_loop::{ControlFlow, EventLoop},
    keyboard::{KeyCode, PhysicalKey},
    window::{Window, WindowAttributes},
};

const WIDTH: u32 = 320;
const HEIGHT: u32 = 240;
const BOX_SIZE: i16 = 64;

struct World {
    box_x: i16,
    box_y: i16,
    velocity_x: i16,
    velocity_y: i16,
}

#[derive(Default)]
struct App {
    pixels: Option<Pixels<'static>>,
    window: Option<Arc<Window>>,
    world: World,
}

impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        let window = {
            let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
            Arc::new(
                event_loop
                    .create_window(
                        Window::default_attributes()
                            .with_title("Hello Pixels")
                            .with_inner_size(size)
                            .with_min_inner_size(size),
                    )
                    .unwrap(),
            )
        };

        self.window = Some(window.clone());
        self.pixels = {
            let window_size = window.inner_size();
            let surface_texture =
                SurfaceTexture::new(window_size.width, window_size.height, window.clone());
            match Pixels::new(WIDTH, HEIGHT, surface_texture) {
                Ok(pixels) => {
                    // Kick off the redraw loop
                    window.request_redraw();

                    Some(pixels)
                }
                Err(err) => {
                    log_error("pixels::new", err);
                    event_loop.exit();

                    None
                }
            }
        };
    }

    fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
        match event {
            WindowEvent::CloseRequested
            | WindowEvent::KeyboardInput {
                event:
                    KeyEvent {
                        logical_key: Key::Named(NamedKey::Escape),
                        ..
                    },
                ..
            } => {
                event_loop.exit();
            }

            WindowEvent::Resized(size) => {
                if let Err(err) = self
                    .pixels
                    .as_mut()
                    .unwrap()
                    .resize_surface(size.width, size.height)
                {
                    log_error("pixels.resize_surface", err);
                    event_loop.exit();
                }
            }

            WindowEvent::RedrawRequested => {
                // Update internal state
                self.world.update();

                // Draw the current frame
                self.world.draw(self.pixels.as_mut().unwrap().frame_mut());
                if let Err(err) = self.pixels.as_ref().unwrap().render() {
                    log_error("pixels.render", err);
                    event_loop.exit();
                } else {
                    // Queue a redraw for the next frame
                    self.window.as_ref().unwrap().request_redraw();
                }
            }

            _ => (),
        }
    }
}

impl World {
    fn new() -> Self {
        Self {
            box_x: 24,
            box_y: 16,
            velocity_x: 1,
            velocity_y: 1,
        }
    }

    /// Update the `World` internal state; bounce the box around the screen.
    fn update(&mut self) {
        if self.box_x <= 0 || self.box_x + BOX_SIZE > WIDTH as i16 {
            self.velocity_x *= -1;
        }
        if self.box_y <= 0 || self.box_y + BOX_SIZE > HEIGHT as i16 {
            self.velocity_y *= -1;
        }

        self.box_x += self.velocity_x;
        self.box_y += self.velocity_y;
    }

    /// Draw the `World` state to the frame buffer.
    ///
    /// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb`
    fn draw(&self, frame: &mut [u8]) {
        for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
            let x = (i % WIDTH as usize) as i16;
            let y = (i / WIDTH as usize) as i16;

            let inside_the_box = x >= self.box_x
                && x < self.box_x + BOX_SIZE
                && y >= self.box_y
                && y < self.box_y + BOX_SIZE;

            let rgba = if inside_the_box {
                [0x5e, 0x48, 0xe8, 0xff]
            } else {
                [0x48, 0xb2, 0xe8, 0xff]
            };

            pixel.copy_from_slice(&rgba);
        }
    }
}

//log_error and main stay the same...

SRabia avatar Mar 31 '25 23:03 SRabia

Hi!

pub struct App<'a> { window: Option<Arc<Window>>, pixels: Option<Pixels<'a>>,// added lifetime here world: World, }

'a is equivalent to 'static in this example due to Pixels<'_> owning an Arc<Window> in:

let surface_texture = SurfaceTexture::new(window_width, window_height, window.clone());// clone the window here! match Pixels::new(WIDTH, HEIGHT, surface_texture) {

The link that I provided earlier already does this without introducing an unnecessary named lifetime.

parasyte avatar Apr 01 '25 00:04 parasyte

my bad, didn't see the link!

SRabia avatar Apr 01 '25 14:04 SRabia