diff options
| author | 2023-05-11 16:45:08 +0200 | |
|---|---|---|
| committer | 2023-05-11 16:45:08 +0200 | |
| commit | 669f7cc74b2e7918e86a8197916f503f2d3d9b93 (patch) | |
| tree | acb365358235be6ce115b50db9404d890b6e77a6 /examples/integration/src | |
| parent | bc62013b6cde52174bf4c4286939cf170bfa7760 (diff) | |
| parent | 63d3fc6996b848e10e77e6924bfebdf6ba82852e (diff) | |
| download | iced-669f7cc74b2e7918e86a8197916f503f2d3d9b93.tar.gz iced-669f7cc74b2e7918e86a8197916f503f2d3d9b93.tar.bz2 iced-669f7cc74b2e7918e86a8197916f503f2d3d9b93.zip  | |
Merge pull request #1830 from iced-rs/advanced-text
Advanced text
Diffstat (limited to 'examples/integration/src')
| -rw-r--r-- | examples/integration/src/controls.rs | 113 | ||||
| -rw-r--r-- | examples/integration/src/main.rs | 298 | ||||
| -rw-r--r-- | examples/integration/src/scene.rs | 102 | ||||
| -rw-r--r-- | examples/integration/src/shader/frag.wgsl | 4 | ||||
| -rw-r--r-- | examples/integration/src/shader/vert.wgsl | 6 | 
5 files changed, 523 insertions, 0 deletions
diff --git a/examples/integration/src/controls.rs b/examples/integration/src/controls.rs new file mode 100644 index 00000000..14e53ede --- /dev/null +++ b/examples/integration/src/controls.rs @@ -0,0 +1,113 @@ +use iced_wgpu::Renderer; +use iced_widget::{slider, text_input, Column, Row, Text}; +use iced_winit::core::{Alignment, Color, Element, Length}; +use iced_winit::runtime::{Command, Program}; +use iced_winit::style::Theme; + +pub struct Controls { +    background_color: Color, +    text: String, +} + +#[derive(Debug, Clone)] +pub enum Message { +    BackgroundColorChanged(Color), +    TextChanged(String), +} + +impl Controls { +    pub fn new() -> Controls { +        Controls { +            background_color: Color::BLACK, +            text: Default::default(), +        } +    } + +    pub fn background_color(&self) -> Color { +        self.background_color +    } +} + +impl Program for Controls { +    type Renderer = Renderer<Theme>; +    type Message = Message; + +    fn update(&mut self, message: Message) -> Command<Message> { +        match message { +            Message::BackgroundColorChanged(color) => { +                self.background_color = color; +            } +            Message::TextChanged(text) => { +                self.text = text; +            } +        } + +        Command::none() +    } + +    fn view(&self) -> Element<Message, Renderer<Theme>> { +        let background_color = self.background_color; +        let text = &self.text; + +        let sliders = Row::new() +            .width(500) +            .spacing(20) +            .push( +                slider(0.0..=1.0, background_color.r, move |r| { +                    Message::BackgroundColorChanged(Color { +                        r, +                        ..background_color +                    }) +                }) +                .step(0.01), +            ) +            .push( +                slider(0.0..=1.0, background_color.g, move |g| { +                    Message::BackgroundColorChanged(Color { +                        g, +                        ..background_color +                    }) +                }) +                .step(0.01), +            ) +            .push( +                slider(0.0..=1.0, background_color.b, move |b| { +                    Message::BackgroundColorChanged(Color { +                        b, +                        ..background_color +                    }) +                }) +                .step(0.01), +            ); + +        Row::new() +            .width(Length::Fill) +            .height(Length::Fill) +            .align_items(Alignment::End) +            .push( +                Column::new() +                    .width(Length::Fill) +                    .align_items(Alignment::End) +                    .push( +                        Column::new() +                            .padding(10) +                            .spacing(10) +                            .push( +                                Text::new("Background color") +                                    .style(Color::WHITE), +                            ) +                            .push(sliders) +                            .push( +                                Text::new(format!("{background_color:?}")) +                                    .size(14) +                                    .style(Color::WHITE), +                            ) +                            .push( +                                text_input("Placeholder", text) +                                    .on_input(Message::TextChanged), +                            ), +                    ), +            ) +            .into() +    } +} diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs new file mode 100644 index 00000000..c935aca7 --- /dev/null +++ b/examples/integration/src/main.rs @@ -0,0 +1,298 @@ +mod controls; +mod scene; + +use controls::Controls; +use scene::Scene; + +use iced_wgpu::graphics::Viewport; +use iced_wgpu::{wgpu, Backend, Renderer, Settings}; +use iced_winit::core::renderer; +use iced_winit::core::{Color, Size}; +use iced_winit::runtime::program; +use iced_winit::runtime::Debug; +use iced_winit::style::Theme; +use iced_winit::{conversion, futures, winit, Clipboard}; + +use winit::{ +    dpi::PhysicalPosition, +    event::{Event, ModifiersState, WindowEvent}, +    event_loop::{ControlFlow, EventLoop}, +}; + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::JsCast; +#[cfg(target_arch = "wasm32")] +use web_sys::HtmlCanvasElement; +#[cfg(target_arch = "wasm32")] +use winit::platform::web::WindowBuilderExtWebSys; + +pub fn main() -> Result<(), Box<dyn std::error::Error>> { +    #[cfg(target_arch = "wasm32")] +    let canvas_element = { +        console_log::init_with_level(log::Level::Debug)?; + +        std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + +        web_sys::window() +            .and_then(|win| win.document()) +            .and_then(|doc| doc.get_element_by_id("iced_canvas")) +            .and_then(|element| element.dyn_into::<HtmlCanvasElement>().ok()) +            .expect("Get canvas element") +    }; +    #[cfg(not(target_arch = "wasm32"))] +    env_logger::init(); + +    // Initialize winit +    let event_loop = EventLoop::new(); + +    #[cfg(target_arch = "wasm32")] +    let window = winit::window::WindowBuilder::new() +        .with_canvas(Some(canvas_element)) +        .build(&event_loop)?; + +    #[cfg(not(target_arch = "wasm32"))] +    let window = winit::window::Window::new(&event_loop)?; + +    let physical_size = window.inner_size(); +    let mut viewport = Viewport::with_physical_size( +        Size::new(physical_size.width, physical_size.height), +        window.scale_factor(), +    ); +    let mut cursor_position = PhysicalPosition::new(-1.0, -1.0); +    let mut modifiers = ModifiersState::default(); +    let mut clipboard = Clipboard::connect(&window); + +    // Initialize wgpu +    #[cfg(target_arch = "wasm32")] +    let default_backend = wgpu::Backends::GL; +    #[cfg(not(target_arch = "wasm32"))] +    let default_backend = wgpu::Backends::PRIMARY; + +    let backend = +        wgpu::util::backend_bits_from_env().unwrap_or(default_backend); + +    let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { +        backends: backend, +        ..Default::default() +    }); +    let surface = unsafe { instance.create_surface(&window) }?; + +    let (format, (device, queue)) = +        futures::futures::executor::block_on(async { +            let adapter = wgpu::util::initialize_adapter_from_env_or_default( +                &instance, +                backend, +                Some(&surface), +            ) +            .await +            .expect("Create adapter"); + +            let adapter_features = adapter.features(); + +            #[cfg(target_arch = "wasm32")] +            let needed_limits = wgpu::Limits::downlevel_webgl2_defaults() +                .using_resolution(adapter.limits()); + +            #[cfg(not(target_arch = "wasm32"))] +            let needed_limits = wgpu::Limits::default(); + +            let capabilities = surface.get_capabilities(&adapter); + +            ( +                capabilities +                    .formats +                    .iter() +                    .copied() +                    .find(wgpu::TextureFormat::is_srgb) +                    .or_else(|| capabilities.formats.first().copied()) +                    .expect("Get preferred format"), +                adapter +                    .request_device( +                        &wgpu::DeviceDescriptor { +                            label: None, +                            features: adapter_features +                                & wgpu::Features::default(), +                            limits: needed_limits, +                        }, +                        None, +                    ) +                    .await +                    .expect("Request device"), +            ) +        }); + +    surface.configure( +        &device, +        &wgpu::SurfaceConfiguration { +            usage: wgpu::TextureUsages::RENDER_ATTACHMENT, +            format, +            width: physical_size.width, +            height: physical_size.height, +            present_mode: wgpu::PresentMode::AutoVsync, +            alpha_mode: wgpu::CompositeAlphaMode::Auto, +            view_formats: vec![], +        }, +    ); + +    let mut resized = false; + +    // Initialize scene and GUI controls +    let scene = Scene::new(&device, format); +    let controls = Controls::new(); + +    // Initialize iced +    let mut debug = Debug::new(); +    let mut renderer = Renderer::new(Backend::new( +        &device, +        &queue, +        Settings::default(), +        format, +    )); + +    let mut state = program::State::new( +        controls, +        viewport.logical_size(), +        &mut renderer, +        &mut debug, +    ); + +    // 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::WindowEvent { event, .. } => { +                match event { +                    WindowEvent::CursorMoved { position, .. } => { +                        cursor_position = position; +                    } +                    WindowEvent::ModifiersChanged(new_modifiers) => { +                        modifiers = new_modifiers; +                    } +                    WindowEvent::Resized(_) => { +                        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, +                ) { +                    state.queue_event(event); +                } +            } +            Event::MainEventsCleared => { +                // If there are events pending +                if !state.is_queue_empty() { +                    // We update iced +                    let _ = state.update( +                        viewport.logical_size(), +                        conversion::cursor_position( +                            cursor_position, +                            viewport.scale_factor(), +                        ), +                        &mut renderer, +                        &Theme::Dark, +                        &renderer::Style { text_color: Color::WHITE }, +                        &mut clipboard, +                        &mut debug, +                    ); + +                    // and request a redraw +                    window.request_redraw(); +                } +            } +            Event::RedrawRequested(_) => { +                if resized { +                    let size = window.inner_size(); + +                    viewport = Viewport::with_physical_size( +                        Size::new(size.width, size.height), +                        window.scale_factor(), +                    ); + +                    surface.configure( +                        &device, +                        &wgpu::SurfaceConfiguration { +                            format, +                            usage: wgpu::TextureUsages::RENDER_ATTACHMENT, +                            width: size.width, +                            height: size.height, +                            present_mode: wgpu::PresentMode::AutoVsync, +                            alpha_mode: wgpu::CompositeAlphaMode::Auto, +                            view_formats: vec![], +                        }, +                    ); + +                    resized = false; +                } + +                match surface.get_current_texture() { +                    Ok(frame) => { +                        let mut encoder = device.create_command_encoder( +                            &wgpu::CommandEncoderDescriptor { label: None }, +                        ); + +                        let program = state.program(); + +                        let view = frame.texture.create_view(&wgpu::TextureViewDescriptor::default()); + +                        { +                            // We clear the frame +                            let mut render_pass = scene.clear( +                                &view, +                                &mut encoder, +                                program.background_color(), +                            ); + +                            // Draw the scene +                            scene.draw(&mut render_pass); +                        } + +                        // And then iced on top +                        renderer.with_primitives(|backend, primitive| { +                            backend.present( +                                &device, +                                &queue, +                                &mut encoder, +                                None, +                                &view, +                                primitive, +                                &viewport, +                                &debug.overlay(), +                            ); +                        }); + +                        // Then we submit the work +                        queue.submit(Some(encoder.finish())); +                        frame.present(); + +                        // Update the mouse cursor +                         window.set_cursor_icon( +                             iced_winit::conversion::mouse_interaction( +                                 state.mouse_interaction(), +                             ), +                         ); +                    } +                    Err(error) => match error { +                        wgpu::SurfaceError::OutOfMemory => { +                            panic!("Swapchain error: {error}. Rendering cannot continue.") +                        } +                        _ => { +                            // Try rendering again next frame. +                            window.request_redraw(); +                        } +                    }, +                } +            } +            _ => {} +        } +    }) +} diff --git a/examples/integration/src/scene.rs b/examples/integration/src/scene.rs new file mode 100644 index 00000000..90c7efbf --- /dev/null +++ b/examples/integration/src/scene.rs @@ -0,0 +1,102 @@ +use iced_wgpu::wgpu; +use iced_winit::core::Color; + +pub struct Scene { +    pipeline: wgpu::RenderPipeline, +} + +impl Scene { +    pub fn new( +        device: &wgpu::Device, +        texture_format: wgpu::TextureFormat, +    ) -> Scene { +        let pipeline = build_pipeline(device, texture_format); + +        Scene { pipeline } +    } + +    pub fn clear<'a>( +        &self, +        target: &'a wgpu::TextureView, +        encoder: &'a mut wgpu::CommandEncoder, +        background_color: Color, +    ) -> wgpu::RenderPass<'a> { +        encoder.begin_render_pass(&wgpu::RenderPassDescriptor { +            label: None, +            color_attachments: &[Some(wgpu::RenderPassColorAttachment { +                view: target, +                resolve_target: None, +                ops: wgpu::Operations { +                    load: wgpu::LoadOp::Clear({ +                        let [r, g, b, a] = background_color.into_linear(); + +                        wgpu::Color { +                            r: r as f64, +                            g: g as f64, +                            b: b as f64, +                            a: a as f64, +                        } +                    }), +                    store: true, +                }, +            })], +            depth_stencil_attachment: None, +        }) +    } + +    pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { +        render_pass.set_pipeline(&self.pipeline); +        render_pass.draw(0..3, 0..1); +    } +} + +fn build_pipeline( +    device: &wgpu::Device, +    texture_format: wgpu::TextureFormat, +) -> wgpu::RenderPipeline { +    let (vs_module, fs_module) = ( +        device.create_shader_module(wgpu::include_wgsl!("shader/vert.wgsl")), +        device.create_shader_module(wgpu::include_wgsl!("shader/frag.wgsl")), +    ); + +    let pipeline_layout = +        device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { +            label: None, +            push_constant_ranges: &[], +            bind_group_layouts: &[], +        }); + +    device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { +        label: None, +        layout: Some(&pipeline_layout), +        vertex: wgpu::VertexState { +            module: &vs_module, +            entry_point: "main", +            buffers: &[], +        }, +        fragment: Some(wgpu::FragmentState { +            module: &fs_module, +            entry_point: "main", +            targets: &[Some(wgpu::ColorTargetState { +                format: texture_format, +                blend: Some(wgpu::BlendState { +                    color: wgpu::BlendComponent::REPLACE, +                    alpha: wgpu::BlendComponent::REPLACE, +                }), +                write_mask: wgpu::ColorWrites::ALL, +            })], +        }), +        primitive: wgpu::PrimitiveState { +            topology: wgpu::PrimitiveTopology::TriangleList, +            front_face: wgpu::FrontFace::Ccw, +            ..Default::default() +        }, +        depth_stencil: None, +        multisample: wgpu::MultisampleState { +            count: 1, +            mask: !0, +            alpha_to_coverage_enabled: false, +        }, +        multiview: None, +    }) +} diff --git a/examples/integration/src/shader/frag.wgsl b/examples/integration/src/shader/frag.wgsl new file mode 100644 index 00000000..cf27bb56 --- /dev/null +++ b/examples/integration/src/shader/frag.wgsl @@ -0,0 +1,4 @@ +@fragment +fn main() -> @location(0) vec4<f32> { +    return vec4<f32>(1.0, 0.0, 0.0, 1.0); +} diff --git a/examples/integration/src/shader/vert.wgsl b/examples/integration/src/shader/vert.wgsl new file mode 100644 index 00000000..e353e6ba --- /dev/null +++ b/examples/integration/src/shader/vert.wgsl @@ -0,0 +1,6 @@ +@vertex +fn main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> { +    let x = f32(1 - i32(in_vertex_index)) * 0.5; +    let y = f32(1 - i32(in_vertex_index & 1u) * 2) * 0.5; +    return vec4<f32>(x, y, 0.0, 1.0); +}  | 
