diff options
| author | 2020-02-10 19:49:08 +0100 | |
|---|---|---|
| committer | 2020-02-10 19:49:08 +0100 | |
| commit | 5d16f431b3088189579cf096b3abf89578cc73f6 (patch) | |
| tree | c7efea00fabd87133a59760e902548d39822a844 /examples/integration | |
| parent | 95880ca74bddb6a23774621ef766b91956d40a61 (diff) | |
| parent | 4337daddb2a02a2c60dfc5beb896e3059588312a (diff) | |
| download | iced-5d16f431b3088189579cf096b3abf89578cc73f6.tar.gz iced-5d16f431b3088189579cf096b3abf89578cc73f6.tar.bz2 iced-5d16f431b3088189579cf096b3abf89578cc73f6.zip | |
Merge pull request #183 from hecrj/feature/wgpu-integration
Integration with existing `wgpu` projects
Diffstat (limited to '')
| -rw-r--r-- | examples/integration/Cargo.toml | 11 | ||||
| -rw-r--r-- | examples/integration/src/controls.rs | 102 | ||||
| -rw-r--r-- | examples/integration/src/main.rs | 204 | ||||
| -rw-r--r-- | examples/integration/src/scene.rs | 119 | ||||
| -rw-r--r-- | examples/integration/src/shader/frag.spv | bin | 0 -> 352 bytes | |||
| -rw-r--r-- | examples/integration/src/shader/vert.spv | bin | 0 -> 904 bytes | 
6 files changed, 436 insertions, 0 deletions
| diff --git a/examples/integration/Cargo.toml b/examples/integration/Cargo.toml new file mode 100644 index 00000000..afc2c791 --- /dev/null +++ b/examples/integration/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "integration" +version = "0.1.0" +authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +iced_winit = { path = "../../winit" } +iced_wgpu = { path = "../../wgpu" } +env_logger = "0.7" diff --git a/examples/integration/src/controls.rs b/examples/integration/src/controls.rs new file mode 100644 index 00000000..0457a058 --- /dev/null +++ b/examples/integration/src/controls.rs @@ -0,0 +1,102 @@ +use crate::Scene; + +use iced_wgpu::Renderer; +use iced_winit::{ +    slider, Align, Color, Column, Element, Length, Row, Slider, Text, +}; + +pub struct Controls { +    sliders: [slider::State; 3], +} + +#[derive(Debug)] +pub enum Message { +    BackgroundColorChanged(Color), +} + +impl Controls { +    pub fn new() -> Controls { +        Controls { +            sliders: Default::default(), +        } +    } + +    pub fn update(&self, message: Message, scene: &mut Scene) { +        match message { +            Message::BackgroundColorChanged(color) => { +                scene.background_color = color; +            } +        } +    } + +    pub fn view<'a>( +        &'a mut self, +        scene: &Scene, +    ) -> Element<'a, Message, Renderer> { +        let [r, g, b] = &mut self.sliders; +        let background_color = scene.background_color; + +        let sliders = Row::new() +            .width(Length::Units(500)) +            .spacing(20) +            .push(Slider::new( +                r, +                0.0..=1.0, +                scene.background_color.r, +                move |r| { +                    Message::BackgroundColorChanged(Color { +                        r, +                        ..background_color +                    }) +                }, +            )) +            .push(Slider::new( +                g, +                0.0..=1.0, +                scene.background_color.g, +                move |g| { +                    Message::BackgroundColorChanged(Color { +                        g, +                        ..background_color +                    }) +                }, +            )) +            .push(Slider::new( +                b, +                0.0..=1.0, +                scene.background_color.b, +                move |b| { +                    Message::BackgroundColorChanged(Color { +                        b, +                        ..background_color +                    }) +                }, +            )); + +        Row::new() +            .width(Length::Fill) +            .height(Length::Fill) +            .align_items(Align::End) +            .push( +                Column::new() +                    .width(Length::Fill) +                    .align_items(Align::End) +                    .push( +                        Column::new() +                            .padding(10) +                            .spacing(10) +                            .push( +                                Text::new("Background color") +                                    .color(Color::WHITE), +                            ) +                            .push(sliders) +                            .push( +                                Text::new(format!("{:?}", background_color)) +                                    .size(14) +                                    .color(Color::WHITE), +                            ), +                    ), +            ) +            .into() +    } +} diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs new file mode 100644 index 00000000..ed36f736 --- /dev/null +++ b/examples/integration/src/main.rs @@ -0,0 +1,204 @@ +mod controls; +mod scene; + +use controls::Controls; +use scene::Scene; + +use iced_wgpu::{ +    wgpu, window::SwapChain, Primitive, Renderer, Settings, Target, +}; +use iced_winit::{winit, Cache, Clipboard, MouseCursor, Size, UserInterface}; + +use winit::{ +    event::{DeviceEvent, Event, ModifiersState, WindowEvent}, +    event_loop::{ControlFlow, EventLoop}, +}; + +pub fn main() { +    env_logger::init(); + +    // Initialize winit +    let event_loop = EventLoop::new(); +    let window = winit::window::Window::new(&event_loop).unwrap(); +    let mut logical_size = +        window.inner_size().to_logical(window.scale_factor()); +    let mut modifiers = ModifiersState::default(); + +    // Initialize WGPU +    let adapter = wgpu::Adapter::request(&wgpu::RequestAdapterOptions { +        power_preference: wgpu::PowerPreference::Default, +        backends: wgpu::BackendBit::PRIMARY, +    }) +    .expect("Request adapter"); + +    let (mut device, mut queue) = +        adapter.request_device(&wgpu::DeviceDescriptor { +            extensions: wgpu::Extensions { +                anisotropic_filtering: false, +            }, +            limits: wgpu::Limits::default(), +        }); + +    let surface = wgpu::Surface::create(&window); + +    let mut swap_chain = { +        let size = window.inner_size(); + +        SwapChain::new(&device, &surface, size.width, size.height) +    }; +    let mut resized = false; + +    // Initialize iced +    let mut events = Vec::new(); +    let mut cache = Some(Cache::default()); +    let mut renderer = Renderer::new(&mut device, Settings::default()); +    let mut output = (Primitive::None, MouseCursor::OutOfBounds); +    let clipboard = Clipboard::new(&window); + +    // Initialize scene and GUI controls +    let mut scene = Scene::new(&device); +    let mut controls = Controls::new(); + +    // Run event loop +    event_loop.run(move |event, _, control_flow| { +        // You should change this if you want to render continuosly +        *control_flow = ControlFlow::Wait; + +        match event { +            Event::DeviceEvent { +                event: DeviceEvent::ModifiersChanged(new_modifiers), +                .. +            } => { +                modifiers = new_modifiers; +            } +            Event::WindowEvent { event, .. } => { +                match event { +                    WindowEvent::Resized(new_size) => { +                        logical_size = +                            new_size.to_logical(window.scale_factor()); +                        resized = true; +                    } +                    WindowEvent::CloseRequested => { +                        *control_flow = ControlFlow::Exit; +                    } +                    _ => {} +                } + +                // Map window event to iced event +                if let Some(event) = iced_winit::conversion::window_event( +                    event, +                    window.scale_factor(), +                    modifiers, +                ) { +                    events.push(event); +                } +            } +            Event::MainEventsCleared => { +                // If no relevant events happened, we can simply skip this +                if events.is_empty() { +                    return; +                } + +                // We need to: +                // 1. Process events of our user interface. +                // 2. Update state as a result of any interaction. +                // 3. Generate a new output for our renderer. + +                // First, we build our user interface. +                let mut user_interface = UserInterface::build( +                    controls.view(&scene), +                    Size::new(logical_size.width, logical_size.height), +                    cache.take().unwrap(), +                    &mut renderer, +                ); + +                // Then, we process the events, obtaining messages in return. +                let messages = user_interface.update( +                    events.drain(..), +                    clipboard.as_ref().map(|c| c as _), +                    &renderer, +                ); + +                let user_interface = if messages.is_empty() { +                    // If there are no messages, no interactions we care about have +                    // happened. We can simply leave our user interface as it is. +                    user_interface +                } else { +                    // If there are messages, we need to update our state +                    // accordingly and rebuild our user interface. +                    // We can only do this if we drop our user interface first +                    // by turning it into its cache. +                    cache = Some(user_interface.into_cache()); + +                    // In this example, `Controls` is the only part that cares +                    // about messages, so updating our state is pretty +                    // straightforward. +                    for message in messages { +                        controls.update(message, &mut scene); +                    } + +                    // Once the state has been changed, we rebuild our updated +                    // user interface. +                    UserInterface::build( +                        controls.view(&scene), +                        Size::new(logical_size.width, logical_size.height), +                        cache.take().unwrap(), +                        &mut renderer, +                    ) +                }; + +                // Finally, we just need to draw a new output for our renderer, +                output = user_interface.draw(&mut renderer); + +                // update our cache, +                cache = Some(user_interface.into_cache()); + +                // and request a redraw +                window.request_redraw(); +            } +            Event::RedrawRequested(_) => { +                if resized { +                    let size = window.inner_size(); + +                    swap_chain = SwapChain::new( +                        &device, +                        &surface, +                        size.width, +                        size.height, +                    ); +                } + +                let (frame, viewport) = swap_chain.next_frame(); + +                let mut encoder = device.create_command_encoder( +                    &wgpu::CommandEncoderDescriptor { todo: 0 }, +                ); + +                // We draw the scene first +                scene.draw(&mut encoder, &frame.view); + +                // And then iced on top +                let mouse_cursor = renderer.draw( +                    &mut device, +                    &mut encoder, +                    Target { +                        texture: &frame.view, +                        viewport, +                    }, +                    &output, +                    window.scale_factor(), +                    &["Some debug information!"], +                ); + +                // Then we submit the work +                queue.submit(&[encoder.finish()]); + +                // And update the mouse cursor +                window.set_cursor_icon(iced_winit::conversion::mouse_cursor( +                    mouse_cursor, +                )); +            } +            _ => {} +        } +    }) +} diff --git a/examples/integration/src/scene.rs b/examples/integration/src/scene.rs new file mode 100644 index 00000000..efb1921b --- /dev/null +++ b/examples/integration/src/scene.rs @@ -0,0 +1,119 @@ +use iced_wgpu::wgpu; +use iced_winit::Color; + +pub struct Scene { +    pub background_color: Color, +    pipeline: wgpu::RenderPipeline, +    bind_group: wgpu::BindGroup, +} + +impl Scene { +    pub fn new(device: &wgpu::Device) -> Scene { +        let (pipeline, bind_group) = build_pipeline(device); + +        Scene { +            background_color: Color::BLACK, +            pipeline, +            bind_group, +        } +    } + +    pub fn draw( +        &self, +        encoder: &mut wgpu::CommandEncoder, +        target: &wgpu::TextureView, +    ) { +        let mut rpass = +            encoder.begin_render_pass(&wgpu::RenderPassDescriptor { +                color_attachments: &[ +                    wgpu::RenderPassColorAttachmentDescriptor { +                        attachment: target, +                        resolve_target: None, +                        load_op: wgpu::LoadOp::Clear, +                        store_op: wgpu::StoreOp::Store, +                        clear_color: { +                            let [r, g, b, a] = +                                self.background_color.into_linear(); + +                            wgpu::Color { +                                r: r as f64, +                                g: g as f64, +                                b: b as f64, +                                a: a as f64, +                            } +                        }, +                    }, +                ], +                depth_stencil_attachment: None, +            }); + +        rpass.set_pipeline(&self.pipeline); +        rpass.set_bind_group(0, &self.bind_group, &[]); +        rpass.draw(0..3, 0..1); +    } +} + +fn build_pipeline( +    device: &wgpu::Device, +) -> (wgpu::RenderPipeline, wgpu::BindGroup) { +    let vs = include_bytes!("shader/vert.spv"); +    let fs = include_bytes!("shader/frag.spv"); + +    let vs_module = device.create_shader_module( +        &wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap(), +    ); + +    let fs_module = device.create_shader_module( +        &wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap(), +    ); + +    let bind_group_layout = +        device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { +            bindings: &[], +        }); + +    let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { +        layout: &bind_group_layout, +        bindings: &[], +    }); + +    let pipeline_layout = +        device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { +            bind_group_layouts: &[&bind_group_layout], +        }); + +    let pipeline = +        device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { +            layout: &pipeline_layout, +            vertex_stage: wgpu::ProgrammableStageDescriptor { +                module: &vs_module, +                entry_point: "main", +            }, +            fragment_stage: Some(wgpu::ProgrammableStageDescriptor { +                module: &fs_module, +                entry_point: "main", +            }), +            rasterization_state: Some(wgpu::RasterizationStateDescriptor { +                front_face: wgpu::FrontFace::Ccw, +                cull_mode: wgpu::CullMode::None, +                depth_bias: 0, +                depth_bias_slope_scale: 0.0, +                depth_bias_clamp: 0.0, +            }), +            primitive_topology: wgpu::PrimitiveTopology::TriangleList, +            color_states: &[wgpu::ColorStateDescriptor { +                format: wgpu::TextureFormat::Bgra8UnormSrgb, +                color_blend: wgpu::BlendDescriptor::REPLACE, +                alpha_blend: wgpu::BlendDescriptor::REPLACE, +                write_mask: wgpu::ColorWrite::ALL, +            }], +            depth_stencil_state: None, +            index_format: wgpu::IndexFormat::Uint16, +            vertex_buffers: &[], +            sample_count: 1, +            sample_mask: !0, +            alpha_to_coverage_enabled: false, +        }); + +    (pipeline, bind_group) +} diff --git a/examples/integration/src/shader/frag.spv b/examples/integration/src/shader/frag.spvBinary files differ new file mode 100644 index 00000000..9d6807c9 --- /dev/null +++ b/examples/integration/src/shader/frag.spv diff --git a/examples/integration/src/shader/vert.spv b/examples/integration/src/shader/vert.spvBinary files differ new file mode 100644 index 00000000..0cabc9c0 --- /dev/null +++ b/examples/integration/src/shader/vert.spv | 
