bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Support load .svg images

Open wyhaya opened this issue 4 years ago • 9 comments
trafficstars

What problem does this solve or what need does it fill?

Allow bevy to load svg vector images

Describe the solution would you like?

Using resvg crate, bevy can easily support svg images

Describe the alternative(s) you've considered?

None

Additional context

I added a SvgTextureLoader and then rendered the image using resvg and now it works fine.

let texture_handle = asset_server.load("branding/bevy_logo_light.svg");
Screen Shot

One troublesome question, since svg is vector, how do we determine the size of the image?

Before rendering the svg we have to determine the size

pub enum FitTo {
    /// Keep original size.
    Original,
    /// Scale to width.
    Width(u32),
    /// Scale to height.
    Height(u32),
    /// Zoom by factor.
    Zoom(f32),
}

Maybe we can?

// Default
asset_server.load("branding/bevy_logo_light.svg");
// Scale
asset_server.load("branding/bevy_logo_light.svg?10.0");
asset_server.load("branding/bevy_logo_light.svg#width=1000.");

Bad scenario: Re-render at each zoom?

wyhaya avatar Dec 23 '20 14:12 wyhaya

WRT the re-render at each zoom problem, perhaps we could build off of mip-maps (#1685) to pre-cache the SVG rendered at different scales.

If we had that, it feels like there are three possibly sensible options:

  1. Use the nearest size.
  2. Recompute if no exact match is found; likely caching the result.
  3. Quickly interpolate between nearby sizes.

I think 2 is my preferred solution in most cases.

alice-i-cecile avatar Mar 20 '21 01:03 alice-i-cecile

Just chiming in to say that this is not really what mipmaps are for. (the use case of using vector graphics like SVG in UI)

Mipmaps are for the GPU hardware to be able to automatically sample a texture at an appropriate resolution when UV-mapping onto 3d geometry (or for raster 2d sprites, when scaling down). Note that you don't really have much choice and control over which size to use when, as mipmaps are a GPU hardware feature and handled automatically. And your mipmap levels/sizes must strictly have specific sizes as expected by the GPU (1/2, 1/4, 1/8, etc., of the base texture).

Your (1) and (3) are things that the GPU hardware does automatically (you should try out the texture_filtering example from the mipmaps PR, which illustrates this ("linear with nearest mipmap" and "linear with linear mipmaps" (interpolation)). Choosing which one you want is just a parameter on the texture sampler. The GPU implements this functionality in hardware.

However, this wouldn't produce the best-looking result for using vector graphics like SVG in UI. Instead, you want to display it rendered natively at the correct size. In that sense, I agree with your (2) point, I just want to point out that it has nothing to do with mipmaps.

On the other hand, if you want to use the SVG to create a texture to be used in your scene / on a mesh, you should totally generate a mipmapped texture with the maximum size (base level) set to something reasonable of your liking. In that case, you should use mipmaps, and probably set the mipmap filtering to LINEAR (or in a 2d game, maybe NEAREST might work better than LINEAR, but anyway, those are just sampler settings).

Really, these are two different use cases: using a SVG in UI and using a SVG for textures in a game. So they call for different implementations. The former should be rendered natively at the correct size, similar to how we handle text. The latter makes sense as a mipmapped texture.

inodentry avatar Mar 22 '21 21:03 inodentry

Thanks @jamadazi; this is very useful expertise :) I agree with your conclusions here.

alice-i-cecile avatar Mar 22 '21 21:03 alice-i-cecile

https://github.com/RazrFalcon/resvg is licensed with MPL-2.0, is it okay to incorporate with bevy or should it be separate MPL-2.0 licensed crate?

There needs also to be a way to supply parameters (at least render width, height) for per-resource rendering.

Maybe the SvgAssetLoader could also have (default/user-configurable) presets for handling?

// single asset params
asset_server.load("branding/bevy_logo_light.svg#width=1024,height=512");

// preset
asset_server.load("branding/bevy_logo_light.svg#svg_preset=my_custom_config");

blaind avatar Jul 23 '21 09:07 blaind

It's best to avoid MPL-2.0, you can find the list of licences accepted in Bevy here: https://github.com/bevyengine/bevy/blob/ba2916c45a6dcf23f7c4007e7ef2a6b0df393433/deny.toml#L16-L25

mockersf avatar Jul 23 '21 19:07 mockersf

Relicensing wgpu from MPL was important as it needs to be patched to run on certain consoles. An svg renderer doesn't need to be patched in any way that needs to remain behind an NDA, so I don't see much of a problem with using MPL here. It is weak and not strong copyleft, so you only need to publish any changes to resvg, not any other dependency or the game itself.

bjorn3 avatar Jul 23 '21 19:07 bjorn3

MPL-2.0 also requires access to the source code of the parts licensed with it, so it would mean that all Bevy games will need to provide a link to the source code of resvg

mockersf avatar Jul 23 '21 19:07 mockersf

The MIT and Apache-2.0 license require attribution notices to be preserved afaik. You could see a link to source code as just another kind of attrbution notice, so it doesn't really add any more obligations on the licensee (the creator of the game) provided that the source code of the MPL licensed dependencies is unchanged.

bjorn3 avatar Jul 23 '21 21:07 bjorn3

Maybe working with Lyon could be another option?

Seems to be fairly solid solid, but it also is considering switching from it's MIT/Apache 2.0 Model to MPL-2.0 aswell. But it is not decided as of today (2022-08-01)

WhatzGames avatar Jul 31 '22 23:07 WhatzGames