diff --git a/examples/invaders/main.rs b/examples/invaders/main.rs index 7312fd4..76935b8 100644 --- a/examples/invaders/main.rs +++ b/examples/invaders/main.rs @@ -42,7 +42,7 @@ fn main() -> Result<(), Error> { }; let surface_texture = SurfaceTexture::new(width, height, surface); - let mut pixels = Pixels::new(224, 256, surface_texture)?; + let mut pixels = Pixels::new(SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32, surface_texture)?; let mut invaders = World::new(debug); let mut time = Instant::now(); let mut controls = Controls::default(); @@ -54,7 +54,8 @@ fn main() -> Result<(), Error> { event: WindowEvent::RedrawRequested, .. } => { - pixels.render(invaders.draw()); + invaders.draw(pixels.get_frame()); + pixels.render(); } _ => (), } diff --git a/simple-invaders/src/lib.rs b/simple-invaders/src/lib.rs index bcb0afd..d92a55c 100644 --- a/simple-invaders/src/lib.rs +++ b/simple-invaders/src/lib.rs @@ -48,7 +48,6 @@ pub struct World { collision: Collision, score: u32, assets: Assets, - screen: Vec, dt: Duration, gameover: bool, random: OsRng, @@ -149,10 +148,6 @@ impl World { let collision = Collision::default(); let score = 0; - // Create a screen with the correct size - let mut screen = Vec::new(); - screen.resize_with(SCREEN_WIDTH * SCREEN_HEIGHT * 4, Default::default); - let dt = Duration::default(); let gameover = false; let random = OsRng; @@ -166,7 +161,6 @@ impl World { collision, score, assets, - screen, dt, gameover, random, @@ -261,47 +255,45 @@ impl World { /// Draw the internal state to the screen. /// /// Calling this method more than once without an `update` call between is a no-op. - pub fn draw(&mut self) -> &[u8] { + pub fn draw(&mut self, screen: &mut [u8]) { // Clear the screen - self.clear(); + clear(screen); // Draw the invaders for row in &self.invaders.grid { for col in row { if let Some(invader) = col { - blit(&mut self.screen, &invader.pos, &invader.sprite); + blit(screen, &invader.pos, &invader.sprite); } } } // Draw the shields for shield in &self.shields { - blit(&mut self.screen, &shield.pos, &shield.sprite); + blit(screen, &shield.pos, &shield.sprite); } // Draw the player - blit(&mut self.screen, &self.player.pos, &self.player.sprite); + blit(screen, &self.player.pos, &self.player.sprite); // Draw the bullet if let Some(bullet) = &self.bullet { - blit(&mut self.screen, &bullet.pos, &bullet.sprite); + blit(screen, &bullet.pos, &bullet.sprite); } // Draw lasers for laser in self.lasers.iter() { - blit(&mut self.screen, &laser.pos, &laser.sprite); + blit(screen, &laser.pos, &laser.sprite); } // Draw debug information if self.debug { - debug::draw_invaders(&mut self.screen, &self.invaders, &self.collision); - debug::draw_bullet(&mut self.screen, self.bullet.as_ref()); - debug::draw_lasers(&mut self.screen, &self.lasers); - debug::draw_player(&mut self.screen, &self.player, &self.collision); - debug::draw_shields(&mut self.screen, &self.shields, &self.collision); + debug::draw_invaders(screen, &self.invaders, &self.collision); + debug::draw_bullet(screen, self.bullet.as_ref()); + debug::draw_lasers(screen, &self.lasers); + debug::draw_player(screen, &self.player, &self.collision); + debug::draw_shields(screen, &self.shields, &self.collision); } - - &self.screen } fn step_invaders(&mut self) { @@ -406,13 +398,6 @@ impl World { }); } } - - /// Clear the screen - fn clear(&mut self) { - for (i, byte) in self.screen.iter_mut().enumerate() { - *byte = if i % 4 == 3 { 255 } else { 0 }; - } - } } impl Default for World { @@ -522,6 +507,13 @@ impl Default for Bounds { } } +/// Clear the screen +fn clear(screen: &mut [u8]) { + for (i, byte) in screen.iter_mut().enumerate() { + *byte = if i % 4 == 3 { 255 } else { 0 }; + } +} + /// Create a grid of invaders. fn make_invader_grid(assets: &Assets) -> Vec>> { use Frame::*; diff --git a/src/lib.rs b/src/lib.rs index 2b361c2..4e42ca0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,7 @@ pub struct Pixels { texture: wgpu::Texture, texture_extent: wgpu::Extent3d, texture_format_size: u32, + pixels: Vec, } /// A builder to help create customized pixel buffers. @@ -124,7 +125,7 @@ impl Pixels { /// # use pixels::Pixels; /// # let surface = wgpu::Surface::create(&pixels_mocks::RWH); /// # let surface_texture = pixels::SurfaceTexture::new(1024, 768, surface); - /// let fb = Pixels::new(320, 240, surface_texture)?; + /// let mut pixels = Pixels::new(320, 240, surface_texture)?; /// # Ok::<(), pixels::Error>(()) /// ``` /// @@ -169,12 +170,7 @@ impl Pixels { /// Draw this pixel buffer to the configured [`SurfaceTexture`]. /// /// This executes all render passes in sequence. See [`RenderPass`]. - /// - /// # Arguments - /// - /// * `texels` - Byte slice of texture pixels (AKA texels) to draw. The texture format can be - /// configured with [`PixelsBuilder`]. - pub fn render(&mut self, texels: &[u8]) { + pub fn render(&mut self) { // TODO: Center frame buffer in surface let frame = self.swap_chain.get_next_texture(); let mut encoder = self @@ -184,8 +180,8 @@ impl Pixels { // Update the pixel buffer texture view let buffer = self .device - .create_buffer_mapped(texels.len(), wgpu::BufferUsage::COPY_SRC) - .fill_from_slice(texels); + .create_buffer_mapped(self.pixels.len(), wgpu::BufferUsage::COPY_SRC) + .fill_from_slice(&self.pixels); encoder.copy_buffer_to_texture( wgpu::BufferCopyView { buffer: &buffer, @@ -214,6 +210,26 @@ impl Pixels { self.queue.borrow_mut().submit(&[encoder.finish()]); } + + /// Get a mutable byte slice for the pixel buffer. The buffer is _not_ cleared for you; it will + /// retain the previous frame's contents until you clear it yourself. + /// + /// # Example + /// + /// ```no_run + /// # use pixels::Pixels; + /// # let surface = wgpu::Surface::create(&pixels_mocks::RWH); + /// # let surface_texture = pixels::SurfaceTexture::new(1024, 768, surface); + /// let mut pixels = Pixels::new(320, 240, surface_texture)?; + /// let frame = pixels.get_frame(); + /// for pixel in frame { + /// *pixel = 0; + /// } + /// # Ok::<(), pixels::Error>(()) + /// ``` + pub fn get_frame(&mut self) -> &mut [u8] { + &mut self.pixels + } } impl PixelsBuilder { @@ -235,7 +251,7 @@ impl PixelsBuilder { /// # fn render_pass(&self, _: &mut wgpu::CommandEncoder, _: &wgpu::TextureView) {} /// } /// - /// let fb = PixelsBuilder::new(256, 240, surface_texture) + /// let mut pixels = PixelsBuilder::new(256, 240, surface_texture) /// .pixel_aspect_ratio(8.0 / 7.0) /// .add_render_pass(|device, queue, texture| { /// // Create reources for MyRenderPass here @@ -391,6 +407,11 @@ impl PixelsBuilder { let texture_view = texture.create_default_view(); let texture_format_size = get_texture_format_size(self.texture_format); + // Create the pixel buffer + let capacity = (width * height * texture_format_size) as usize; + let mut pixels = Vec::with_capacity(capacity); + pixels.resize_with(capacity, Default::default); + // Create swap chain let surface_texture = self.surface_texture; let swap_chain = device.create_swap_chain( @@ -426,6 +447,7 @@ impl PixelsBuilder { texture, texture_extent, texture_format_size, + pixels, }) } }