2019-05-11 14:53:26 -04:00
|
|
|
// pathfinder/examples/canvas_minimal/src/main.rs
|
2019-05-03 15:35:19 -04:00
|
|
|
//
|
|
|
|
// Copyright © 2019 The Pathfinder Project Developers.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2020-04-23 21:00:52 -04:00
|
|
|
use euclid::default::Size2D;
|
2020-04-02 16:49:30 -04:00
|
|
|
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D};
|
2020-01-31 03:16:34 -05:00
|
|
|
use pathfinder_color::ColorF;
|
2019-07-12 14:26:09 -04:00
|
|
|
use pathfinder_geometry::rect::RectF;
|
2020-03-31 23:21:27 -04:00
|
|
|
use pathfinder_geometry::vector::{vec2f, vec2i};
|
2019-05-03 15:35:19 -04:00
|
|
|
use pathfinder_gl::{GLDevice, GLVersion};
|
|
|
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
|
|
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
2019-06-05 17:35:46 -04:00
|
|
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
|
|
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
|
|
|
use pathfinder_renderer::options::BuildOptions;
|
2020-02-28 20:10:53 -05:00
|
|
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
2020-04-23 21:00:52 -04:00
|
|
|
use surfman::{Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion};
|
|
|
|
use surfman::{SurfaceAccess, SurfaceType};
|
|
|
|
use winit::dpi::LogicalSize;
|
|
|
|
use winit::{ControlFlow, Event, EventsLoop, WindowBuilder, WindowEvent};
|
2019-05-03 15:35:19 -04:00
|
|
|
|
|
|
|
fn main() {
|
2020-04-23 21:00:52 -04:00
|
|
|
// Open a window.
|
|
|
|
let mut event_loop = EventsLoop::new();
|
|
|
|
let window_size = Size2D::new(640, 480);
|
|
|
|
let logical_size = LogicalSize::new(window_size.width as f64, window_size.height as f64);
|
|
|
|
let window = WindowBuilder::new().with_title("Minimal example")
|
|
|
|
.with_dimensions(logical_size)
|
|
|
|
.build(&event_loop)
|
|
|
|
.unwrap();
|
|
|
|
window.show();
|
2019-05-03 15:35:19 -04:00
|
|
|
|
2020-04-23 21:00:52 -04:00
|
|
|
// Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
|
|
|
|
// GPU.
|
|
|
|
let connection = Connection::from_winit_window(&window).unwrap();
|
|
|
|
let native_widget = connection.create_native_widget_from_winit_window(&window).unwrap();
|
|
|
|
let adapter = connection.create_low_power_adapter().unwrap();
|
|
|
|
let mut device = connection.create_device(&adapter).unwrap();
|
2019-05-03 15:35:19 -04:00
|
|
|
|
2020-04-23 21:00:52 -04:00
|
|
|
// Request an OpenGL 3.x context. Pathfinder requires this.
|
|
|
|
let context_attributes = ContextAttributes {
|
|
|
|
version: SurfmanGLVersion::new(3, 0),
|
|
|
|
flags: ContextAttributeFlags::ALPHA,
|
|
|
|
};
|
|
|
|
let context_descriptor = device.create_context_descriptor(&context_attributes).unwrap();
|
|
|
|
|
|
|
|
// Make the OpenGL context via `surfman`, and load OpenGL functions.
|
|
|
|
let surface_type = SurfaceType::Widget { native_widget };
|
|
|
|
let mut context = device.create_context(&context_descriptor).unwrap();
|
|
|
|
let surface = device.create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
|
|
|
|
.unwrap();
|
|
|
|
device.bind_surface_to_context(&mut context, surface).unwrap();
|
|
|
|
device.make_context_current(&context).unwrap();
|
|
|
|
gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));
|
2019-05-03 15:35:19 -04:00
|
|
|
|
2020-04-23 21:00:52 -04:00
|
|
|
// Get the real size of the window, taking HiDPI into account.
|
|
|
|
let hidpi_factor = window.get_current_monitor().get_hidpi_factor();
|
|
|
|
let physical_size = logical_size.to_physical(hidpi_factor);
|
|
|
|
let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);
|
|
|
|
|
|
|
|
// Create a Pathfinder GL device.
|
|
|
|
let default_framebuffer = device.context_surface_info(&context)
|
|
|
|
.unwrap()
|
|
|
|
.unwrap()
|
|
|
|
.framebuffer_object;
|
|
|
|
let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);
|
2019-05-03 15:35:19 -04:00
|
|
|
|
|
|
|
// Create a Pathfinder renderer.
|
2020-04-23 21:00:52 -04:00
|
|
|
let mut renderer = Renderer::new(pathfinder_device,
|
2020-02-28 20:10:53 -05:00
|
|
|
&EmbeddedResourceLoader::new(),
|
2020-04-23 21:00:52 -04:00
|
|
|
DestFramebuffer::full_window(framebuffer_size),
|
|
|
|
RendererOptions {
|
|
|
|
background_color: Some(ColorF::white()),
|
|
|
|
..RendererOptions::default()
|
|
|
|
});
|
2019-05-03 15:35:19 -04:00
|
|
|
|
|
|
|
// Make a canvas. We're going to draw a house.
|
2020-04-02 16:49:30 -04:00
|
|
|
let font_context = CanvasFontContext::from_system_source();
|
2020-04-23 21:00:52 -04:00
|
|
|
let mut canvas = Canvas::new(framebuffer_size.to_f32()).get_context_2d(font_context);
|
2019-05-03 15:35:19 -04:00
|
|
|
|
|
|
|
// Set line width.
|
|
|
|
canvas.set_line_width(10.0);
|
|
|
|
|
|
|
|
// Draw walls.
|
2020-03-31 14:28:34 -04:00
|
|
|
canvas.stroke_rect(RectF::new(vec2f(75.0, 140.0), vec2f(150.0, 110.0)));
|
2019-05-03 15:35:19 -04:00
|
|
|
|
|
|
|
// Draw door.
|
2020-03-31 14:28:34 -04:00
|
|
|
canvas.fill_rect(RectF::new(vec2f(130.0, 190.0), vec2f(40.0, 60.0)));
|
2019-05-03 15:35:19 -04:00
|
|
|
|
|
|
|
// Draw roof.
|
|
|
|
let mut path = Path2D::new();
|
2020-03-31 14:28:34 -04:00
|
|
|
path.move_to(vec2f(50.0, 140.0));
|
|
|
|
path.line_to(vec2f(150.0, 60.0));
|
|
|
|
path.line_to(vec2f(250.0, 140.0));
|
2019-05-03 15:35:19 -04:00
|
|
|
path.close_path();
|
|
|
|
canvas.stroke_path(path);
|
|
|
|
|
|
|
|
// Render the canvas to screen.
|
2020-04-02 16:49:30 -04:00
|
|
|
let scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(), RayonExecutor);
|
2019-06-05 17:35:46 -04:00
|
|
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
2020-04-23 21:00:52 -04:00
|
|
|
|
|
|
|
// Present the surface.
|
|
|
|
let mut surface = device.unbind_surface_from_context(&mut context).unwrap().unwrap();
|
|
|
|
device.present_surface(&mut context, &mut surface).unwrap();
|
|
|
|
device.bind_surface_to_context(&mut context, surface).unwrap();
|
2019-05-03 15:35:19 -04:00
|
|
|
|
|
|
|
// Wait for a keypress.
|
2020-04-23 21:00:52 -04:00
|
|
|
event_loop.run_forever(|event| {
|
|
|
|
match event {
|
|
|
|
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } |
|
|
|
|
Event::WindowEvent { event: WindowEvent::KeyboardInput { .. }, .. } => {
|
|
|
|
ControlFlow::Break
|
|
|
|
}
|
|
|
|
_ => ControlFlow::Continue,
|
2019-05-03 15:35:19 -04:00
|
|
|
}
|
2020-04-23 21:00:52 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
// Clean up.
|
|
|
|
drop(device.destroy_context(&mut context));
|
2019-05-03 15:35:19 -04:00
|
|
|
}
|