godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.11k stars 69 forks source link

Add a way to load SVG files from buffer at an adjustable scale #3422

Closed ghost closed 1 year ago

ghost commented 2 years ago

Describe the project you are working on

2D topdown game.

Describe the problem or limitation you are having in your project

Some elements need to be scaled correctly, the strategy of scaling the SVG up on import and shrinking when drawing has its limitations.

I'm importing a lot of SVG files at a larger scale (and shrinking later), this is increasing the size of the pck a lot, being able to load them at runtime would allow me to have a much smaller pck.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The Image contains methods to load different formats from a buffer: bmp, jpg, png, tga, webp.

But there are no methods to load buffer containing SVG data.

Implementing this method makes it possible to start working on a solution to update the texture when the desired size changes.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

The addition of this method Image::load_svg_from_buffer(buffer: PoolByteArray, scale: float = 1.0) to the Image.

This method should be available in the editor and in exported projects.

If this enhancement will not be used often, can it be worked around with a few lines of script?

No, we can load SVGs from file at runtime with Image::load, but there is no option to load it at different scales, the scale 1.0 is implicit and cannot be modified.

Edit: According to https://github.com/godotengine/godot-proposals/issues/3422#issuecomment-942560151, SVG is only available in editor builds, so even the Image::load won't work for exported projects.

Is there a reason why this should be core and not an add-on in the asset library?

This method provides functionality to create amazing add-ons, but its implementation depends on things only available in the core, like access to the SVG parser and rasterizer library (nanosvg).

Calinou commented 2 years ago

The SVG module is currently only compiled in editor builds. For this to work in exported projects, the SVG module needs to be compiled in export templates as well, which will increase its binary size.

This is not a problem in 4.0 as we'll need run-time SVG loading for https://github.com/godotengine/godot/pull/51159, but this is something to keep in mind for 3.x.

Some elements need to be scaled correctly, the strategy of scaling the SVG up on import and shrinking when drawing has its limitations.

This approach generally works well as long as you enable mipmaps on the texture in the Import dock. This will use more memory, but it makes run-time scaling easier and faster.

ghost commented 2 years ago

This is not a problem in 4.0 as we'll need run-time SVG loading for godotengine/godot#51159, but this is something to keep in mind for 3.x.

Good to know about 4.0, I'm interested in this feature for 3.x.

I'm using emojis (3k+) and importing each one of them on a larger scale, this is increasing the size of the pck a lot. Being able to load them at runtime would allow me to have a much smaller pck and increasing the binary size of the exported templates would be worth it.

EDIT: I updated the proposal with information about the large amount of SVG files and pck increase.

Calinou commented 2 years ago

I'm using emojis (3k+) and importing each one of them on a larger scale, this is increasing the size of the pck a lot.

Remember that Godot supports colored DynamicFonts, so you can load an .otf file containing emoji then display them using a Label or RichTextLabel. However, this will only work correctly for emoji in 4.0 due to https://github.com/godotengine/godot/issues/23093.

ghost commented 2 years ago

Remember that Godot supports colored DynamicFonts, so you can load an .otf file containing emoji then display them using a Label or RichTextLabel. However, this will only work correctly for emoji in 4.0 due to godotengine/godot#23093.

Unfortunately, this isn't an option for me, the support for colored fonts from the emoji library I'm using (OpenMoji) is low (only Firefox / Edge / Adobe CC supports it), I've tried it on Godot and it doesn't work so I opted for the SVG approach. 😭

One option would be to make Godot support it, but probably the runtime SVG approach is much simpler.

fire commented 2 years ago

I am interested in the proposal and I'm working on the thorvg svg upgrade. https://github.com/godotengine/godot/pull/49645

Not sure if the core team will approve of doing the svg import at runtime, but still am interested.

2plus2makes5 commented 2 years ago

I'm in for improvements to SVG, being able to decide the import size of a SVG depending on the window size or even on a graphics setting would be great, on the other hand that would need the region rect coordinates to be specified as UVs or to be multiplied by the chosen size, the mulltiplication is easy to implement though so it's not a problem, but only if the sprite don't change rect in the middle of an animation.

Xrayez commented 2 years ago

Goost has a way to rasterize SVGs as an Image using GoostImage.render_svg() method with adjustable scale from a SVG document represented as a String. Goost reuses Godot's SVG loader library, so it's also possible to expose the same method in Godot.

But as suggested here, a better SVG importer would need to be integrated. As far as I know, current SVG loader is mostly useful for rendering simple geometry such as editor icons.

sammycage commented 2 years ago

But as suggested here, a better SVG importer would need to be integrated.

You can use LunaSVG for importing SVG files. It's fast, easy to use, regularly maintained, free from crash and supports a wide range of svg features.

YuriSizov commented 2 years ago

@sammycage Current plan is to use ThorVG (https://github.com/godotengine/godot/pull/49645). Luna has been tried, but seems to be less maintained, among other things (https://github.com/godotengine/godot/pull/49601).

sammycage commented 2 years ago

but seems to be less maintained

@pycbouh This is a misleading statement.

YuriSizov commented 2 years ago

I understand that it's your project and you are defensive of it, but that's what the maintainer responsible for changes decided after testing it thoroughly. I didn't intend to hurt your feelings, just wanted to point out that we did try it and it didn't work out practically.

sammycage commented 2 years ago

@pycbouh I understand. This is just a suggestion 😊😊😊.

Xrayez commented 2 years ago

Not to hurt the feelings of fire who tried to integrate both libs, but I wish him to be more descriptive for the work that is done in general (there's barely anything at #2912, what are other pro's and con's?). πŸ˜›

While ThorVG may be better maintained (backed by Samsung), it does not necessarily mean that the quality and feature set is the same. And it's unlikely that such a lib will require major maintenance effort anyways.

fire commented 2 years ago

Evaluation notes on Samsung ThorVG vs LunaVG:

As requested I have typed some notes.

ThorVG

https://github.com/Samsung/thorvg

  1. rlottie changed license from Lgpl to Mit at request
  2. rlottie is a defacto vector animation standard in Discord and Telegram
  3. iFire has experience with rlottie from a previous module https://github.com/godot-extended-libraries/lottie
  4. Thorvg is a upgrade of rlottie
  5. Samsung is providing support on light dark theme in Godot Engine
  6. Samsung has been investigating and fixing 10+ Github issues from the Godot Engine team https://github.com/Samsung/thorvg/issues?q=is%3Aissue+godot+
  7. Thorvg has a full-time team of 3-4 people.
  8. Thorvg has an EFL Tizen operating system SVG maintainer. https://docs.tizen.org/application/native/tutorials/ui-builder/ui-builder-overview/
  9. Activity. Concerns that NanoSVG is abandoned and a requirement of any replacement.

image

LunaSVG

https://github.com/sammycage/lunasvg

  1. Was the prototype for better SVG in Godot Engine master
  2. LunaSVG said feature requests would be made after summer 2021 compared to Samsung ThorVG response the next day in June-July 2021.
  3. Activity

image

sammycage commented 2 years ago

LunaSVG said feature requests would be made after summer 2021

Although CSS has a very complex structure, I implemented it as promised during the summer vacation.

Support on light dark theme in Godot Engine

It would also be worth investigating how to use CSS to control the coloring of the SVG files as well, rather than having the coloring hard-coded, but that may take a little more work.

Example


static const std::string KDarkThemeCSS = ".pane { fill:darkgreen;} ...";
static const std::string KLightThemeCSS = ".pane { fill:#80c080;} ...";

lunasvg::Environment::loadGlobalStyleSheet(KDarkThemeCSS); // The theme's properties are applied to every single file that is loaded after this function call.
TechnoPorg commented 1 year ago

This could tie in nicely to #6495, and probably others too, like #2924. Implementing a brand new SVG texture type would really improve Godot's SVG experience and make it much more powerful on that front. I'm not sure whether a dedicated SVGTexture subclass of Texture2D would be the best solution for SVG handling, or whether it would be better to create an SVGImage to drop into an ImageTexture. Any thoughts?

Calinou commented 1 year ago

I'm not sure whether a dedicated SVGTexture subclass of Texture2D would be the best solution for SVG handling, or whether it would be better to create an SVGImage to drop into an ImageTexture. Any thoughts?

I think it should be a dedicated SVGTexture with a scale property and a source property where you write the SVG code. The texture is updated when scale or source are modified. This would make it similar in spirit to GradientTexture, CurveTexture, etc.

Even with https://github.com/godotengine/godot/pull/78248, I think SVGTexture is still relevant as a helper for procedural texture generation without relying on a Viewport.

ghost commented 1 year ago

@Calinou

I think it should be a dedicated SVGTexture with a scale property and a source property where you write the SVG code. The texture is updated when scale or source are modified. This would make it similar in spirit to GradientTexture, CurveTexture, etc.

I've tested an implementation like that here.

It works, but the usability is poor, the ".svg" must exist as a file/resource, not as a property of SVGTexture.

Calinou commented 1 year ago

It works, but the usability is poor, the ".svg" must exist as a file/resource, not as a property of SVGTexture.

I think it could have good usability if you added a way to change the texture's import mode to a SVGTexture, so that it imports a SVGTexture instead of an ImageTexture. You'd need to find a way to restrict this import mode to .svg only (and perhaps .svgz if its data can be decompressed on-the-fly).

ghost commented 1 year ago

so that it imports a SVGTexture instead of an ImageTexture

I thought about this possibility, what made me disregard it for now was the current "import workflow", where Resource's properties are defined when importing.

This is fine in the case of .svg content, but an issue in the case of scale which would ideally be changed in the EditorInspector.

It's possible to write a custom workflow for .svg, but the work done is not so trivial. At least for me 😝