summaryrefslogtreecommitdiffstats
path: root/examples/integration
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-02-09 05:32:56 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-02-09 05:32:56 +0100
commit4d7979aa77e481a5f8ff2f22bc2665912617fc04 (patch)
tree767519bfaf64a8abf3b091d3ff7d66cc44c4d4ad /examples/integration
parenta244f9324305a2393da95be76085cba6a29b4b27 (diff)
downloadiced-4d7979aa77e481a5f8ff2f22bc2665912617fc04.tar.gz
iced-4d7979aa77e481a5f8ff2f22bc2665912617fc04.tar.bz2
iced-4d7979aa77e481a5f8ff2f22bc2665912617fc04.zip
Add `integration` example
It showcases how to integrate iced in an existing graphical application.
Diffstat (limited to 'examples/integration')
-rw-r--r--examples/integration/Cargo.toml11
-rw-r--r--examples/integration/src/controls.rs102
-rw-r--r--examples/integration/src/main.rs204
-rw-r--r--examples/integration/src/scene.rs119
-rw-r--r--examples/integration/src/shader/frag.spvbin0 -> 352 bytes
-rw-r--r--examples/integration/src/shader/vert.spvbin0 -> 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.spv
new file mode 100644
index 00000000..9d6807c9
--- /dev/null
+++ b/examples/integration/src/shader/frag.spv
Binary files differ
diff --git a/examples/integration/src/shader/vert.spv b/examples/integration/src/shader/vert.spv
new file mode 100644
index 00000000..0cabc9c0
--- /dev/null
+++ b/examples/integration/src/shader/vert.spv
Binary files differ