summaryrefslogtreecommitdiffstats
path: root/examples/custom_shader/src/scene.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/custom_shader/src/scene.rs')
-rw-r--r--examples/custom_shader/src/scene.rs186
1 files changed, 186 insertions, 0 deletions
diff --git a/examples/custom_shader/src/scene.rs b/examples/custom_shader/src/scene.rs
new file mode 100644
index 00000000..a35efdd9
--- /dev/null
+++ b/examples/custom_shader/src/scene.rs
@@ -0,0 +1,186 @@
+mod camera;
+mod pipeline;
+
+use camera::Camera;
+use pipeline::Pipeline;
+
+use crate::wgpu;
+use pipeline::cube::{self, Cube};
+
+use iced::mouse;
+use iced::time::Duration;
+use iced::widget::shader;
+use iced::{Color, Rectangle, Size};
+
+use glam::Vec3;
+use rand::Rng;
+use std::cmp::Ordering;
+use std::iter;
+
+pub const MAX: u32 = 500;
+
+#[derive(Clone)]
+pub struct Scene {
+ pub size: f32,
+ pub cubes: Vec<Cube>,
+ pub camera: Camera,
+ pub show_depth_buffer: bool,
+ pub light_color: Color,
+}
+
+impl Scene {
+ pub fn new() -> Self {
+ let mut scene = Self {
+ size: 0.2,
+ cubes: vec![],
+ camera: Camera::default(),
+ show_depth_buffer: false,
+ light_color: Color::WHITE,
+ };
+
+ scene.change_amount(MAX);
+
+ scene
+ }
+
+ pub fn update(&mut self, time: Duration) {
+ for cube in self.cubes.iter_mut() {
+ cube.update(self.size, time.as_secs_f32());
+ }
+ }
+
+ pub fn change_amount(&mut self, amount: u32) {
+ let curr_cubes = self.cubes.len() as u32;
+
+ match amount.cmp(&curr_cubes) {
+ Ordering::Greater => {
+ // spawn
+ let cubes_2_spawn = (amount - curr_cubes) as usize;
+
+ let mut cubes = 0;
+ self.cubes.extend(iter::from_fn(|| {
+ if cubes < cubes_2_spawn {
+ cubes += 1;
+ Some(Cube::new(self.size, rnd_origin()))
+ } else {
+ None
+ }
+ }));
+ }
+ Ordering::Less => {
+ // chop
+ let cubes_2_cut = curr_cubes - amount;
+ let new_len = self.cubes.len() - cubes_2_cut as usize;
+ self.cubes.truncate(new_len);
+ }
+ Ordering::Equal => {}
+ }
+ }
+}
+
+impl<Message> shader::Program<Message> for Scene {
+ type State = ();
+ type Primitive = Primitive;
+
+ fn draw(
+ &self,
+ _state: &Self::State,
+ _cursor: mouse::Cursor,
+ bounds: Rectangle,
+ ) -> Self::Primitive {
+ Primitive::new(
+ &self.cubes,
+ &self.camera,
+ bounds,
+ self.show_depth_buffer,
+ self.light_color,
+ )
+ }
+}
+
+/// A collection of `Cube`s that can be rendered.
+#[derive(Debug)]
+pub struct Primitive {
+ cubes: Vec<cube::Raw>,
+ uniforms: pipeline::Uniforms,
+ show_depth_buffer: bool,
+}
+
+impl Primitive {
+ pub fn new(
+ cubes: &[Cube],
+ camera: &Camera,
+ bounds: Rectangle,
+ show_depth_buffer: bool,
+ light_color: Color,
+ ) -> Self {
+ let uniforms = pipeline::Uniforms::new(camera, bounds, light_color);
+
+ Self {
+ cubes: cubes
+ .iter()
+ .map(cube::Raw::from_cube)
+ .collect::<Vec<cube::Raw>>(),
+ uniforms,
+ show_depth_buffer,
+ }
+ }
+}
+
+impl shader::Primitive for Primitive {
+ fn prepare(
+ &self,
+ format: wgpu::TextureFormat,
+ device: &wgpu::Device,
+ queue: &wgpu::Queue,
+ _bounds: Rectangle,
+ target_size: Size<u32>,
+ _scale_factor: f32,
+ storage: &mut shader::Storage,
+ ) {
+ if !storage.has::<Pipeline>() {
+ storage.store(Pipeline::new(device, queue, format, target_size));
+ }
+
+ let pipeline = storage.get_mut::<Pipeline>().unwrap();
+
+ //upload data to GPU
+ pipeline.update(
+ device,
+ queue,
+ target_size,
+ &self.uniforms,
+ self.cubes.len(),
+ &self.cubes,
+ );
+ }
+
+ fn render(
+ &self,
+ storage: &shader::Storage,
+ target: &wgpu::TextureView,
+ _target_size: Size<u32>,
+ viewport: Rectangle<u32>,
+ encoder: &mut wgpu::CommandEncoder,
+ ) {
+ //at this point our pipeline should always be initialized
+ let pipeline = storage.get::<Pipeline>().unwrap();
+
+ //render primitive
+ pipeline.render(
+ target,
+ encoder,
+ viewport,
+ self.cubes.len() as u32,
+ self.show_depth_buffer,
+ );
+ }
+}
+
+fn rnd_origin() -> Vec3 {
+ Vec3::new(
+ rand::thread_rng().gen_range(-4.0..4.0),
+ rand::thread_rng().gen_range(-4.0..4.0),
+ rand::thread_rng().gen_range(-4.0..2.0),
+ )
+}