If you want to render some 2D graphics in Rust to screen right now without having to deal with the usual palaver involved with setting up
a graphics context in a UI framework, flo_draw
is the crate you need.
use flo_draw::*;
use flo_canvas::*;
///
/// Displays a filled circle in a window
///
pub fn main() {
with_2d_graphics(|| {
// Create a window
let canvas = create_drawing_window("Circle");
// Draw a circle
canvas.draw(|gc| {
// Set up the canvas
gc.canvas_height(1000.0);
gc.center_region(0.0, 0.0, 1000.0, 1000.0);
// Draw a circle
gc.new_path();
gc.circle(500.0, 500.0, 250.0);
gc.fill_color(Color::Rgba(0.3, 0.6, 0.8, 1.0));
gc.fill();
gc.line_width(6.0);
gc.stroke_color(Color::Rgba(0.0, 0.0, 0.0, 1.0));
gc.stroke();
});
});
}
flo_draw
also comes with a powerful set of 2D graphics libraries and has a flexible stream-based API that can make light work of many
tasks that other libraries can make a meal of.
While building FlowBetween, I found I needed a few when it came to rendering graphics: a platform-agnostic API and a way to render bitmap files that's not tied to any one platform. When debugging it, I found another thing I really wanted was a simple way to just throw up a window and start drawing graphics in it. This used to be quite simple in the 1980s (as demonstated in the screenshot) but the rise of the GUI and 3D accelleration has made rendering graphics increasingly difficult.
flo_draw
takes the 2D graphics crates created for FlowBetween and adds an API to take all of the hassle out of the task of making
them work.
This is a set of libraries that provide a 2D rendering framework for Rust. It provides on and off-screen rendering and an abstraction API. You might want to read the guide for some in-depth discussion of what can be achieved with the libraries in this repository.
flo_draw
is a library that renders 2D graphics on-screen via glutinflo_canvas
provides a way to describe 2D drawing operations without being tied to any particular rendering implementationflo_render
is an abstraction API that converts low-level rendering instructions to a graphics API (OpenGL and Metal are supported)flo_render_canvas
converts the instructions described inflo_canvas
to instructions forflo_render
(using lyon for the tessellation)flo_render_gl_offscreen
helpsflo_render
by providing system-specific initialisation instructions for offscreen rendering
There are some other implementations of the flo_canvas
protocol that are not yet packaged up conveniently: in particular,
canvas.js
allows rendering to an HTML canvas, and FlowBetween contains implementations for Quartz and Cairo.
Apart from the main 'party-piece' trick of popping up a window to render 2D graphics whenever it's needed, flo_draw
and its companion
crates have a number of other tricks up their sleeves:
- Fully interactive: handle mouse and keyboard events to create graphical demonstrates
- Flexible but straightforward text layout engine (which can render text to vectors if required)
- Draw to bitmaps as well as to the screen
- OpenGL accelerated 2D graphics
- Stream-based API allows for easily composing effects on top of existing rendering instructions
- Layers provide a way to partially update previously rendered graphics
- Sprites provide a way to quickly re-render complex objects
- Rendering from multiple threads (especially easy if each thread has its own layer)
- Stream-based API allows easy redirection of the rendering instructions to the graphics API of your choice (both 2D APIs and GPU APIs)
The flo_draw
library is the best place to start, it provides a very easy way to render things on-screen:
use flo_draw::*;
use flo_canvas::*;
pub fn main() {
with_2d_graphics(|| {
let canvas = create_canvas_window("Hello, triangle");
canvas.draw(|gc| {
gc.clear_canvas(Color::Rgba(0.0, 0.4, 0.4, 1.0));
gc.canvas_height(1000.0);
gc.center_region(0.0, 0.0, 1000.0, 1000.0);
gc.new_path();
gc.move_to(200.0, 200.0);
gc.line_to(800.0, 200.0);
gc.line_to(500.0, 800.0);
gc.line_to(200.0, 200.0);
gc.fill_color(Color::Rgba(0.0, 0.0, 0.8, 1.0));
gc.fill();
});
});
}
See the examples folder in the draw
and render_canvas
subdirectories for some more things that can be done with the library.
-
cargo run --example canvas_window
- displays a basic window -
cargo run --example hello_world
- traditional -
cargo run --example layer_alpha
- blending between layers -
cargo run --example bounce_sprites
- animates some bouncing balls -
cargo run --example follow_mouse
- demonstrates event handling by tracking the mouse around -
cargo run --example vectoroids
- more involved example of event handling with an incomplete game (arrow keys to move, space to fire) -
cargo run --example png_triangle
- renders a triangle to a png file -
cargo run --example mandelbrot
- an interactive mandelbrot set program -
cargo run --example wibble
- render text to vectors and distort it in real time -
cargo run --example mascot
- render FlowBetween's mascot from some pre-encoded vector instructions -
cargo run --example mascot_sprite
- use a sprite to render the mascot -
cargo run --example mascot_filter
- render the mascot with some filters applied to it -
cargo run --example texture
- bitmap rendering -
cargo run --example texture_filter
- applying filters to bitmaps -
cargo run --example texture_sprites
- bouncing balls with bitmap images -
cargo run --example texture_spin
- bitmap rendering with an animated transformation applied -
cargo run --example texture_from_sprite
- demonstrates rendering to a texture -
cargo run --example texture_from_sprite_dynamic
- dynamic textures provide a way to render to textures at 'native' canvas resolution -
cargo run --example gradient
- gradient rendering -
cargo run --example mascot_shadow
- reprocess the mascot rendering to add some extra shading -
cargo run --example wibble_mascot
- reprocess the mascot rendering to make it wobble -
cargo run --example wibble_dynamic_mascot
- wobbly mascot rendered multiple times using a dynamic texture -
cargo run --example text_layout
- some effects that can be acheived with the text layout engine -
cargo run --example show_tessellation
- demonstrates how 2D graphics are tessellated for display using a GPU (and how to perform this manually and intercept the results) -
cargo run --example show_text_tessellation
- tessellating text rendered from a font -
cargo run --example guide_illustrations
- regenerate the png files used in the guide -
cargo run --example raw_wgpu_winit
- canvas rendering directly using winit without the supporting functions inflo_draw
-
cargo run --example raw_wgpu_winit_triangle
- direct rendering using winit without the supporting functions inflo_render_canvas
There are a couple of feature flags that can be used to choose rendering engines or enable or disable features:
render-opengl
- the default renderer, using the OpenGL API. Right now this provides the highest performance on the widest range of possible hardware.render-wgpu
- uses WGPU instead of OpenGL. WGPU can use a wide range of backends but is currently quite low performing on several systemsprofile
- output some performance metrics to the console on each framewgpu-profiler
- add in the WGPU profiler (somewhat unreliable)
flo_draw
was developed alongside several other crates, which may be of interest when developing software that uses the canvas:
flo_curves
provides a lot of functionality for manipulating bezier curves.flo_stream
provides pubsub and generator streams, which are useful for distributing events around an application. (See the vectoroids example for a way to use a generator stream as a game clock)desync
provides a simpler way to write asynchronous code than traditional threadsflo_binding
provides a way to convert between state changes and message streams, used inflo_draw
to update the window configurationflo_scene
is a toolkit for building larger pieces of software from components that communicate by exchanging messages or monitoring properties.
This is version 0.4 of flo_draw
.
Future versions will incorporate more rendering targets. FlowBetween has Quartz, Cairo and HTML canvas targets so those are very likely, and some sort of non-accelerated version of the offscreen renderer is also a likely addition. Version 0.4 will likely add some more pipes for drawing streams: for example, a stream to simplify the rendering instructions so they match up to more conventional 2D graphics libraries more closely.
There are a few known issues with 0.4: dashed lines don't work too well either in this version.