-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for custom shader widget for iced_wgpu backend.
- Loading branch information
1 parent
9245423
commit 8b25fce
Showing
37 changed files
with
2,131 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "custom_shader" | ||
version = "0.1.0" | ||
authors = ["Bingus <[email protected]>"] | ||
edition = "2021" | ||
|
||
[dependencies] | ||
iced = { path = "../..", features = ["debug", "advanced"]} | ||
image = { version = "0.24.6"} | ||
wgpu = "0.17" | ||
bytemuck = { version = "1.13.1" } | ||
glam = { version = "0.24.0", features = ["bytemuck"] } | ||
rand = "0.8.5" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
use glam::{mat4, vec3, vec4}; | ||
use iced::Rectangle; | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct Camera { | ||
eye: glam::Vec3, | ||
target: glam::Vec3, | ||
up: glam::Vec3, | ||
fov_y: f32, | ||
near: f32, | ||
far: f32, | ||
} | ||
|
||
impl Default for Camera { | ||
fn default() -> Self { | ||
Self { | ||
eye: vec3(0.0, 2.0, 3.0), | ||
target: glam::Vec3::ZERO, | ||
up: glam::Vec3::Y, | ||
fov_y: 45.0, | ||
near: 0.1, | ||
far: 100.0, | ||
} | ||
} | ||
} | ||
|
||
pub const OPENGL_TO_WGPU_MATRIX: glam::Mat4 = mat4( | ||
vec4(1.0, 0.0, 0.0, 0.0), | ||
vec4(0.0, 1.0, 0.0, 0.0), | ||
vec4(0.0, 0.0, 0.5, 0.0), | ||
vec4(0.0, 0.0, 0.5, 1.0), | ||
); | ||
|
||
impl Camera { | ||
pub fn build_view_proj_matrix(&self, bounds: Rectangle) -> glam::Mat4 { | ||
//TODO looks distorted without padding; base on surface texture size instead? | ||
let aspect_ratio = bounds.width / (bounds.height + 150.0); | ||
|
||
let view = glam::Mat4::look_at_rh(self.eye, self.target, self.up); | ||
let proj = glam::Mat4::perspective_rh( | ||
self.fov_y, | ||
aspect_ratio, | ||
self.near, | ||
self.far, | ||
); | ||
|
||
OPENGL_TO_WGPU_MATRIX * proj * view | ||
} | ||
|
||
pub fn position(&self) -> glam::Vec4 { | ||
glam::Vec4::from((self.eye, 0.0)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
use crate::camera::Camera; | ||
use crate::primitive; | ||
use crate::primitive::cube::Cube; | ||
use glam::Vec3; | ||
use iced::widget::shader; | ||
use iced::{mouse, Color, Rectangle}; | ||
use rand::Rng; | ||
use std::cmp::Ordering; | ||
use std::iter; | ||
use std::time::Duration; | ||
|
||
pub const MAX: u32 = 500; | ||
|
||
#[derive(Clone)] | ||
pub struct Cubes { | ||
pub size: f32, | ||
pub cubes: Vec<Cube>, | ||
pub camera: Camera, | ||
pub show_depth_buffer: bool, | ||
pub light_color: Color, | ||
} | ||
|
||
impl Cubes { | ||
pub fn new() -> Self { | ||
let mut cubes = Self { | ||
size: 0.2, | ||
cubes: vec![], | ||
camera: Camera::default(), | ||
show_depth_buffer: false, | ||
light_color: Color::WHITE, | ||
}; | ||
|
||
cubes.adjust_num_cubes(MAX); | ||
|
||
cubes | ||
} | ||
|
||
pub fn update(&mut self, time: Duration) { | ||
for cube in self.cubes.iter_mut() { | ||
cube.update(self.size, time.as_secs_f32()); | ||
} | ||
} | ||
|
||
pub fn adjust_num_cubes(&mut self, num_cubes: u32) { | ||
let curr_cubes = self.cubes.len() as u32; | ||
|
||
match num_cubes.cmp(&curr_cubes) { | ||
Ordering::Greater => { | ||
// spawn | ||
let cubes_2_spawn = (num_cubes - 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 - num_cubes; | ||
let new_len = self.cubes.len() - cubes_2_cut as usize; | ||
self.cubes.truncate(new_len); | ||
} | ||
_ => {} | ||
} | ||
} | ||
} | ||
|
||
impl<Message> shader::Program<Message> for Cubes { | ||
type State = (); | ||
type Primitive = primitive::Primitive; | ||
|
||
fn draw( | ||
&self, | ||
_state: &Self::State, | ||
_cursor: mouse::Cursor, | ||
bounds: Rectangle, | ||
) -> Self::Primitive { | ||
primitive::Primitive::new( | ||
&self.cubes, | ||
&self.camera, | ||
bounds, | ||
self.show_depth_buffer, | ||
self.light_color, | ||
) | ||
} | ||
} | ||
|
||
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), | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
mod camera; | ||
mod cubes; | ||
mod pipeline; | ||
mod primitive; | ||
|
||
use crate::cubes::Cubes; | ||
use iced::widget::{ | ||
checkbox, column, container, row, slider, text, vertical_space, Shader, | ||
}; | ||
use iced::{ | ||
executor, window, Alignment, Application, Color, Command, Element, Length, | ||
Renderer, Subscription, Theme, | ||
}; | ||
use std::time::Instant; | ||
|
||
fn main() -> iced::Result { | ||
IcedCubes::run(iced::Settings::default()) | ||
} | ||
|
||
struct IcedCubes { | ||
start: Instant, | ||
cubes: Cubes, | ||
num_cubes_slider: u32, | ||
} | ||
|
||
impl Default for IcedCubes { | ||
fn default() -> Self { | ||
Self { | ||
start: Instant::now(), | ||
cubes: Cubes::new(), | ||
num_cubes_slider: cubes::MAX, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
enum Message { | ||
CubeAmountChanged(u32), | ||
CubeSizeChanged(f32), | ||
Tick(Instant), | ||
ShowDepthBuffer(bool), | ||
LightColorChanged(Color), | ||
} | ||
|
||
impl Application for IcedCubes { | ||
type Executor = executor::Default; | ||
type Message = Message; | ||
type Theme = Theme; | ||
type Flags = (); | ||
|
||
fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) { | ||
(IcedCubes::default(), Command::none()) | ||
} | ||
|
||
fn title(&self) -> String { | ||
"Iced Cubes".to_string() | ||
} | ||
|
||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> { | ||
match message { | ||
Message::CubeAmountChanged(num) => { | ||
self.num_cubes_slider = num; | ||
self.cubes.adjust_num_cubes(num); | ||
} | ||
Message::CubeSizeChanged(size) => { | ||
self.cubes.size = size; | ||
} | ||
Message::Tick(time) => { | ||
self.cubes.update(time - self.start); | ||
} | ||
Message::ShowDepthBuffer(show) => { | ||
self.cubes.show_depth_buffer = show; | ||
} | ||
Message::LightColorChanged(color) => { | ||
self.cubes.light_color = color; | ||
} | ||
} | ||
|
||
Command::none() | ||
} | ||
|
||
fn view(&self) -> Element<'_, Self::Message, Renderer<Self::Theme>> { | ||
let top_controls = row![ | ||
control( | ||
"Amount", | ||
slider( | ||
1..=cubes::MAX, | ||
self.num_cubes_slider, | ||
Message::CubeAmountChanged | ||
) | ||
.width(100) | ||
), | ||
control( | ||
"Size", | ||
slider(0.1..=0.25, self.cubes.size, Message::CubeSizeChanged) | ||
.step(0.01) | ||
.width(100), | ||
), | ||
checkbox( | ||
"Show Depth Buffer", | ||
self.cubes.show_depth_buffer, | ||
Message::ShowDepthBuffer | ||
), | ||
] | ||
.spacing(40); | ||
|
||
let bottom_controls = row![ | ||
control( | ||
"R", | ||
slider(0.0..=1.0, self.cubes.light_color.r, move |r| { | ||
Message::LightColorChanged(Color { | ||
r, | ||
..self.cubes.light_color | ||
}) | ||
}) | ||
.step(0.01) | ||
.width(100) | ||
), | ||
control( | ||
"G", | ||
slider(0.0..=1.0, self.cubes.light_color.g, move |g| { | ||
Message::LightColorChanged(Color { | ||
g, | ||
..self.cubes.light_color | ||
}) | ||
}) | ||
.step(0.01) | ||
.width(100) | ||
), | ||
control( | ||
"B", | ||
slider(0.0..=1.0, self.cubes.light_color.b, move |b| { | ||
Message::LightColorChanged(Color { | ||
b, | ||
..self.cubes.light_color | ||
}) | ||
}) | ||
.step(0.01) | ||
.width(100) | ||
) | ||
] | ||
.spacing(40); | ||
|
||
let controls = column![top_controls, bottom_controls,] | ||
.spacing(10) | ||
.align_items(Alignment::Center); | ||
|
||
let shader = Shader::new(&self.cubes) | ||
.width(Length::Fill) | ||
.height(Length::Fill); | ||
|
||
container( | ||
column![shader, controls, vertical_space(20),] | ||
.spacing(40) | ||
.align_items(Alignment::Center), | ||
) | ||
.width(Length::Fill) | ||
.height(Length::Fill) | ||
.center_x() | ||
.center_y() | ||
.into() | ||
} | ||
|
||
fn subscription(&self) -> Subscription<Self::Message> { | ||
window::frames().map(Message::Tick) | ||
} | ||
} | ||
|
||
fn control<'a>( | ||
label: &'static str, | ||
control: impl Into<Element<'a, Message>>, | ||
) -> Element<'a, Message> { | ||
row![text(label), control.into()].spacing(10).into() | ||
} |
Oops, something went wrong.