├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── THANKS.md ├── canvas ├── Cargo.toml ├── README.md ├── src │ ├── canvas.rs │ ├── color.rs │ ├── context.rs │ ├── conversion_streams │ │ ├── dashed_lines.rs │ │ ├── glyph_layout.rs │ │ ├── mod.rs │ │ ├── outline_fonts.rs │ │ └── path_stream.rs │ ├── decoding.rs │ ├── draw.rs │ ├── draw_resource.rs │ ├── draw_stream.rs │ ├── drawing_target.rs │ ├── encoding.rs │ ├── font.rs │ ├── font_face.rs │ ├── font_line_layout.rs │ ├── gradient.rs │ ├── lib.rs │ ├── namespace.rs │ ├── path.rs │ ├── primitives.rs │ ├── scenery │ │ ├── drawing_request.rs │ │ ├── mod.rs │ │ └── sprite_properties.rs │ ├── sprite.rs │ ├── texture.rs │ └── transform2d.rs ├── test_data │ ├── Lato-Regular.ttf │ └── Lato-license.md └── tests │ └── readme.rs ├── canvas_events ├── Cargo.toml └── src │ ├── draw_event.rs │ ├── draw_event_request.rs │ ├── draw_window_request.rs │ ├── key.rs │ ├── lib.rs │ ├── pointer_event.rs │ └── render_request.rs ├── draw ├── Cargo.toml ├── GUIDE.md ├── README.md ├── examples │ ├── Lato-Bold.ttf │ ├── Lato-Regular.ttf │ ├── Lato-license.md │ ├── bounce.rs │ ├── bounce_sprites.rs │ ├── canvas_window.rs │ ├── circle.rs │ ├── clip.rs │ ├── dashed_line.rs │ ├── erase.rs │ ├── flo_and_carrot.png │ ├── flo_drawing_on_window.png │ ├── follow_mouse.rs │ ├── gradient.rs │ ├── hello_world.rs │ ├── layer_alpha.rs │ ├── layer_reorder.rs │ ├── mandelbrot.rs │ ├── mascot.rs │ ├── mascot_dynamic_texture.rs │ ├── mascot_filter.rs │ ├── mascot_shadow.rs │ ├── mascot_sprite.rs │ ├── mascot_texture.rs │ ├── mirror_windows.rs │ ├── render_window.rs │ ├── render_window_double_resolve.rs │ ├── show_tessellation.rs │ ├── show_text_tessellation.rs │ ├── sprite.rs │ ├── text_layout.rs │ ├── texture.rs │ ├── texture_filters.rs │ ├── texture_from_sprite.rs │ ├── texture_from_sprite_dynamic.rs │ ├── texture_spin.rs │ ├── texture_sprites.rs │ ├── update_title.rs │ ├── vectoroids.rs │ ├── wibble.rs │ ├── wibble_dynamic_mascot.rs │ └── wibble_mascot.rs ├── guide_images │ ├── s_gradients.png │ ├── s_graphics_primitives.png │ ├── s_layers.png │ ├── s_sprites.png │ ├── s_text_layout.png │ ├── s_text_rendering.png │ ├── s_textures.png │ └── s_transforms.png ├── images │ ├── beeb.png │ ├── mandelbrot.png │ ├── mascot.png │ └── wibble.png ├── src │ ├── draw_scene │ │ ├── drawing_window_program.rs │ │ ├── glutin_render_window_program.rs │ │ ├── glutin_scene.rs │ │ ├── mod.rs │ │ ├── render_window_program.rs │ │ ├── scene.rs │ │ ├── software_drawing_window_program.rs │ │ ├── software_scene.rs │ │ ├── wgpu_render_window_program.rs │ │ └── wgpu_scene.rs │ ├── drawing_window.rs │ ├── glutin │ │ ├── event_conversion.rs │ │ ├── glutin_runtime.rs │ │ ├── glutin_thread.rs │ │ ├── glutin_thread_event.rs │ │ ├── glutin_window.rs │ │ └── mod.rs │ ├── lib.rs │ ├── render_window.rs │ ├── software │ │ ├── event_conversion.rs │ │ ├── mod.rs │ │ ├── winit_runtime.rs │ │ ├── winit_thread.rs │ │ ├── winit_thread_event.rs │ │ └── winit_window.rs │ ├── wgpu │ │ ├── event_conversion.rs │ │ ├── mod.rs │ │ ├── platform_macos │ │ │ ├── events.rs │ │ │ ├── flo_draw_view.rs │ │ │ └── mod.rs │ │ ├── winit_runtime.rs │ │ ├── winit_thread.rs │ │ ├── winit_thread_event.rs │ │ └── winit_window.rs │ └── window_properties.rs └── tests │ └── readme.rs ├── images ├── bounce.png ├── flo_drawing_on_window.png ├── flo_drawing_on_window_small.png ├── gradient.png ├── mandelbrot.png ├── mascot.png ├── textlayout.png └── wibble.png ├── render ├── Cargo.toml ├── bindings │ ├── metal_bindings.h │ └── metal_vertex2d.h ├── build.rs ├── examples │ ├── raw_wgpu_winit_circle.rs │ └── raw_wgpu_winit_triangle.rs ├── shaders │ ├── dashed_line │ │ └── dashed_line.glslf │ ├── filters │ │ ├── alpha_blend.glslf │ │ ├── alpha_blend.wgsl │ │ ├── blur_29.glslf │ │ ├── blur_61.glslf │ │ ├── blur_9.glslf │ │ ├── blur_fixed.wgsl │ │ ├── blur_texture.glslf │ │ ├── blur_texture.wgsl │ │ ├── displacement.glslf │ │ ├── displacement.wgsl │ │ ├── mask.glslf │ │ ├── mask.wgsl │ │ ├── premultiply.glslf │ │ ├── reduce.wgsl │ │ ├── tint.glslf │ │ └── tint.wgsl │ ├── simple │ │ ├── clip_mask.metal │ │ ├── clip_mask.wgsl │ │ ├── clip_none.wgsl │ │ ├── color_invert_alpha.wgsl │ │ ├── color_multiply_alpha.wgsl │ │ ├── color_no_post_processing.wgsl │ │ ├── multisample_resolve_4.glslf │ │ ├── postprocessing.metal │ │ ├── rasterizer.metal │ │ ├── resolve.glslv │ │ ├── simple.glslf │ │ ├── simple.glslv │ │ ├── simple.metal │ │ └── simple.wgsl │ └── texture │ │ ├── alpha_no_premultiply.wgsl │ │ ├── alpha_premultiplied.wgsl │ │ ├── gradient.glslf │ │ ├── gradient.glslv │ │ ├── gradient.wgsl │ │ ├── gradient_fragment.metal │ │ ├── texture.glslf │ │ ├── texture.glslv │ │ ├── texture.wgsl │ │ ├── texture_fragment.metal │ │ ├── texture_multisample.wgsl │ │ ├── texture_none.wgsl │ │ ├── texture_pos_input.wgsl │ │ ├── texture_pos_separate.wgsl │ │ └── texture_sampler.wgsl └── src │ ├── action │ ├── blend_mode.rs │ ├── color.rs │ ├── identities.rs │ ├── mod.rs │ ├── render_action.rs │ ├── render_action_type.rs │ ├── render_target_type.rs │ ├── shader_type.rs │ └── texture_filter.rs │ ├── buffer │ ├── matrix.rs │ ├── mod.rs │ └── vertex.rs │ ├── gl_renderer │ ├── buffer.rs │ ├── error.rs │ ├── gl_renderer.rs │ ├── mod.rs │ ├── render_target.rs │ ├── shader.rs │ ├── shader_collection.rs │ ├── shader_program.rs │ ├── shader_uniforms.rs │ ├── standard_shader_programs.rs │ ├── texture.rs │ ├── vertex.rs │ └── vertex_array.rs │ ├── lib.rs │ ├── metal_renderer │ ├── bindings.rs │ ├── buffer.rs │ ├── convert.rs │ ├── matrix_buffer.rs │ ├── metal_renderer.rs │ ├── mod.rs │ ├── pipeline_configuration.rs │ └── render_target.rs │ ├── offscreen │ ├── error.rs │ ├── metal.rs │ ├── mod.rs │ ├── offscreen_trait.rs │ ├── opengl.rs │ ├── opengl_cgl_init.rs │ ├── opengl_egl_init.rs │ ├── opengl_wgl_init.rs │ ├── test.rs │ └── wgpu_offscreen.rs │ ├── profiler.rs │ └── wgpu_renderer │ ├── alpha_blend_filter.rs │ ├── blur_filter.rs │ ├── displacement_map_filter.rs │ ├── mask_filter.rs │ ├── mod.rs │ ├── pipeline.rs │ ├── pipeline_configuration.rs │ ├── reduce_filter.rs │ ├── render_pass_resources.rs │ ├── render_target.rs │ ├── renderer_state.rs │ ├── samplers.rs │ ├── shader_cache.rs │ ├── texture.rs │ ├── texture_settings.rs │ ├── tint_filter.rs │ ├── to_buffer.rs │ ├── wgpu_renderer.rs │ └── wgpu_shader.rs ├── render_canvas ├── Cargo.toml ├── examples │ ├── Lato-Regular.ttf │ ├── Lato-license.md │ ├── guide_illustrations.rs │ ├── png_mascot.rs │ ├── png_triangle.rs │ └── raw_wgpu_winit.rs ├── src │ ├── canvas_renderer │ │ ├── canvas_renderer.rs │ │ ├── mod.rs │ │ ├── tessellate_build_path.rs │ │ ├── tessellate_font.rs │ │ ├── tessellate_frame.rs │ │ ├── tessellate_gradients.rs │ │ ├── tessellate_layers.rs │ │ ├── tessellate_namespaces.rs │ │ ├── tessellate_path.rs │ │ ├── tessellate_properties.rs │ │ ├── tessellate_sprites.rs │ │ ├── tessellate_state.rs │ │ ├── tessellate_textures.rs │ │ └── tessellate_transform.rs │ ├── dynamic_texture_state.rs │ ├── fill_state.rs │ ├── layer_bounds.rs │ ├── layer_handle.rs │ ├── layer_state.rs │ ├── lib.rs │ ├── matrix.rs │ ├── offscreen │ │ ├── hardware.rs │ │ ├── initialise.rs │ │ ├── mod.rs │ │ ├── offscreen_trait.rs │ │ ├── render_offscreen.rs │ │ └── software.rs │ ├── render_entity.rs │ ├── render_entity_details.rs │ ├── render_gradient.rs │ ├── render_texture.rs │ ├── renderer_core.rs │ ├── renderer_layer.rs │ ├── renderer_stream.rs │ ├── renderer_worker.rs │ ├── resource_ids.rs │ ├── stroke_settings.rs │ ├── texture_filter_request.rs │ └── texture_render_request.rs └── tests │ └── render_tests.rs ├── render_gl_offscreen ├── Cargo.toml ├── build.rs ├── linux_gbm.h ├── src │ ├── egl.rs │ ├── gbm.rs │ └── lib.rs └── tiny_gbm.h └── render_software ├── Cargo.toml ├── README.md ├── examples ├── circle_to_png.rs ├── flo_drawing_on_window.png ├── render_canvas_drawing.rs ├── software_basic.rs ├── software_dynamic_sprite.rs ├── software_gradient.rs ├── software_mascot.rs ├── software_mascot_sprite.rs ├── software_mascot_texture.rs ├── software_render_perf.rs ├── software_sprite.rs ├── software_text_layout.rs ├── software_texture.rs ├── software_texture_filters.rs ├── software_texture_scaling.rs └── software_texture_transform.rs ├── src ├── draw │ ├── canvas_drawing.rs │ ├── canvas_drawing_region_renderer.rs │ ├── drawing_state.rs │ ├── dynamic_sprites.rs │ ├── gradient.rs │ ├── layer.rs │ ├── mod.rs │ ├── path.rs │ ├── pixel_programs.rs │ ├── prepared_layer.rs │ ├── sprite.rs │ ├── stroke.rs │ ├── texture.rs │ └── transform.rs ├── edgeplan │ ├── edge_descriptor.rs │ ├── edge_descriptor_intercept.rs │ ├── edge_id.rs │ ├── edge_intercept_direction.rs │ ├── edge_plan.rs │ ├── edge_plan_intercept.rs │ ├── mod.rs │ ├── shape_descriptor.rs │ └── shape_id.rs ├── edges │ ├── bezier_subpath_edge.rs │ ├── clipping_edge.rs │ ├── contour_edge.rs │ ├── flattened_bezier_subpath_edge.rs │ ├── line_stroke_edge.rs │ ├── mod.rs │ ├── polyline_edge.rs │ └── rectangle_edge.rs ├── filters │ ├── alpha_blend_filter.rs │ ├── combined_filter.rs │ ├── displacement_map_filter.rs │ ├── gaussian_blur_filter.rs │ ├── mask_filter.rs │ ├── mod.rs │ ├── pixel_filter_trait.rs │ ├── texture_filter.rs │ └── tint_filter.rs ├── lib.rs ├── pixel │ ├── alpha_blend_trait.rs │ ├── f32_linear.rs │ ├── f32_linear_texture_reader.rs │ ├── gamma_lut.rs │ ├── mip_map.rs │ ├── mod.rs │ ├── pixel_program.rs │ ├── pixel_program_cache.rs │ ├── pixel_program_runner.rs │ ├── pixel_trait.rs │ ├── rgba_texture.rs │ ├── texture_reader.rs │ ├── to_gamma_colorspace_trait.rs │ ├── to_linear_colorspace_trait.rs │ ├── u16_linear_texture.rs │ ├── u16_rgba.rs │ ├── u32_argb.rs │ ├── u32_fixed_point.rs │ ├── u32_linear.rs │ ├── u32_linear_texture_reader.rs │ └── u8_rgba.rs ├── pixel_programs │ ├── basic_sprite.rs │ ├── basic_texture.rs │ ├── bilinear_texture.rs │ ├── blend.rs │ ├── debug_ypos.rs │ ├── filtered_scanline.rs │ ├── gradient_linear.rs │ ├── mip_map_texture.rs │ ├── mod.rs │ ├── solid_color.rs │ ├── source_over.rs │ └── transformed_sprite.rs ├── render │ ├── edge_plan.rs │ ├── edgeplan_region_renderer.rs │ ├── frame_size.rs │ ├── image_render.rs │ ├── mod.rs │ ├── render_frame.rs │ ├── render_slice.rs │ ├── render_source_trait.rs │ ├── render_target_trait.rs │ ├── renderer.rs │ ├── rgba_frame.rs │ ├── scanline_renderer.rs │ ├── terminal_render.rs │ ├── u16_linear_frame_renderer.rs │ ├── u32_frame_renderer.rs │ └── u8_frame_renderer.rs └── scanplan │ ├── alpha_coverage.rs │ ├── background_scan_planner.rs │ ├── buffer_stack.rs │ ├── debug_ypos_scan_planner.rs │ ├── intercept_blend.rs │ ├── mod.rs │ ├── pixel_scan_planner.rs │ ├── scan_planner.rs │ ├── scanline_intercept.rs │ ├── scanline_plan.rs │ ├── scanline_shard_intercept.rs │ ├── scanline_transform.rs │ ├── scanspan.rs │ ├── shard.rs │ ├── shard_scan_planner.rs │ └── shard_subpixel.rs ├── test_data ├── Lato-Bold.ttf ├── Lato-Regular.ttf └── Lato-license.md └── tests ├── apex_tests.rs ├── bezier_subpath_edge_tests.rs ├── canvas_render_tests.rs ├── clip_edge_tests.rs ├── edge_plan_render_tests.rs ├── f32_linear_pixel_tests.rs ├── filter_tests.rs ├── mascot_tests.rs ├── pixel_planner_tests.rs ├── polyline_edge_tests.rs ├── scanline_plan_tests.rs ├── shard_scan_planner_tests.rs ├── shard_tests.rs ├── texture_tests.rs └── u32_linear_pixel_tests.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/target 2 | **/target-* 3 | */**/Cargo.lock 4 | */**/xcuserdata/** 5 | *.xcworkspace 6 | *.xcscheme 7 | *.flo 8 | .DS_Store 9 | triangle.png 10 | flo.png 11 | etc 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "canvas", 5 | "canvas_events", 6 | "render", 7 | "render_canvas", 8 | "render_software", 9 | "render_gl_offscreen", 10 | "draw", 11 | ] 12 | 13 | [workspace.dependencies] 14 | wgpu = "24" 15 | wgpu-profiler = "0.22" 16 | 17 | [patch.crates-io] 18 | flo_canvas = { path = "./canvas" } 19 | flo_canvas_events = { path = "./canvas_events" } 20 | flo_render = { path = "./render" } 21 | flo_render_canvas = { path = "./render_canvas" } 22 | flo_render_gl_offscreen = { path = "./render_gl_offscreen" } 23 | flo_render_software = { path = "./render_software" } 24 | flo_draw = { path = "./draw" } 25 | 26 | flo_curves = { git = "https://github.com/Logicalshift/flo_curves", branch = "v0.8" } 27 | flo_binding = { git = "https://github.com/Logicalshift/flo_binding", branch = "v3.0" } 28 | flo_scene = { git = "https://github.com/Logicalshift/flo_scene", branch = "v0.2" } 29 | flo_scene_guest = { git = "https://github.com/Logicalshift/flo_scene", branch = "v0.2" } 30 | desync = { git = "https://github.com/Logicalshift/desync", branch = "v0.9" } 31 | 32 | #naga = { path = "../../src/wgpu/naga" } 33 | #wgpu = { path = "../../src/wgpu/wgpu" } 34 | #wgpu-core = { path = "../../src/wgpu/wgpu-core" } 35 | #wgpu-hal = { path = "../../src/wgpu/wgpu-hal"} 36 | #wgpu-info = { path = "../../src/wgpu/wgpu-info"} 37 | #wgpu-macros = { path = "../../src/wgpu/wgpu-macros"} 38 | #wgpu-types = { path = "../../src/wgpu/wgpu-types"} 39 | 40 | # allsorts is very slow when built for debug, so packages using flo_draw should consider optimising it even in debug builds 41 | [profile.dev.package.allsorts] 42 | opt-level = 2 43 | 44 | [profile.dev.package.wgpu] 45 | opt-level = 2 46 | 47 | [profile.dev.package.lyon] 48 | opt-level = 2 49 | 50 | [profile.release] 51 | debug = 1 52 | -------------------------------------------------------------------------------- /THANKS.md: -------------------------------------------------------------------------------- 1 | Thankyou to everyone who has contributed to this library and to the authors of 2 | the crates that flo_draw depends on. 3 | 4 | Apika Luca (https://github.com/Brayan-724): bug reports and code contributions 5 | Ales Tsurko (https://github.com/ales-tsurko): bug reports, suggestions and code contributions 6 | -------------------------------------------------------------------------------- /canvas/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flo_canvas" 3 | version = "0.4.0" 4 | authors = ["Andrew Hunter"] 5 | license = "Apache-2.0" 6 | edition = "2018" 7 | readme = "README.md" 8 | categories = [ "graphics", "rendering::data-formats" ] 9 | repository = "https://github.com/Logicalshift/flo_draw" 10 | description = "Library for describing graphics context drawing actions without requiring a specific implementation" 11 | 12 | include = [ "Cargo.toml", "src/**/*", "test_data/**/*", "README.md" ] 13 | 14 | [features] 15 | outline-fonts = [ "allsorts", "ttf-parser", "pathfinder_geometry" ] 16 | image-loading = [ "image" ] 17 | scenery = [ "flo_scene" ] 18 | 19 | [dependencies] 20 | flo_curves = "0.8" 21 | flo_stream = "0.7" 22 | flo_scene = { version = "0.2", optional = true } 23 | uuid = { version = "1.0", features = [ "v4", "serde" ] } 24 | 25 | futures = "0.3" 26 | desync = "0.9" 27 | once_cell = "1.18" 28 | rust-hsluv = "0.1" 29 | itertools = "0.14" 30 | serde = { version = "1.0", features = [ "rc" ] } 31 | serde_derive = "1.0" 32 | allsorts = { version = "0.15", optional = true } 33 | ttf-parser = { version = "0.25", optional = true } 34 | pathfinder_geometry = { version = "0.5", optional = true } 35 | image = { version = "0.25", optional = true } 36 | smallvec = "1.6" 37 | ouroboros = "0.18" 38 | 39 | [dev-dependencies] 40 | serde_json = "1.0" 41 | -------------------------------------------------------------------------------- /canvas/README.md: -------------------------------------------------------------------------------- 1 | ```toml 2 | flo_canvas = "0.4" 3 | ``` 4 | 5 | # flo_canvas 6 | 7 | `flo_canvas` is a library that provides a way to describe 2D drawings, without providing any 8 | concrete implementation of how those drawings should be rendered. It supports streaming updates 9 | to allow canvases to be displayed in any user interface library that understands the `Draw` 10 | instructions, and it provides a serialization and deserialization mechanism for sending canvas 11 | instructions to other applications. 12 | 13 | This library was designed to support FlowBetween, an interactive animation editor. However, 14 | it has several implementations that make it useful outside that context. In particular, the 15 | `flo_draw` crate provides a straightforward way to render canvases into a window. `flo_render` 16 | and `flo_render_canvas` combine to provide a general-purpose way of rendering 2D canvases using 17 | modern 3D-accellerated graphics hardware: this includes the ability to render canvases 18 | off-screen to a bitmap on Linux, OS X and Windows systems. 19 | 20 | FlowBetween itself has some implementations that are not quite so accessible but may still be 21 | of interest. In particular `canvas.js` provides an implementation of `flo_canvas` in javascript, 22 | suitable for rendering to a HTML canvas. 23 | -------------------------------------------------------------------------------- /canvas/src/conversion_streams/mod.rs: -------------------------------------------------------------------------------- 1 | mod path_stream; 2 | pub use self::path_stream::*; 3 | 4 | 5 | #[cfg(feature = "outline-fonts")] mod glyph_layout; 6 | #[cfg(feature = "outline-fonts")] mod outline_fonts; 7 | 8 | #[cfg(feature = "outline-fonts")] pub use self::glyph_layout::*; 9 | #[cfg(feature = "outline-fonts")] pub use self::outline_fonts::*; 10 | 11 | mod dashed_lines; 12 | 13 | pub use self::dashed_lines::*; 14 | -------------------------------------------------------------------------------- /canvas/src/path.rs: -------------------------------------------------------------------------------- 1 | use super::draw::*; 2 | 3 | /// 4 | /// Operations that define paths 5 | /// 6 | #[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] 7 | pub enum PathOp { 8 | /// Begins a new path 9 | NewPath, 10 | 11 | /// Move to a new point 12 | Move(f32, f32), 13 | 14 | /// Line to point 15 | Line(f32, f32), 16 | 17 | /// Bezier curve to point 18 | BezierCurve(((f32, f32), (f32, f32)), (f32, f32)), 19 | 20 | /// Closes the current subpath 21 | ClosePath, 22 | } 23 | 24 | impl Into for PathOp { 25 | #[inline] 26 | fn into(self) -> Draw { 27 | Draw::Path(self) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /canvas/src/scenery/drawing_request.rs: -------------------------------------------------------------------------------- 1 | use crate::draw::*; 2 | 3 | use flo_scene::*; 4 | use serde::*; 5 | 6 | use std::sync::*; 7 | 8 | /// 9 | /// A request to a 2D drawing target 10 | /// 11 | #[derive(Debug, Clone)] 12 | #[derive(Serialize, Deserialize)] 13 | pub enum DrawingRequest { 14 | /// Perform the specified drawing actions 15 | Draw(Arc>), 16 | } 17 | 18 | impl SceneMessage for DrawingRequest { } 19 | -------------------------------------------------------------------------------- /canvas/src/scenery/mod.rs: -------------------------------------------------------------------------------- 1 | mod drawing_request; 2 | /* mod sprite_properties; */ 3 | 4 | pub use drawing_request::*; 5 | /* pub use sprite_properties::*; */ 6 | -------------------------------------------------------------------------------- /canvas/src/sprite.rs: -------------------------------------------------------------------------------- 1 | /// 2 | /// Identifier of a canvas 'sprite' 3 | /// 4 | /// A 'sprite' is just a placeholder for a set of pre-rendered actions (it's useful for things like 5 | /// images or drawings that are expected to repeat). Sprites survive layer and canvas clears so they 6 | /// can be re-used repeatedly. The drawing layer may cache these actions in order to render the sprite 7 | /// quickly. 8 | /// 9 | /// Sprites are also faster to draw when rendering to a remote surface as they only need to be sent 10 | /// across once before they can be re-rendered as often as necessary. 11 | /// 12 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] 13 | pub struct SpriteId(pub u64); 14 | 15 | /// 16 | /// A position within a sprite 17 | /// 18 | #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] 19 | pub struct SpritePosition(pub f32, pub f32); 20 | 21 | /// 22 | /// A size within a sprite 23 | /// 24 | #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] 25 | pub struct SpriteSize(pub f32, pub f32); 26 | 27 | /// 28 | /// A bounding box within a sprite 29 | /// 30 | #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] 31 | pub struct SpriteBounds(pub SpritePosition, pub SpriteSize); 32 | -------------------------------------------------------------------------------- /canvas/test_data/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/canvas/test_data/Lato-Regular.ttf -------------------------------------------------------------------------------- /canvas/test_data/Lato-license.md: -------------------------------------------------------------------------------- 1 | Lato is included under the Open Font License (https://scripts.sil.org/OFL). 2 | It has an official site here: https://www.latofonts.com/ 3 | 4 | It is incorporated into flo_canvas when built for testing, but is not present in debug or 5 | release builds. 6 | -------------------------------------------------------------------------------- /canvas/tests/readme.rs: -------------------------------------------------------------------------------- 1 | use std::str; 2 | 3 | /// 4 | /// Reads the README file for the crate 5 | /// 6 | fn readme() -> &'static str { 7 | let readme_bytes = include_bytes!("../README.md"); 8 | let readme_str = str::from_utf8(readme_bytes); 9 | 10 | readme_str.expect("Could not decode README.md") 11 | } 12 | 13 | #[test] 14 | fn starts_with_version_number_toml() { 15 | let major_version = env!("CARGO_PKG_VERSION_MAJOR"); 16 | let minor_version = env!("CARGO_PKG_VERSION_MINOR"); 17 | 18 | let expected = format!("```toml 19 | flo_canvas = \"{}.{}\" 20 | ```", major_version, minor_version); 21 | 22 | println!("{}", expected); 23 | assert!(readme().starts_with(&expected)); 24 | } 25 | -------------------------------------------------------------------------------- /canvas_events/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flo_canvas_events" 3 | version = "0.4.0" 4 | authors = ["Andrew Hunter"] 5 | license = "Apache-2.0" 6 | edition = "2018" 7 | repository = "https://github.com/Logicalshift/flo_draw" 8 | description = "User input events for a flo_draw canvas" 9 | categories = [ "graphics", "rendering", "gui" ] 10 | 11 | [dependencies] 12 | flo_canvas = { version = "0.4", features = [ "scenery" ] } 13 | flo_render = "0.4" 14 | flo_scene = "0.2" 15 | serde = "1.0" 16 | -------------------------------------------------------------------------------- /canvas_events/src/draw_event.rs: -------------------------------------------------------------------------------- 1 | use crate::key::*; 2 | use crate::pointer_event::*; 3 | 4 | use flo_canvas::*; 5 | use flo_scene::*; 6 | 7 | /// 8 | /// Events that can arrive from a flo_draw window 9 | /// 10 | #[derive(Clone, PartialEq, Debug)] 11 | #[derive(serde::Serialize, serde::Deserialize)] 12 | pub enum DrawEvent { 13 | /// Request to re-render the window (this is automatic for canvas windows) 14 | Redraw, 15 | 16 | /// Indicates that a frame has finished rendering to the canvas 17 | NewFrame, 18 | 19 | /// The window has a new scale 20 | Scale(f64), 21 | 22 | /// Window has a new size 23 | Resize(f64, f64), 24 | 25 | /// Canvas transformation for the window has changed (this will convert between window coordinates and canvas coordinates) 26 | CanvasTransform(Transform2D), 27 | 28 | /// A pointer device has changed its state 29 | Pointer(PointerAction, PointerId, PointerState), 30 | 31 | /// The user has pressed a key (parameters are scancode and the name of the key that was pressed, if known) 32 | KeyDown(u64, Option), 33 | 34 | /// The user has released a key (parameters are scancode and the name of the key that was pressed, if known) 35 | KeyUp(u64, Option), 36 | 37 | /// Window has been closed 38 | Closed 39 | } 40 | 41 | impl SceneMessage for DrawEvent { } 42 | -------------------------------------------------------------------------------- /canvas_events/src/draw_event_request.rs: -------------------------------------------------------------------------------- 1 | use super::draw_event::*; 2 | 3 | /// Draw events are already specified in the flo_canvas_evevents library and are sent singly so this is just an alias for that type 4 | pub type DrawEventRequest = DrawEvent; 5 | -------------------------------------------------------------------------------- /canvas_events/src/key.rs: -------------------------------------------------------------------------------- 1 | /// 2 | /// Represents a key 3 | /// 4 | #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)] 5 | #[derive(serde::Serialize, serde::Deserialize)] 6 | pub enum Key { 7 | Unknown, 8 | 9 | ModifierShift, 10 | ModifierCtrl, 11 | ModifierAlt, 12 | ModifierMeta, 13 | ModifierSuper, 14 | ModifierHyper, 15 | 16 | KeyTab, 17 | 18 | KeyA, 19 | KeyB, 20 | KeyC, 21 | KeyD, 22 | KeyE, 23 | KeyF, 24 | KeyG, 25 | KeyH, 26 | KeyI, 27 | KeyJ, 28 | KeyK, 29 | KeyL, 30 | KeyM, 31 | KeyN, 32 | KeyO, 33 | KeyP, 34 | KeyQ, 35 | KeyR, 36 | KeyS, 37 | KeyT, 38 | KeyU, 39 | KeyV, 40 | KeyW, 41 | KeyX, 42 | KeyY, 43 | KeyZ, 44 | 45 | Key1, 46 | Key2, 47 | Key3, 48 | Key4, 49 | Key5, 50 | Key6, 51 | Key7, 52 | Key8, 53 | Key9, 54 | Key0, 55 | 56 | KeyUp, 57 | KeyDown, 58 | KeyLeft, 59 | KeyRight, 60 | 61 | KeyBackslash, 62 | KeyForwardslash, 63 | KeyBacktick, 64 | KeyComma, 65 | KeyFullstop, 66 | KeySemicolon, 67 | KeyQuote, 68 | KeyMinus, 69 | KeyEquals, 70 | 71 | KeySpace, 72 | KeyEscape, 73 | KeyInsert, 74 | KeyHome, 75 | KeyPgUp, 76 | KeyDelete, 77 | KeyEnd, 78 | KeyPgDown, 79 | KeyBackspace, 80 | KeyEnter, 81 | 82 | KeyF1, 83 | KeyF2, 84 | KeyF3, 85 | KeyF4, 86 | KeyF5, 87 | KeyF6, 88 | KeyF7, 89 | KeyF8, 90 | KeyF9, 91 | KeyF10, 92 | KeyF11, 93 | KeyF12, 94 | KeyF13, 95 | KeyF14, 96 | KeyF15, 97 | KeyF16, 98 | 99 | KeyNumpad0, 100 | KeyNumpad1, 101 | KeyNumpad2, 102 | KeyNumpad3, 103 | KeyNumpad4, 104 | KeyNumpad5, 105 | KeyNumpad6, 106 | KeyNumpad7, 107 | KeyNumpad8, 108 | KeyNumpad9, 109 | KeyNumpadDivide, 110 | KeyNumpadMultiply, 111 | KeyNumpadMinus, 112 | KeyNumpadAdd, 113 | KeyNumpadEnter, 114 | KeyNumpadDecimal, 115 | } 116 | -------------------------------------------------------------------------------- /canvas_events/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! 2 | //! # Events 3 | //! 4 | //! `flo_draw` is currently based on glutin, but uses its own event structure: this is to make it so that 5 | //! it's possible for future versions to replace glutin easily if that ever proves to be necessary, and 6 | //! to support easy porting of code using `flo_draw` to other windowing systems. This also isolates software 7 | //! implemented using `flo_draw` from changes to glutin. 8 | //! 9 | 10 | mod key; 11 | mod draw_event; 12 | mod pointer_event; 13 | 14 | mod render_request; 15 | mod draw_event_request; 16 | 17 | mod draw_window_request; 18 | 19 | pub use self::key::*; 20 | pub use self::draw_event::*; 21 | pub use self::pointer_event::*; 22 | 23 | pub use self::render_request::*; 24 | pub use self::draw_event_request::*; 25 | 26 | pub use self::draw_window_request::*; 27 | -------------------------------------------------------------------------------- /canvas_events/src/render_request.rs: -------------------------------------------------------------------------------- 1 | use flo_render::*; 2 | use flo_scene::*; 3 | 4 | /// 5 | /// A request to a low-level render target 6 | /// 7 | #[derive(Debug)] 8 | #[derive(serde::Serialize, serde::Deserialize)] 9 | pub enum RenderRequest { 10 | /// Performs the specified set of render actions immediately 11 | Render(Vec) 12 | } 13 | 14 | impl SceneMessage for RenderRequest { 15 | } 16 | -------------------------------------------------------------------------------- /draw/examples/Lato-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/examples/Lato-Bold.ttf -------------------------------------------------------------------------------- /draw/examples/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/examples/Lato-Regular.ttf -------------------------------------------------------------------------------- /draw/examples/Lato-license.md: -------------------------------------------------------------------------------- 1 | Lato is included under the Open Font License (https://scripts.sil.org/OFL). 2 | It has an official site here: https://www.latofonts.com/ 3 | -------------------------------------------------------------------------------- /draw/examples/canvas_window.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_canvas::*; 3 | 4 | /// 5 | /// Simple example that displays a canvas window and renders a triangle 6 | /// 7 | pub fn main() { 8 | // 'with_2d_graphics' is used to support operating systems that can't run event loops anywhere other than the main thread 9 | with_2d_graphics(|| { 10 | // Create a window 11 | let canvas = create_drawing_window("Canvas window"); 12 | 13 | // Render a triangle to it 14 | canvas.draw(|gc| { 15 | // Clear the canvas and set up the coordinates 16 | gc.clear_canvas(Color::Rgba(0.3, 0.2, 0.0, 1.0)); 17 | gc.canvas_height(1000.0); 18 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 19 | 20 | // Draw a rectangle... 21 | gc.new_path(); 22 | gc.move_to(0.0, 0.0); 23 | gc.line_to(1000.0, 0.0); 24 | gc.line_to(1000.0, 1000.0); 25 | gc.line_to(0.0, 1000.0); 26 | gc.line_to(0.0, 0.0); 27 | 28 | gc.fill_color(Color::Rgba(1.0, 1.0, 0.8, 1.0)); 29 | gc.fill(); 30 | 31 | // Draw a triangle on top 32 | gc.new_path(); 33 | gc.move_to(200.0, 200.0); 34 | gc.line_to(800.0, 200.0); 35 | gc.line_to(500.0, 800.0); 36 | gc.line_to(200.0, 200.0); 37 | 38 | gc.fill_color(Color::Rgba(0.0, 0.0, 0.8, 1.0)); 39 | gc.fill(); 40 | }); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /draw/examples/circle.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_canvas::*; 3 | 4 | /// 5 | /// Displays a filled circle 6 | /// 7 | pub fn main() { 8 | with_2d_graphics(|| { 9 | // Create a window 10 | let canvas = create_drawing_window("Circle"); 11 | 12 | // Draw a circle 13 | canvas.draw(|gc| { 14 | // Set up the canvas 15 | gc.canvas_height(1000.0); 16 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 17 | 18 | // Draw a circle 19 | gc.new_path(); 20 | gc.circle(500.0, 500.0, 250.0); 21 | 22 | gc.fill_color(Color::Rgba(0.3, 0.6, 0.8, 1.0)); 23 | gc.fill(); 24 | 25 | gc.line_width(6.0); 26 | gc.stroke_color(Color::Rgba(0.0, 0.0, 0.0, 1.0)); 27 | gc.stroke(); 28 | }); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /draw/examples/clip.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_draw::canvas::*; 3 | 4 | /// 5 | /// Demonstrates using a clipping path 6 | /// 7 | pub fn main() { 8 | with_2d_graphics(|| { 9 | // Create a window 10 | let canvas = create_drawing_window("Clipping demonstration"); 11 | 12 | // Clip a large path using a circular clipping path 13 | canvas.draw(|gc| { 14 | // Set up the canvas 15 | gc.clear_canvas(Color::Rgba(0.95, 1.0, 0.9, 1.0)); 16 | gc.canvas_height(1000.0); 17 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 18 | 19 | gc.new_path(); 20 | gc.rect(800.0, 800.0, 900.0, 900.0); 21 | gc.fill_color(Color::Rgba(0.6, 0.0, 0.0, 1.0)); 22 | gc.fill(); 23 | 24 | gc.new_path(); 25 | gc.circle(500.0, 500.0, 200.0); 26 | gc.circle(150.0, 850.0, 100.0); 27 | gc.clip(); 28 | 29 | gc.new_path(); 30 | gc.rect(0.0, 0.0, 1000.0, 1000.0); 31 | gc.fill_color(Color::Rgba(0.0, 0.0, 0.6, 1.0)); 32 | gc.fill(); 33 | 34 | gc.new_path(); 35 | gc.move_to(0.0, 1000.0); 36 | gc.line_to(1000.0, 0.0); 37 | gc.stroke_color(Color::Rgba(0.0, 0.6, 0.0, 1.0)); 38 | gc.line_width(16.0); 39 | gc.stroke(); 40 | 41 | gc.unclip(); 42 | 43 | gc.new_path(); 44 | gc.rect(100.0, 100.0, 200.0, 200.0); 45 | gc.fill_color(Color::Rgba(0.6, 0.0, 0.0, 1.0)); 46 | gc.fill(); 47 | }); 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /draw/examples/dashed_line.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_draw::canvas::*; 3 | 4 | use std::thread; 5 | use std::time::{Duration}; 6 | 7 | /// 8 | /// Draws a dashed line 9 | /// 10 | pub fn main() { 11 | with_2d_graphics(|| { 12 | // Create a window 13 | let canvas = create_drawing_window("Dashed line"); 14 | 15 | let mut offset = 0.0; 16 | loop { 17 | canvas.draw(|gc| { 18 | gc.clear_canvas(Color::Rgba(1.0, 1.0, 1.0, 1.0)); 19 | 20 | // Set up the canvas 21 | gc.canvas_height(1000.0); 22 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 23 | 24 | gc.line_width(8.0); 25 | gc.new_dash_pattern(); 26 | gc.dash_offset(offset % 60.0); 27 | gc.dash_length(20.0); 28 | gc.dash_length(10.0); 29 | gc.dash_length(20.0); 30 | gc.dash_length(10.0); 31 | gc.stroke_color(Color::Rgba(0.0, 0.0, 0.6, 1.0)); 32 | 33 | gc.new_path(); 34 | gc.rect(100.0, 100.0, 900.0, 900.0); 35 | gc.stroke(); 36 | 37 | gc.new_path(); 38 | gc.move_to(200.0, 200.0); 39 | gc.line_to(800.0, 800.0); 40 | gc.stroke(); 41 | 42 | gc.new_path(); 43 | gc.circle(300.0, 700.0, 100.0); 44 | gc.stroke(); 45 | 46 | gc.new_path(); 47 | gc.circle(700.0, 300.0, 100.0); 48 | gc.fill(); 49 | }); 50 | 51 | offset += 1.0; 52 | thread::sleep(Duration::from_nanos(1_000_000_000 / 60)); 53 | } 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /draw/examples/erase.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_canvas::*; 3 | 4 | use std::sync::*; 5 | 6 | /// 7 | /// Erases 'Hello, World' from a rectangle to allow the background to show through 8 | /// 9 | pub fn main() { 10 | with_2d_graphics(|| { 11 | let lato = CanvasFontFace::from_slice(include_bytes!("Lato-Regular.ttf")); 12 | 13 | // Create a window 14 | let canvas = create_drawing_window("Hello"); 15 | 16 | let hello_size = measure_text(&lato, "Hello, World", 100.0); 17 | let (min, max) = hello_size.inner_bounds; 18 | 19 | let x_pos = (1000.0 - (max.x()-min.x()))/2.0; 20 | let y_pos = (1000.0 - (max.y()-min.y()))/2.0; 21 | 22 | // Say 'hello, world' 23 | canvas.draw(|gc| { 24 | // Set up the canvas 25 | gc.canvas_height(1000.0); 26 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 27 | 28 | gc.layer(LayerId(2)); 29 | 30 | // Draw a rectangle 31 | gc.new_path(); 32 | gc.rect(100.0, 100.0, 900.0, 900.0); 33 | gc.fill_color(Color::Rgba(0.0, 0.0, 0.6, 1.0)); 34 | gc.fill(); 35 | 36 | // Load a font 37 | gc.define_font_data(FontId(1), Arc::clone(&lato)); 38 | gc.set_font_size(FontId(1), 100.0); 39 | 40 | // Erase a hole in our text 41 | gc.blend_mode(BlendMode::DestinationOut); 42 | gc.fill_color(Color::Rgba(0.0, 0.0, 0.0, 1.0)); 43 | gc.draw_text(FontId(1), "Hello, World".to_string(), x_pos as _, y_pos as _); 44 | gc.blend_mode(BlendMode::SourceOver); 45 | 46 | // Draw a line underneath (it will show through the erased section) 47 | gc.layer(LayerId(1)); 48 | gc.new_path(); 49 | gc.rect(300.0, 450.0, 700.0, 490.0); 50 | gc.fill_color(Color::Rgba(0.6, 0.0, 0.0, 1.0)); 51 | gc.fill(); 52 | }); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /draw/examples/flo_and_carrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/examples/flo_and_carrot.png -------------------------------------------------------------------------------- /draw/examples/flo_drawing_on_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/examples/flo_drawing_on_window.png -------------------------------------------------------------------------------- /draw/examples/hello_world.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_canvas::*; 3 | 4 | use std::sync::*; 5 | 6 | /// 7 | /// Displays 'Hello, World' in a window 8 | /// 9 | pub fn main() { 10 | with_2d_graphics(|| { 11 | let lato = CanvasFontFace::from_slice(include_bytes!("Lato-Regular.ttf")); 12 | 13 | // Create a window 14 | let canvas = create_drawing_window("Hello"); 15 | 16 | let hello_size = measure_text(&lato, "Hello, World", 100.0); 17 | let (min, max) = hello_size.inner_bounds; 18 | 19 | let x_pos = (1000.0 - (max.x()-min.x()))/2.0; 20 | let y_pos = (1000.0 - (max.y()-min.y()))/2.0; 21 | 22 | // Say 'hello, world' 23 | canvas.draw(|gc| { 24 | // Set up the canvas 25 | gc.canvas_height(1000.0); 26 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 27 | 28 | // Load a font 29 | gc.define_font_data(FontId(1), Arc::clone(&lato)); 30 | gc.set_font_size(FontId(1), 100.0); 31 | 32 | // Draw some text in our font 33 | gc.fill_color(Color::Rgba(0.0, 0.0, 0.6, 1.0)); 34 | gc.draw_text(FontId(1), "Hello, World".to_string(), x_pos as _, y_pos as _); 35 | }); 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /draw/examples/layer_reorder.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_canvas::*; 3 | 4 | use std::thread; 5 | use std::time::{Duration}; 6 | 7 | use rand::*; 8 | 9 | pub fn main() { 10 | with_2d_graphics(|| { 11 | // Create a window with a canvas to draw on 12 | let canvas = create_drawing_window("Reordering layers"); 13 | let lato_bold = CanvasFontFace::from_slice(include_bytes!("Lato-Bold.ttf")); 14 | 15 | canvas.draw(|gc| { 16 | gc.clear_canvas(Color::Rgba(0.5, 0.8, 1.0, 1.0)); 17 | gc.canvas_height(1000.0); 18 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 19 | 20 | gc.define_font_data(FontId(1), lato_bold); 21 | gc.set_font_size(FontId(1), 1000.0); 22 | 23 | gc.layer(LayerId(0)); 24 | gc.fill_color(Color::Rgba(0.0, 0.0, 0.6, 1.0)); 25 | 26 | gc.begin_line_layout(500.0, 150.0, TextAlignment::Center); 27 | gc.layout_text(FontId(1), "A".to_string()); 28 | gc.draw_text_layout(); 29 | 30 | gc.layer(LayerId(1)); 31 | gc.fill_color(Color::Rgba(0.0, 0.6, 0.0, 1.0)); 32 | 33 | gc.begin_line_layout(500.0, 150.0, TextAlignment::Center); 34 | gc.layout_text(FontId(1), "B".to_string()); 35 | gc.draw_text_layout(); 36 | 37 | gc.layer(LayerId(2)); 38 | gc.fill_color(Color::Rgba(0.8, 0.8, 0.0, 1.0)); 39 | 40 | gc.begin_line_layout(500.0, 150.0, TextAlignment::Center); 41 | gc.layout_text(FontId(1), "C".to_string()); 42 | gc.draw_text_layout(); 43 | }); 44 | 45 | loop { 46 | thread::sleep(Duration::from_secs(2)); 47 | 48 | let first_layer = random_range(0..3); 49 | let second_layer = random_range(0..3); 50 | 51 | println!("{:?} before {:?}", second_layer, first_layer); 52 | 53 | canvas.draw(|gc| { 54 | gc.layer(LayerId(first_layer)); 55 | gc.place_layer_before(NamespaceId::default(), LayerId(second_layer)); 56 | }) 57 | } 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /draw/examples/mirror_windows.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_draw::canvas::*; 3 | 4 | use futures::prelude::*; 5 | 6 | use std::thread; 7 | use std::time::{Duration}; 8 | 9 | /// 10 | /// Draws to two windows simultaneously 11 | /// 12 | pub fn main() { 13 | with_2d_graphics(|| { 14 | // Create a canvas window: canvases store their drawing instructions and can mirror them to multiple targets 15 | let canvas = create_canvas_window("Mirror windows"); 16 | 17 | // Create a duplicate window from the same canvas (gluting creates windows on top of each other, annoyingly) 18 | let _ = create_drawing_window_from_stream(canvas.stream().ready_chunks(10000), "Second window (might need to drag to see the other window)"); 19 | 20 | // Draw to both windows at once 21 | let mut p = 0.0f32; 22 | loop { 23 | p += 0.02; 24 | 25 | canvas.draw(|gc| { 26 | gc.clear_canvas(Color::Rgba(1.0, 1.0, 1.0, 1.0)); 27 | 28 | gc.canvas_height(1000.0); 29 | 30 | let x = p.sin() * 500.0; 31 | let y = (p*3.0).cos() * 200.0; 32 | 33 | gc.new_path(); 34 | gc.circle(x, y, 50.0); 35 | gc.fill_color(Color::Rgba(0.7, 0.0, 0.0, 1.0)); 36 | gc.fill(); 37 | }); 38 | 39 | // 60fps 40 | thread::sleep(Duration::from_nanos(1_000_000_000 / 60)); 41 | } 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /draw/examples/sprite.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_canvas::*; 3 | 4 | /// 5 | /// Simple example that displays a canvas window and renders a triangle 6 | /// 7 | pub fn main() { 8 | with_2d_graphics(|| { 9 | // Create a window 10 | let canvas = create_drawing_window("Basic sprite rendering"); 11 | 12 | // Sprites are a way to rapidly repeat a set of drawing instructions 13 | canvas.draw(|gc| { 14 | // Clear the canvas and set up the coordinates 15 | gc.clear_canvas(Color::Rgba(0.0, 1.0, 0.0, 1.0)); 16 | gc.canvas_height(1000.0); 17 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 18 | 19 | // Create a triangle sprite 20 | gc.sprite(SpriteId(0)); 21 | gc.clear_sprite(); 22 | gc.new_path(); 23 | gc.move_to(200.0, 200.0); 24 | gc.line_to(800.0, 200.0); 25 | gc.line_to(500.0, 800.0); 26 | gc.line_to(200.0, 200.0); 27 | 28 | gc.fill_color(Color::Rgba(0.8, 0.4, 0.2, 1.0)); 29 | gc.fill(); 30 | 31 | // Draw the triangle in a few places 32 | gc.layer(LayerId(0)); 33 | 34 | gc.sprite_transform(SpriteTransform::Identity); 35 | gc.draw_sprite(SpriteId(0)); 36 | 37 | gc.sprite_transform(SpriteTransform::Identity); 38 | gc.sprite_transform(SpriteTransform::Scale(0.5, 0.5)); 39 | gc.draw_sprite(SpriteId(0)); 40 | 41 | gc.sprite_transform(SpriteTransform::Identity); 42 | gc.sprite_transform(SpriteTransform::Rotate(30.0)); 43 | gc.draw_sprite(SpriteId(0)); 44 | 45 | gc.sprite_transform(SpriteTransform::Identity); 46 | gc.sprite_transform(SpriteTransform::Translate(100.0, 100.0)); 47 | gc.draw_sprite(SpriteId(0)); 48 | 49 | gc.sprite_transform(SpriteTransform::Identity); 50 | gc.sprite_transform(SpriteTransform::Translate(200.0, 100.0)); 51 | gc.draw_sprite(SpriteId(0)); 52 | 53 | gc.sprite_transform(SpriteTransform::Identity); 54 | gc.sprite_transform(SpriteTransform::Transform2D(Transform2D::translate(300.0, 100.0))); 55 | gc.draw_sprite(SpriteId(0)); 56 | }); 57 | }); 58 | } 59 | -------------------------------------------------------------------------------- /draw/examples/texture.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_draw::canvas::*; 3 | 4 | use std::io; 5 | 6 | /// 7 | /// Simple example that displays a canvas window and renders an image from a png file 8 | /// 9 | pub fn main() { 10 | // 'with_2d_graphics' is used to support operating systems that can't run event loops anywhere other than the main thread 11 | with_2d_graphics(|| { 12 | // Load a png file 13 | let flo_bytes: &[u8] = include_bytes!["flo_drawing_on_window.png"]; 14 | 15 | // Create a window 16 | let canvas = create_drawing_window("Flo drawing on a window"); 17 | 18 | // Render the png to the window 19 | canvas.draw(|gc| { 20 | // Clear the canvas and set up the coordinates 21 | gc.clear_canvas(Color::Rgba(1.0, 1.0, 1.0, 1.0)); 22 | gc.canvas_height(1000.0); 23 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 24 | 25 | // Set up the texture 26 | let (flo_w, flo_h) = gc.load_texture(TextureId(0), io::Cursor::new(flo_bytes)).unwrap(); 27 | 28 | let ratio = (flo_w as f32)/(flo_h as f32); 29 | let height = 1000.0 / ratio; 30 | let y_pos = (1000.0-height)/2.0; 31 | 32 | // Draw a rectangle... 33 | gc.new_path(); 34 | gc.rect(0.0, y_pos, 1000.0, y_pos+height); 35 | 36 | // Fill with the texture we just loaded 37 | gc.fill_texture(TextureId(0), 0.0, y_pos+height as f32, 1000.0, y_pos); 38 | gc.fill(); 39 | }); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /draw/examples/update_title.rs: -------------------------------------------------------------------------------- 1 | use flo_draw::*; 2 | use flo_canvas::*; 3 | use flo_binding::*; 4 | 5 | use std::thread; 6 | use std::time::{Duration}; 7 | 8 | /// 9 | /// Simple example that displays a canvas window, then updates the title once a second 10 | /// 11 | pub fn main() { 12 | // 'with_2d_graphics' is used to support operating systems that can't run event loops anywhere other than the main thread 13 | with_2d_graphics(|| { 14 | // Create some window properties with a title binding 15 | let title = bind("Title".to_string()); 16 | let mut window_properties = WindowProperties::from(&()); 17 | 18 | window_properties.title = BindRef::from(title.clone()); 19 | 20 | // Create a window with these properties 21 | let canvas = create_drawing_window(window_properties); 22 | 23 | // Render a triangle to it 24 | canvas.draw(|gc| { 25 | // Clear the canvas and set up the coordinates 26 | gc.clear_canvas(Color::Rgba(0.3, 0.2, 0.0, 1.0)); 27 | gc.canvas_height(1000.0); 28 | gc.center_region(0.0, 0.0, 1000.0, 1000.0); 29 | 30 | // Draw a rectangle... 31 | gc.new_path(); 32 | gc.move_to(0.0, 0.0); 33 | gc.line_to(1000.0, 0.0); 34 | gc.line_to(1000.0, 1000.0); 35 | gc.line_to(0.0, 1000.0); 36 | gc.line_to(0.0, 0.0); 37 | 38 | gc.fill_color(Color::Rgba(1.0, 1.0, 0.8, 1.0)); 39 | gc.fill(); 40 | 41 | // Draw a triangle on top 42 | gc.new_path(); 43 | gc.move_to(200.0, 200.0); 44 | gc.line_to(800.0, 200.0); 45 | gc.line_to(500.0, 800.0); 46 | gc.line_to(200.0, 200.0); 47 | 48 | gc.fill_color(Color::Rgba(0.0, 0.0, 0.8, 1.0)); 49 | gc.fill(); 50 | }); 51 | 52 | // Fairly boring 'update the title once a second' sequence 53 | let mut count = 0; 54 | loop { 55 | thread::sleep(Duration::from_secs(1)); 56 | 57 | count += 1; 58 | title.set(format!("Running for {} seconds", count)); 59 | } 60 | }); 61 | } 62 | -------------------------------------------------------------------------------- /draw/guide_images/s_gradients.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/guide_images/s_gradients.png -------------------------------------------------------------------------------- /draw/guide_images/s_graphics_primitives.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/guide_images/s_graphics_primitives.png -------------------------------------------------------------------------------- /draw/guide_images/s_layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/guide_images/s_layers.png -------------------------------------------------------------------------------- /draw/guide_images/s_sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/guide_images/s_sprites.png -------------------------------------------------------------------------------- /draw/guide_images/s_text_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/guide_images/s_text_layout.png -------------------------------------------------------------------------------- /draw/guide_images/s_text_rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/guide_images/s_text_rendering.png -------------------------------------------------------------------------------- /draw/guide_images/s_textures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/guide_images/s_textures.png -------------------------------------------------------------------------------- /draw/guide_images/s_transforms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/guide_images/s_transforms.png -------------------------------------------------------------------------------- /draw/images/beeb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/images/beeb.png -------------------------------------------------------------------------------- /draw/images/mandelbrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/images/mandelbrot.png -------------------------------------------------------------------------------- /draw/images/mascot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/images/mascot.png -------------------------------------------------------------------------------- /draw/images/wibble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logicalshift/flo_draw/7a8b1613d141f07d0b36e02993e0b195a1b6c25d/draw/images/wibble.png -------------------------------------------------------------------------------- /draw/src/draw_scene/glutin_scene.rs: -------------------------------------------------------------------------------- 1 | use crate::glutin::*; 2 | 3 | use futures::prelude::*; 4 | use once_cell::sync::Lazy; 5 | 6 | use flo_scene::*; 7 | 8 | use std::sync::*; 9 | 10 | /// The scene context used for flo_draw, or None if a scene context has not been created yet 11 | static DRAW_SCENE: Lazy>>> = Lazy::new(|| Mutex::new(None)); 12 | 13 | /// 14 | /// Retrieves or creates a scene for flo_draw 15 | /// 16 | #[allow(dead_code)] 17 | pub fn flo_draw_glutin_scene() -> Arc { 18 | let mut scene = DRAW_SCENE.lock().unwrap(); 19 | 20 | // Start a new scene if none was running 21 | if scene.is_none() { 22 | // Create a new scene, and run it on the glutin thread 23 | let new_scene = Arc::new(Scene::default()); 24 | 25 | // Store as the active scene 26 | *scene = Some(Arc::clone(&new_scene)); 27 | 28 | // Run on the glutin thread 29 | glutin_thread().send_event(GlutinThreadEvent::RunProcess(Box::new(move || async move { 30 | new_scene.run_scene_with_threads(4).await; 31 | }.boxed()))); 32 | } 33 | 34 | // Unwrap the scene context 35 | scene.as_ref().unwrap().clone() 36 | } 37 | -------------------------------------------------------------------------------- /draw/src/draw_scene/mod.rs: -------------------------------------------------------------------------------- 1 | //! 2 | //! The draw_scene module provides an interface to flo_draw using the flo_scene library. 3 | //! 4 | //! `flo_scene` is a message and property passing framework. It's good for developing more complex applications 5 | //! with flo_draw, such as those with a user interface. 6 | //! 7 | //! There are three main types of request: a `RenderRequest` which is a request for low-level graphics operations, 8 | //! a `DrawRequest` which is a request for a high-level 2D graphics operation, and a `DrawEventRequest` which is 9 | //! a request in the other direction to process a user interaction. 10 | //! 11 | //! `DrawWindowRequest` provides a set of requests for interacting directly with the window: this is mainly a way 12 | //! to obtain the events and rendering event channels for a particular window. 13 | //! 14 | 15 | mod render_window_program; 16 | mod drawing_window_program; 17 | mod scene; 18 | 19 | #[cfg(feature="render-opengl")] 20 | mod glutin_render_window_program; 21 | #[cfg(feature="render-opengl")] 22 | mod glutin_scene; 23 | 24 | #[cfg(feature="render-wgpu")] 25 | mod wgpu_render_window_program; 26 | #[cfg(feature="render-wgpu")] 27 | mod wgpu_scene; 28 | 29 | #[cfg(feature="render-software")] 30 | mod software_drawing_window_program; 31 | #[cfg(feature="render-software")] 32 | mod software_scene; 33 | 34 | pub use self::render_window_program::*; 35 | pub use self::drawing_window_program::*; 36 | pub use self::scene::*; 37 | -------------------------------------------------------------------------------- /draw/src/draw_scene/render_window_program.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(feature="render-opengl", not(feature="render-wgpu")))] 2 | use super::glutin_render_window_program::*; 3 | 4 | #[cfg(feature="render-wgpu")] 5 | use super::wgpu_render_window_program::*; 6 | 7 | #[cfg(feature="render-software")] 8 | use super::software_drawing_window_program::*; 9 | 10 | use flo_scene::*; 11 | 12 | use std::sync::*; 13 | 14 | /// 15 | /// Creates a render window in a scene for OpenGL rendering with the specified program ID 16 | /// 17 | #[cfg(all(feature="render-opengl", not(feature="render-wgpu")))] 18 | pub fn create_render_window_sub_program(scene: &Arc, program_id: SubProgramId, initial_size: (u64, u64)) -> Result<(), ConnectionError> { 19 | create_glutin_render_window_program(scene, program_id, initial_size) 20 | } 21 | 22 | /// 23 | /// Creates a render window in a scene for WGPU rendering, with a specified program ID 24 | /// 25 | #[cfg(all(feature="render-wgpu"))] 26 | pub fn create_render_window_sub_program(scene: &Arc, program_id: SubProgramId, initial_size: (u64, u64)) -> Result<(), ConnectionError> { 27 | create_wgpu_render_window_program(scene, program_id, initial_size) 28 | } 29 | 30 | /// 31 | /// Creates a drawing window in a scene for software rendering, with a specified program ID 32 | /// 33 | /// (Note that a drawing window differs from a render window in that it takes canvas drawing instructions directly instead of render actions) 34 | /// 35 | #[cfg(all(feature="render-software", not(any(feature="render-opengl", feature="render-wgpu"))))] 36 | pub fn create_render_window_sub_program(scene: &Arc, program_id: SubProgramId, initial_size: (u64, u64)) -> Result<(), ConnectionError> { 37 | create_software_draw_window_program(scene, program_id, initial_size) 38 | } 39 | 40 | /// 41 | /// Retrieves or creates a scene context for flo_draw 42 | /// 43 | #[cfg(all(not(feature="render-wgpu"), not(feature="render-opengl"), not(feature="render-software")))] 44 | pub fn create_render_window_sub_program(context: &Arc, program_id: SubProgramId, initial_size: (u64, u64)) -> Result<(), ConnectionError> { 45 | panic!("No default renderer was specified when flo_draw was compiled (use `render-wgpu` or `render-opengl`)") 46 | } 47 | -------------------------------------------------------------------------------- /draw/src/draw_scene/scene.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature="render-opengl")] 2 | use super::glutin_scene::*; 3 | 4 | #[cfg(feature="render-wgpu")] 5 | use super::wgpu_scene::*; 6 | 7 | #[cfg(feature="render-software")] 8 | use super::software_scene::*; 9 | 10 | use flo_scene::*; 11 | use std::sync::*; 12 | 13 | /// 14 | /// Retrieves or creates a scene context for flo_draw 15 | /// 16 | #[cfg(all(feature="render-opengl", not(feature="render-wgpu")))] 17 | pub fn flo_draw_scene_context() -> Arc { 18 | flo_draw_glutin_scene() 19 | } 20 | 21 | /// 22 | /// Retrieves or creates a scene context for flo_draw 23 | /// 24 | #[cfg(all(feature="render-wgpu"))] 25 | pub fn flo_draw_scene_context() -> Arc { 26 | flo_draw_wgpu_scene() 27 | } 28 | 29 | 30 | /// 31 | /// Retrieves or creates a scene context for flo_draw 32 | /// 33 | #[cfg(all(feature="render-software", not(any(feature="render-wgpu", feature="render-opengl"))))] 34 | pub fn flo_draw_scene_context() -> Arc { 35 | flo_draw_software_scene() 36 | } 37 | 38 | /// 39 | /// Retrieves or creates a scene context for flo_draw 40 | /// 41 | #[cfg(all(not(feature="render-wgpu"), not(feature="render-opengl"), not(feature="render-software")))] 42 | pub fn flo_draw_scene_context() -> Arc { 43 | panic!("No default renderer was specified when flo_draw was compiled (use `render-wgpu`, `render-opengl` or `render-software`)") 44 | } 45 | -------------------------------------------------------------------------------- /draw/src/draw_scene/software_scene.rs: -------------------------------------------------------------------------------- 1 | use crate::software::*; 2 | 3 | use futures::prelude::*; 4 | use once_cell::sync::{Lazy}; 5 | 6 | use flo_scene::*; 7 | 8 | use std::sync::*; 9 | 10 | /// The scene context used for flo_draw, or None if a scene context has not been created yet 11 | static DRAW_SCENE_CONTEXT: Lazy>>> = Lazy::new(|| Mutex::new(None)); 12 | 13 | /// 14 | /// Retrieves or creates a scene for flo_draw, intended for the software renderer 15 | /// 16 | pub fn flo_draw_software_scene() -> Arc { 17 | let mut scene = DRAW_SCENE_CONTEXT.lock().unwrap(); 18 | 19 | // Start a new scene if none was running 20 | if scene.is_none() { 21 | // Create a new scene context, and run it on the winit thread 22 | let new_scene = Arc::new(Scene::default()); 23 | 24 | // Store as the active scene 25 | *scene = Some(Arc::clone(&new_scene)); 26 | 27 | // Run on the winit thread 28 | winit_thread().send_event(WinitThreadEvent::RunProcess(Box::new(move || async move { 29 | new_scene.run_scene_with_threads(4).await; 30 | }.boxed()))); 31 | } 32 | 33 | // Unwrap the scene context 34 | scene.as_ref().unwrap().clone() 35 | } 36 | -------------------------------------------------------------------------------- /draw/src/draw_scene/wgpu_scene.rs: -------------------------------------------------------------------------------- 1 | use crate::wgpu::*; 2 | 3 | use futures::prelude::*; 4 | use once_cell::sync::{Lazy}; 5 | 6 | use flo_scene::*; 7 | 8 | use std::sync::*; 9 | 10 | /// The scene context used for flo_draw, or None if a scene context has not been created yet 11 | static DRAW_SCENE_CONTEXT: Lazy>>> = Lazy::new(|| Mutex::new(None)); 12 | 13 | /// 14 | /// Retrieves or creates a scene for flo_draw 15 | /// 16 | pub fn flo_draw_wgpu_scene() -> Arc { 17 | let mut scene = DRAW_SCENE_CONTEXT.lock().unwrap(); 18 | 19 | // Start a new scene if none was running 20 | if scene.is_none() { 21 | // Create a new scene context, and run it on the winit thread 22 | let new_scene = Arc::new(Scene::default()); 23 | 24 | // Store as the active scene 25 | *scene = Some(Arc::clone(&new_scene)); 26 | 27 | // Run on the winit thread 28 | winit_thread().send_event(WinitThreadEvent::RunProcess(Box::new(move || async move { 29 | new_scene.run_scene_with_threads(4).await; 30 | }.boxed()))); 31 | } 32 | 33 | // Unwrap the scene context 34 | scene.as_ref().unwrap().clone() 35 | } 36 | -------------------------------------------------------------------------------- /draw/src/glutin/glutin_thread_event.rs: -------------------------------------------------------------------------------- 1 | use crate::events::*; 2 | use crate::window_properties::*; 3 | 4 | use flo_stream::*; 5 | use flo_render::*; 6 | 7 | use futures::future::{LocalBoxFuture}; 8 | use futures::stream::{BoxStream}; 9 | 10 | use winit::window::{WindowId}; 11 | 12 | /// 13 | /// Event that can be sent to a glutin thread 14 | /// 15 | pub enum GlutinThreadEvent { 16 | /// Creates a window that will render the specified actions 17 | CreateRenderWindow(BoxStream<'static, Vec>, Publisher, WindowProperties), 18 | 19 | /// Runs a future on the Glutin thread 20 | RunProcess(Box LocalBoxFuture<'static, ()>>), 21 | 22 | /// Polls the future with the specified ID 23 | WakeFuture(u64), 24 | 25 | /// Stop sending events for the specified window 26 | StopSendingToWindow(WindowId), 27 | 28 | /// Tells the UI thread to stop when there are no more windows open 29 | StopWhenAllWindowsClosed 30 | } 31 | -------------------------------------------------------------------------------- /draw/src/glutin/mod.rs: -------------------------------------------------------------------------------- 1 | mod glutin_thread; 2 | mod glutin_window; 3 | mod glutin_runtime; 4 | mod event_conversion; 5 | mod glutin_thread_event; 6 | 7 | pub (crate) use self::glutin_thread::*; 8 | pub (crate) use self::glutin_thread_event::*; 9 | 10 | pub use self::glutin_thread::{with_2d_graphics}; 11 | -------------------------------------------------------------------------------- /draw/src/software/mod.rs: -------------------------------------------------------------------------------- 1 | mod event_conversion; 2 | mod winit_window; 3 | mod winit_thread; 4 | mod winit_runtime; 5 | mod winit_thread_event; 6 | 7 | pub (crate) use self::winit_thread::*; 8 | pub (crate) use self::winit_thread_event::*; 9 | 10 | pub use self::winit_thread::{with_2d_graphics}; 11 | -------------------------------------------------------------------------------- /draw/src/software/winit_thread_event.rs: -------------------------------------------------------------------------------- 1 | use crate::events::*; 2 | use crate::window_properties::*; 3 | 4 | use flo_canvas::*; 5 | use flo_stream::*; 6 | 7 | use futures::future::{LocalBoxFuture}; 8 | use futures::stream::{BoxStream}; 9 | use futures::channel::oneshot; 10 | 11 | use winit::window::{WindowId}; 12 | 13 | use std::fmt; 14 | use std::fmt::*; 15 | use std::sync::*; 16 | 17 | /// 18 | /// Event that can be sent to a winit thread 19 | /// 20 | pub enum WinitThreadEvent { 21 | /// Creates a window that will render the specified actions 22 | CreateDrawingWindow(BoxStream<'static, Arc>>, Publisher, WindowProperties), 23 | 24 | /// Runs a future on the winit thread 25 | RunProcess(Box LocalBoxFuture<'static, ()>>), 26 | 27 | /// Polls the future with the specified ID 28 | WakeFuture(u64), 29 | 30 | /// Resolves a yield request by sending an empty message (used to yield to process events) 31 | Yield(oneshot::Sender<()>), 32 | 33 | /// Stop sending events for the specified window 34 | StopSendingToWindow(WindowId), 35 | 36 | /// Tells the UI thread to stop when there are no more windows open 37 | StopWhenAllWindowsClosed, 38 | } 39 | 40 | impl Debug for WinitThreadEvent { 41 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 42 | use self::WinitThreadEvent::*; 43 | 44 | match self { 45 | CreateDrawingWindow(_, _, _) => write!(f, "CreateDrawingWindow(...)"), 46 | RunProcess(_) => write!(f, "RunProcess(...)"), 47 | WakeFuture(id) => write!(f, "WakeFuture({})", id), 48 | Yield(_) => write!(f, "Yield(...)"), 49 | StopSendingToWindow(id) => write!(f, "StopSendingToWindow({:?})", id), 50 | StopWhenAllWindowsClosed => write!(f, "StopWhenAllWindowsClosed"), 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /draw/src/wgpu/mod.rs: -------------------------------------------------------------------------------- 1 | mod event_conversion; 2 | mod winit_window; 3 | mod winit_thread; 4 | mod winit_runtime; 5 | mod winit_thread_event; 6 | 7 | #[cfg(target_os="macos")] mod platform_macos; 8 | 9 | pub (crate) use self::winit_thread::*; 10 | pub (crate) use self::winit_thread_event::*; 11 | 12 | pub use self::winit_thread::{with_2d_graphics}; 13 | -------------------------------------------------------------------------------- /draw/src/wgpu/platform_macos/events.rs: -------------------------------------------------------------------------------- 1 | use flo_canvas_events::*; 2 | use objc2_foundation::{CGPoint}; 3 | use objc2_app_kit::{NSView, NSEvent}; 4 | 5 | /// 6 | /// Converts an NSEvent from a pointer event to a DrawEvent::Pointer event, with the specified action 7 | /// 8 | pub fn draw_pointer_event_for_nsevent(view: &NSView, action: PointerAction, buttons: Vec