/ let-engine / examples / client / texture.rs
texture.rs
  1  //! Texture test featuring my cat Rusty.
  2  //!
  3  //! Press space to bitshift random pixels to make an interesting effect.
  4  
  5  use glam::vec2;
  6  use gpu::{VulkanTypes, texture::TextureId};
  7  use image::ImageBuffer;
  8  use let_engine::prelude::*;
  9  
 10  static RES: UVec2 = uvec2(1122, 821);
 11  
 12  fn main() {
 13      // Log messages
 14      simple_logger::SimpleLogger::new()
 15          .with_level(log::LevelFilter::Debug)
 16          .init()
 17          .unwrap();
 18  
 19      // First you make a builder containing the description of the window.
 20  
 21      let window_builder = WindowBuilder::new()
 22          .inner_size(RES)
 23          .title(env!("CARGO_CRATE_NAME"));
 24  
 25      let_engine::start(
 26          EngineSettings::default()
 27              .window(window_builder)
 28              .gpu(gpu::GpuSettings {
 29                  present_mode: gpu::PresentMode::Fifo,
 30                  ..Default::default()
 31              }),
 32          Game::new,
 33      )
 34      .unwrap();
 35  }
 36  
 37  /// Makes a game struct containing
 38  struct Game {
 39      texture: TextureId,
 40  }
 41  
 42  impl Game {
 43      /// Constructor for this scene.
 44      pub fn new(context: EngineContext) -> Result<Self, ()> {
 45          context.scene.root_view_mut().scaling = CameraScaling::Expand;
 46  
 47          // A square model with textured vertices.
 48          let model = context
 49              .gpu
 50              .load_model(&Model::new_indexed(
 51                  vec![
 52                      tvert(1.0, 1.0, 1.0, 1.0),
 53                      tvert(1.0, -1.0, 1.0, 0.0),
 54                      tvert(-1.0, 1.0, 0.0, 1.0),
 55                      tvert(-1.0, -1.0, 0.0, 0.0),
 56                  ],
 57                  vec![0, 1, 2, 2, 1, 3],
 58                  BufferAccess::Fixed,
 59              ))
 60              .unwrap();
 61  
 62          let texture = Texture::from_bytes(
 63              include_bytes!("../assets/example-texture.png").to_vec(),
 64              ImageFormat::Png,
 65              TextureSettingsBuilder::default()
 66                  .format(Format::Rgba8Unorm)
 67                  .access_pattern(BufferAccess::RingBuffer { buffers: 2 }) // `BufferAccess::Pinned` to make the texture mutable for each frame
 68                  .unwrap()
 69                  .build()
 70                  .unwrap(),
 71          )
 72          .unwrap();
 73  
 74          // Load the texture to the GPU
 75          let gpu_texture = context.gpu.load_texture(&texture).unwrap();
 76  
 77          let default_material = context
 78              .gpu
 79              .load_material::<TVert>(&Material::default_textured())
 80              .unwrap();
 81  
 82          let color_buffer = context
 83              .gpu
 84              .load_buffer(&Buffer::from_data(
 85                  buffer::BufferUsage::Uniform,
 86                  BufferAccess::Fixed,
 87                  Color::WHITE,
 88              ))
 89              .unwrap();
 90  
 91          let dim = texture.dimensions().extent();
 92  
 93          let appearance = AppearanceBuilder::<VulkanTypes, TVert>::default()
 94              .model(model)
 95              .material(default_material)
 96              .transform(Transform::with_size_2d(vec2(dim[0] as f32, dim[1] as f32)))
 97              .descriptors(&[
 98                  (Location::new(0, 0), Descriptor::Mvp),
 99                  (Location::new(1, 0), Descriptor::buffer(color_buffer)),
100                  (Location::new(2, 0), Descriptor::Texture(gpu_texture)),
101              ])
102              .build(&context.gpu)
103              .unwrap();
104  
105          let object = ObjectBuilder::with_appearance(appearance);
106  
107          // Initializes the object to the layer
108          context
109              .scene
110              .add_object(context.scene.root_layer_id(), object)
111              .unwrap();
112  
113          Ok(Self {
114              texture: gpu_texture,
115          })
116      }
117  }
118  
119  /// Implement the Game trait into the Game struct.
120  impl let_engine::Game for Game {
121      // Exit when the X button on the window is pressed.
122      fn window(&mut self, context: EngineContext, event: events::WindowEvent) -> Result<(), ()> {
123          if let WindowEvent::CloseRequested = event {
124              context.exit();
125          }
126          Ok(())
127      }
128  
129      fn input(&mut self, context: EngineContext, event: events::InputEvent) -> Result<(), ()> {
130          if let InputEvent::KeyboardInput { input } = event
131              && let ElementState::Pressed = input.state
132          {
133              match input.key {
134                  // Exit when the escape key is pressed.
135                  Key::Named(NamedKey::Escape) => {
136                      context.exit();
137                  }
138                  // Edit texture when space is pressed.
139                  Key::Named(NamedKey::Space) => {
140                      // Write data to the texture
141                      context.gpu[self.texture]
142                          .write_data(|data| {
143                              let mut buffer: ImageBuffer<image::Rgba<u8>, &mut [u8]> =
144                                  ImageBuffer::from_raw(RES.x, RES.y, data).unwrap();
145  
146                              const PIXELS: usize = 100000;
147  
148                              log::info!("Shifting {PIXELS} pixels");
149                              for _ in 0..PIXELS {
150                                  let c = uvec2(
151                                      rand::random_range(0..RES.x),
152                                      rand::random_range(0..RES.y),
153                                  );
154  
155                                  let pixel = buffer.get_pixel_mut(c.x, c.y);
156                                  pixel.0[0..2].iter_mut().for_each(|rgb: &mut u8| {
157                                      *rgb = rgb.rotate_left(1);
158                                  });
159                              }
160                          })
161                          .unwrap();
162                  }
163                  _ => (),
164              }
165          }
166          Ok(())
167      }
168  }