SVG drawing

fschutt edited this page Oct 21, 2018 · 3 revisions

For drawing custom graphics, azul has a high-performance 2D vector API. It also allows you to load and draw SVG files (with the exceptions of gradients: gradients in SVG files are not yet supported). But azul itself does not know about SVG shapes at all - so how the SVG widget implemented?

The solution is to draw the SVG to an OpenGL texture and hand that to azul. This way, the SVG drawing component could even be implemented in an external crate, if you really wanted to. This mechanism also allows for completely custom drawing (let's say: a game, a 3D viewer, etc.) to be drawn.

The SVG component currently uses the resvg parser, usvg simplification and the lyon triangulation libraries). Of course you can also add custom shapes (bezier curves, circles, lines, whatever) programmatically, without going through the SVG parser:

const TEST_SVG: &str = include_str!("tiger.svg");

impl Layout for Model {
    fn layout() {
        if let Some((svg_cache, svg_layers)) = self.svg {
            Svg::with_layers(svg_layers).dom(&info.window, &svg_cache)
        } else {
             Button::labeled("Load SVG file").dom()
                .with_callback(load_svg)
        }
    }
}

fn load_svg(app_state: &mut AppState<MyAppData>, _: WindowEvent<MyAppData>) -> UpdateScreen {
    let mut svg_cache = SvgCache::empty();
    let svg_layers = svg_cache.add_svg(TEST_SVG).unwrap();
    app_state.data.modify(|data| data.svg = Some((svg_cache, svg_layers)));
    UpdateScreen::Redraw
}

This is one of the few exceptions where azul allows persistent data across frames since it wouldn't be performant enough otherwise. Ideally you'd have to load, triangulate and draw the SVG file on every frame, but this isn't performant. You might have noticed that the .dom() function takes in an extra parameter: The svg_cache and the info.window. This way, the svg_cache handles everything necessary to cache vertex buffers / the triangulated layers and shapes, only the drawing itself is done on every frame.

Additionally, you can also register callbacks on any item inside the SVG using the SvgCallbacks, i.e. when someone clicks on or hovers over a certain shape. In order to draw your own vector data (for example in order to make a vector graphics editor), you can build the "SVG layers" yourself (ex. from the SVG data). Each layer is batch-rendered, so you can draw many lines or polygons in one draw call, as long as they share the same SvgStyle.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.