diff options
Diffstat (limited to 'gfx/wr/examples/multiwindow.rs')
-rw-r--r-- | gfx/wr/examples/multiwindow.rs | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/gfx/wr/examples/multiwindow.rs b/gfx/wr/examples/multiwindow.rs new file mode 100644 index 0000000000..aa0ac87151 --- /dev/null +++ b/gfx/wr/examples/multiwindow.rs @@ -0,0 +1,327 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +extern crate euclid; +extern crate gleam; +extern crate glutin; +extern crate webrender; +extern crate winit; + +use gleam::gl; +use glutin::NotCurrent; +use std::fs::File; +use std::io::Read; +use webrender::api::*; +use webrender::api::units::*; +use webrender::render_api::*; +use webrender::DebugFlags; +use winit::dpi::LogicalSize; + +struct Notifier { + events_proxy: winit::EventsLoopProxy, +} + +impl Notifier { + fn new(events_proxy: winit::EventsLoopProxy) -> Notifier { + Notifier { events_proxy } + } +} + +impl RenderNotifier for Notifier { + fn clone(&self) -> Box<dyn RenderNotifier> { + Box::new(Notifier { + events_proxy: self.events_proxy.clone(), + }) + } + + fn wake_up(&self, _composite_needed: bool) { + #[cfg(not(target_os = "android"))] + let _ = self.events_proxy.wakeup(); + } + + fn new_frame_ready(&self, + _: DocumentId, + _scrolled: bool, + composite_needed: bool, + _render_time: Option<u64>) { + self.wake_up(composite_needed); + } +} + +struct Window { + events_loop: winit::EventsLoop, //TODO: share events loop? + context: Option<glutin::WindowedContext<NotCurrent>>, + renderer: webrender::Renderer, + name: &'static str, + pipeline_id: PipelineId, + document_id: DocumentId, + epoch: Epoch, + api: RenderApi, + font_instance_key: FontInstanceKey, +} + +impl Window { + fn new(name: &'static str, clear_color: ColorF) -> Self { + let events_loop = winit::EventsLoop::new(); + let window_builder = winit::WindowBuilder::new() + .with_title(name) + .with_multitouch() + .with_dimensions(LogicalSize::new(800., 600.)); + let context = glutin::ContextBuilder::new() + .with_gl(glutin::GlRequest::GlThenGles { + opengl_version: (3, 2), + opengles_version: (3, 0), + }) + .build_windowed(window_builder, &events_loop) + .unwrap(); + + let context = unsafe { context.make_current().unwrap() }; + + let gl = match context.get_api() { + glutin::Api::OpenGl => unsafe { + gl::GlFns::load_with(|symbol| context.get_proc_address(symbol) as *const _) + }, + glutin::Api::OpenGlEs => unsafe { + gl::GlesFns::load_with(|symbol| context.get_proc_address(symbol) as *const _) + }, + glutin::Api::WebGl => unimplemented!(), + }; + + let device_pixel_ratio = context.window().get_hidpi_factor() as f32; + + let opts = webrender::RendererOptions { + device_pixel_ratio, + clear_color: Some(clear_color), + ..webrender::RendererOptions::default() + }; + + let device_size = { + let size = context + .window() + .get_inner_size() + .unwrap() + .to_physical(device_pixel_ratio as f64); + DeviceIntSize::new(size.width as i32, size.height as i32) + }; + let notifier = Box::new(Notifier::new(events_loop.create_proxy())); + let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None).unwrap(); + let mut api = sender.create_api(); + let document_id = api.add_document(device_size); + + let epoch = Epoch(0); + let pipeline_id = PipelineId(0, 0); + let mut txn = Transaction::new(); + + let font_key = api.generate_font_key(); + let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf"); + txn.add_raw_font(font_key, font_bytes, 0); + + let font_instance_key = api.generate_font_instance_key(); + txn.add_font_instance(font_instance_key, font_key, 32.0, None, None, Vec::new()); + + api.send_transaction(document_id, txn); + + Window { + events_loop, + context: Some(unsafe { context.make_not_current().unwrap() }), + renderer, + name, + epoch, + pipeline_id, + document_id, + api, + font_instance_key, + } + } + + fn tick(&mut self) -> bool { + let mut do_exit = false; + let my_name = &self.name; + let renderer = &mut self.renderer; + let api = &mut self.api; + + self.events_loop.poll_events(|global_event| match global_event { + winit::Event::WindowEvent { event, .. } => match event { + winit::WindowEvent::CloseRequested | + winit::WindowEvent::KeyboardInput { + input: winit::KeyboardInput { + virtual_keycode: Some(winit::VirtualKeyCode::Escape), + .. + }, + .. + } => { + do_exit = true + } + winit::WindowEvent::KeyboardInput { + input: winit::KeyboardInput { + state: winit::ElementState::Pressed, + virtual_keycode: Some(winit::VirtualKeyCode::P), + .. + }, + .. + } => { + println!("set flags {}", my_name); + api.send_debug_cmd(DebugCommand::SetFlags(DebugFlags::PROFILER_DBG)) + } + _ => {} + } + _ => {} + }); + if do_exit { + return true + } + + let context = unsafe { self.context.take().unwrap().make_current().unwrap() }; + let device_pixel_ratio = context.window().get_hidpi_factor() as f32; + let device_size = { + let size = context + .window() + .get_inner_size() + .unwrap() + .to_physical(device_pixel_ratio as f64); + DeviceIntSize::new(size.width as i32, size.height as i32) + }; + let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio); + let mut txn = Transaction::new(); + let mut builder = DisplayListBuilder::new(self.pipeline_id); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id); + + let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size); + builder.push_simple_stacking_context( + bounds.origin, + space_and_clip.spatial_id, + PrimitiveFlags::IS_BACKFACE_VISIBLE, + ); + + builder.push_rect( + &CommonItemProperties::new( + LayoutRect::new( + LayoutPoint::new(100.0, 200.0), + LayoutSize::new(100.0, 200.0), + ), + space_and_clip, + ), + LayoutRect::new( + LayoutPoint::new(100.0, 200.0), + LayoutSize::new(100.0, 200.0), + ), + ColorF::new(0.0, 1.0, 0.0, 1.0)); + + let text_bounds = LayoutRect::new( + LayoutPoint::new(100.0, 50.0), + LayoutSize::new(700.0, 200.0) + ); + let glyphs = vec![ + GlyphInstance { + index: 48, + point: LayoutPoint::new(100.0, 100.0), + }, + GlyphInstance { + index: 68, + point: LayoutPoint::new(150.0, 100.0), + }, + GlyphInstance { + index: 80, + point: LayoutPoint::new(200.0, 100.0), + }, + GlyphInstance { + index: 82, + point: LayoutPoint::new(250.0, 100.0), + }, + GlyphInstance { + index: 81, + point: LayoutPoint::new(300.0, 100.0), + }, + GlyphInstance { + index: 3, + point: LayoutPoint::new(350.0, 100.0), + }, + GlyphInstance { + index: 86, + point: LayoutPoint::new(400.0, 100.0), + }, + GlyphInstance { + index: 79, + point: LayoutPoint::new(450.0, 100.0), + }, + GlyphInstance { + index: 72, + point: LayoutPoint::new(500.0, 100.0), + }, + GlyphInstance { + index: 83, + point: LayoutPoint::new(550.0, 100.0), + }, + GlyphInstance { + index: 87, + point: LayoutPoint::new(600.0, 100.0), + }, + GlyphInstance { + index: 17, + point: LayoutPoint::new(650.0, 100.0), + }, + ]; + + builder.push_text( + &CommonItemProperties::new( + text_bounds, + space_and_clip, + ), + text_bounds, + &glyphs, + self.font_instance_key, + ColorF::new(1.0, 1.0, 0.0, 1.0), + None, + ); + + builder.pop_stacking_context(); + + txn.set_display_list( + self.epoch, + None, + layout_size, + builder.finalize(), + true, + ); + txn.set_root_pipeline(self.pipeline_id); + txn.generate_frame(0); + api.send_transaction(self.document_id, txn); + + renderer.update(); + renderer.render(device_size, 0).unwrap(); + context.swap_buffers().ok(); + + self.context = Some(unsafe { context.make_not_current().unwrap() }); + + false + } + + fn deinit(self) { + self.renderer.deinit(); + } +} + +fn main() { + let mut win1 = Window::new("window1", ColorF::new(0.3, 0.0, 0.0, 1.0)); + let mut win2 = Window::new("window2", ColorF::new(0.0, 0.3, 0.0, 1.0)); + + loop { + if win1.tick() { + break; + } + if win2.tick() { + break; + } + } + + win1.deinit(); + win2.deinit(); +} + +fn load_file(name: &str) -> Vec<u8> { + let mut file = File::open(name).unwrap(); + let mut buffer = vec![]; + file.read_to_end(&mut buffer).unwrap(); + buffer +} |