diff options
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | examples/integration_gl/Cargo.toml | 13 | ||||
-rw-r--r-- | examples/integration_gl/README.md | 16 | ||||
-rw-r--r-- | examples/integration_gl/src/controls.rs | 110 | ||||
-rw-r--r-- | examples/integration_gl/src/main.rs | 175 | ||||
-rw-r--r-- | examples/integration_gl/src/scene.rs | 93 | ||||
-rw-r--r-- | glow/src/lib.rs | 4 |
7 files changed, 410 insertions, 2 deletions
@@ -86,6 +86,7 @@ members = [ "examples/tooltip", "examples/url_handler", "examples/menu", + "examples/integration_gl", ] [dependencies] diff --git a/examples/integration_gl/Cargo.toml b/examples/integration_gl/Cargo.toml new file mode 100644 index 00000000..80d7adad --- /dev/null +++ b/examples/integration_gl/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "integration_gl" +version = "0.1.0" +authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +iced_glutin = { path = "../../glutin" } +iced_glow = { path = "../../glow" } +iced_winit = { path = "../../winit" } +env_logger = "0.8" +glow = "0.6" diff --git a/examples/integration_gl/README.md b/examples/integration_gl/README.md new file mode 100644 index 00000000..87491508 --- /dev/null +++ b/examples/integration_gl/README.md @@ -0,0 +1,16 @@ +## Integration + +A demonstration of how to integrate Iced in an existing graphical OpenGL application. + +The __[`main`]__ file contains all the code of the example. + +<div align="center"> + <a href="https://imgbox.com/9P9ETcod" target="_blank"><img src="https://images2.imgbox.com/2a/51/9P9ETcod_o.gif" alt="image host"/></a> +</div> + +You can run it with `cargo run`: +``` +cargo run --package integration_gl +``` + +[`main`]: src/main.rs diff --git a/examples/integration_gl/src/controls.rs b/examples/integration_gl/src/controls.rs new file mode 100644 index 00000000..13b7fbc2 --- /dev/null +++ b/examples/integration_gl/src/controls.rs @@ -0,0 +1,110 @@ +use iced_glow::Renderer; +use iced_glutin::{ + slider, Align, Clipboard, Color, Column, Command, Element, Length, Program, + Row, Slider, Text, +}; + +pub struct Controls { + background_color: Color, + sliders: [slider::State; 3], +} + +#[derive(Debug, Clone)] +pub enum Message { + BackgroundColorChanged(Color), +} + +impl Controls { + pub fn new() -> Controls { + Controls { + background_color: Color::BLACK, + sliders: Default::default(), + } + } + + pub fn background_color(&self) -> Color { + self.background_color + } +} + +impl Program for Controls { + type Renderer = Renderer; + type Message = Message; + type Clipboard = Clipboard; + + fn update( + &mut self, + message: Message, + _clipboard: &mut Clipboard, + ) -> Command<Message> { + match message { + Message::BackgroundColorChanged(color) => { + self.background_color = color; + } + } + + Command::none() + } + + fn view(&mut self) -> Element<Message, Renderer> { + let [r, g, b] = &mut self.sliders; + let background_color = self.background_color; + + let sliders = Row::new() + .width(Length::Units(500)) + .spacing(20) + .push( + Slider::new(r, 0.0..=1.0, background_color.r, move |r| { + Message::BackgroundColorChanged(Color { + r, + ..background_color + }) + }) + .step(0.01), + ) + .push( + Slider::new(g, 0.0..=1.0, background_color.g, move |g| { + Message::BackgroundColorChanged(Color { + g, + ..background_color + }) + }) + .step(0.01), + ) + .push( + Slider::new(b, 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(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_gl/src/main.rs b/examples/integration_gl/src/main.rs new file mode 100644 index 00000000..925102e3 --- /dev/null +++ b/examples/integration_gl/src/main.rs @@ -0,0 +1,175 @@ +mod controls; +mod scene; + +use controls::Controls; +use scene::Scene; + +use glow; +use glow::*; +use iced_glow::{Backend, Renderer, Settings, Viewport}; +use iced_glutin::glutin; +use iced_glutin::glutin::event::{Event, WindowEvent}; +use iced_glutin::glutin::event_loop::ControlFlow; +use iced_glutin::{program, Clipboard, Debug, Size}; +use iced_winit::conversion; +use iced_winit::winit; +use winit::{dpi::PhysicalPosition, event::ModifiersState}; + +pub fn main() { + env_logger::init(); + let (gl, event_loop, windowed_context, shader_version) = { + let el = glutin::event_loop::EventLoop::new(); + let wb = glutin::window::WindowBuilder::new() + .with_title("OpenGL integration example") + .with_inner_size(glutin::dpi::LogicalSize::new(1024.0, 768.0)); + let windowed_context = glutin::ContextBuilder::new() + .with_vsync(true) + .build_windowed(wb, &el) + .unwrap(); + unsafe { + let windowed_context = windowed_context.make_current().unwrap(); + let gl = glow::Context::from_loader_function(|s| { + windowed_context.get_proc_address(s) as *const _ + }); + // Enable auto-conversion from/to sRGB + gl.enable(glow::FRAMEBUFFER_SRGB); + + // Enable alpha blending + gl.enable(glow::BLEND); + gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); + + // Disable multisampling by default + gl.disable(glow::MULTISAMPLE); + (gl, el, windowed_context, "#version 410") + } + }; + + let physical_size = windowed_context.window().inner_size(); + let mut viewport = Viewport::with_physical_size( + Size::new(physical_size.width, physical_size.height), + windowed_context.window().scale_factor(), + ); + + let mut cursor_position = PhysicalPosition::new(-1.0, -1.0); + let mut modifiers = ModifiersState::default(); + let mut clipboard = Clipboard::connect(&windowed_context.window()); + + let mut renderer = Renderer::new(Backend::new(&gl, Settings::default())); + + let mut debug = Debug::new(); + + let controls = Controls::new(); + let mut state = program::State::new( + controls, + viewport.logical_size(), + conversion::cursor_position(cursor_position, viewport.scale_factor()), + &mut renderer, + &mut debug, + ); + let mut resized = false; + + event_loop.run(move |event, _, control_flow| { + let scene = Scene::new(&gl, &shader_version); + *control_flow = ControlFlow::Wait; + + match event { + Event::LoopDestroyed => return, + Event::WindowEvent { event, .. } => { + match event { + WindowEvent::CursorMoved { position, .. } => { + cursor_position = position; + } + WindowEvent::ModifiersChanged(new_modifiers) => { + modifiers = new_modifiers; + } + WindowEvent::Resized(physical_size) => { + viewport = Viewport::with_physical_size( + Size::new( + physical_size.width, + physical_size.height, + ), + windowed_context.window().scale_factor(), + ); + + resized = true; + } + WindowEvent::CloseRequested => { + scene.cleanup(&gl); + *control_flow = ControlFlow::Exit + } + _ => (), + } + + // Map window event to iced event + if let Some(event) = iced_winit::conversion::window_event( + &event, + windowed_context.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, + &mut clipboard, + &mut debug, + ); + + // and request a redraw + windowed_context.window().request_redraw(); + } + } + Event::RedrawRequested(_) => { + if resized { + let size = windowed_context.window().inner_size(); + + unsafe { + gl.viewport( + 0, + 0, + size.width as i32, + size.height as i32, + ); + } + + resized = false; + } + + let program = state.program(); + { + // We clear the frame + scene.clear(&gl, program.background_color()); + + // Draw the scene + scene.draw(&gl); + } + + // And then iced on top + let mouse_interaction = renderer.backend_mut().draw( + &gl, + &viewport, + state.primitive(), + &debug.overlay(), + ); + // Update the mouse cursor + windowed_context.window().set_cursor_icon( + iced_winit::conversion::mouse_interaction( + mouse_interaction, + ), + ); + + windowed_context.swap_buffers().unwrap(); + } + _ => (), + } + }); +} diff --git a/examples/integration_gl/src/scene.rs b/examples/integration_gl/src/scene.rs new file mode 100644 index 00000000..596381b3 --- /dev/null +++ b/examples/integration_gl/src/scene.rs @@ -0,0 +1,93 @@ +use glow::*; +use iced_glow::Color; + +pub struct Scene { + program: glow::Program, + vertex_array: glow::VertexArray, +} + +impl Scene { + pub fn new(gl: &glow::Context, shader_version: &str) -> Self { + unsafe { + let vertex_array = gl + .create_vertex_array() + .expect("Cannot create vertex array"); + gl.bind_vertex_array(Some(vertex_array)); + + let program = gl.create_program().expect("Cannot create program"); + + let (vertex_shader_source, fragment_shader_source) = ( + r#"const vec2 verts[3] = vec2[3]( + vec2(0.5f, 1.0f), + vec2(0.0f, 0.0f), + vec2(1.0f, 0.0f) + ); + out vec2 vert; + void main() { + vert = verts[gl_VertexID]; + gl_Position = vec4(vert - 0.5, 0.0, 1.0); + }"#, + r#"precision highp float; + in vec2 vert; + out vec4 color; + void main() { + color = vec4(vert, 0.5, 1.0); + }"#, + ); + + let shader_sources = [ + (glow::VERTEX_SHADER, vertex_shader_source), + (glow::FRAGMENT_SHADER, fragment_shader_source), + ]; + + let mut shaders = Vec::with_capacity(shader_sources.len()); + + for (shader_type, shader_source) in shader_sources.iter() { + let shader = gl + .create_shader(*shader_type) + .expect("Cannot create shader"); + gl.shader_source(shader, &format!("{}\n{}", shader_version, shader_source)); + gl.compile_shader(shader); + if !gl.get_shader_compile_status(shader) { + panic!(gl.get_shader_info_log(shader)); + } + gl.attach_shader(program, shader); + shaders.push(shader); + } + + gl.link_program(program); + if !gl.get_program_link_status(program) { + panic!(gl.get_program_info_log(program)); + } + + for shader in shaders { + gl.detach_shader(program, shader); + gl.delete_shader(shader); + } + + gl.use_program(Some(program)); + Self { program, vertex_array } + } + } + + pub fn clear(&self, gl: &glow::Context, background_color: Color) { + let [r, g, b, a] = background_color.into_linear(); + unsafe { + gl.clear_color(r, g, b, a); + gl.clear(glow::COLOR_BUFFER_BIT); + } + } + + pub fn draw(&self, gl: &glow::Context) { + unsafe { + gl.draw_arrays(glow::TRIANGLES, 0, 3); + } + } + + pub fn cleanup(&self, gl: &glow::Context) { + unsafe { + gl.delete_program(self.program); + gl.delete_vertex_array(self.vertex_array); + } + } +}
\ No newline at end of file diff --git a/glow/src/lib.rs b/glow/src/lib.rs index 98faf24c..888492d8 100644 --- a/glow/src/lib.rs +++ b/glow/src/lib.rs @@ -4,14 +4,14 @@ //! //! [`glow`]: https://github.com/grovesNL/glow //! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native -#![deny(missing_docs)] +//#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![forbid(rust_2018_idioms)] #![cfg_attr(docsrs, feature(doc_cfg))] mod backend; -mod program; +pub mod program; mod quad; mod text; mod triangle; |