Introducing ThorVG-Nim: Nim wrapper for ThorVG super lightweight vector graphics backend. It supports software, opengl, and webgpu rendering. The WebGPU can be run natively and supports Vulkan, Metal, DirectX, etc, which is a huge boon over pure OpenGL. ThorVG supports Lottie animations as well. Also it lives up to the super lightweight part and compiles to a shared library of only a couple hundred kilobytes!
It uses the ThorVG C API and loads the dynamic library. The wrapper is fairly complete but a bit rough around the edged. PRs welcome! This is likely to be a pretty stable project though (which is the best). It took longer to figure out how to integrate it with SDL2 in Nim.
Check the tests/ folder for examples. I've gotten it to work in Nim with SDL2 in both software and OpenGL modes. There's also a working example with Windex (my Windy fork with small fixes), but it'll require a new Windex release to add a couple of the required APIs.
I made this because I've been considering ThorVG as a backend rendering option for Figuro. ThorVG is already used by several other GUI systems which is nice. Figuro's built in rendering only supports OpenGL currently and I'd like to target more devices, included embedded devices. If ThorVG's performance holds up it'll likely become the default backend renderer.
There's also a working example with Windex (my Windy fork with small fixes), but it'll require a new Windex release...
With Windy appearing to be abandoned, when can we expect to see Windex in the package directory?
What is the main diffrence between Skia and ThorVG?
Primarily ThorVG is lightweight, but still high performance. Skia is heavy and the API is in constant churn in proper Google fashion.
Both FWs are written in C++, have a C API and support GPU (OpenGL, Vulkan, WebGPU) and Software-Rendering.
The C API for Skia appears to be marked experimental.
Also generally skia is a pain to build, see this HN thread. Endlessly updating to match the C++ API sounds terrible. I want Figuro to e able to target embedded devices which have much long lifecycles than normal software where it's a major benefit to be able to update a library without huge refactors.
As I can remember the overhead of the Skia runtime in a Kotlin compose (native) app on an iOS device is about 9 MB.
Yeah 200kB is way better than that. Super impressive for a C++ project. It's probably comparable to Pixie's compile size, though Pixie lacks GPU rendering (though with Boxy it comes close but the performance of Boxy has been lacking in my tests unfortunately). ThorVG is used to render 9k element OpenMaps of Paris.
Interesting project, i also was considering using that in my framework but in the end i choose to use Rive renderer instead. It's a bit bigger in size (definately not like skia and can target embedded too) but it's definately more powerful in term of gpu tessellation, feathering and it allows to have UI artists to work directly in Rive to create hot reloadable interfaces and controls while the developer can focus on just the business logic.
https://youtu.be/b3PUNkMc5QM?si=JM4ZeBT6Xod4EAY4
Anyway, good job! I might come back to it for nim apps somewhen in the future.
Thanks! Yeah I looked into Rive for a bit. It's more powerful looking and the editor looks sweet.
Unfortunately figuring out how to setup and just use the Rive renderer from the rest of the runtime would've taken more work. The ThorVG docs and examples were much clearer there. I'm pretty new to Opengl and just getting a handle on setting up windowing with another library was a bit annoying.
After adding a ThorVG backend to Figuro it should be easy to add any vector graphics backend. The APIs for vector graphics seem to have largely converged which is nice. I just need to convert the vector paths from Pixie to Thor. I'll probably add Pixie compatible Api's to the Thor wrapper.
Maybe the Rive editor can export lottie files which Thor supports? Hmmm.. it'd be awesome to support tying Figuro directly to Rive or Lottie style animations using signals and slots.
Thanks for the ThorVG wrapper.
In your windex/opengl example https://github.com/elcritch/thorvg-nim/blob/main/tests/windex_opengl_example.nim you are still using SDL2. Both Windex and SDL2 offer window management functions and OpenGL context. Why is this necessary?
In your windex/opengl example https://github.com/elcritch/thorvg-nim/blob/main/tests/windex_opengl_example.nim you are still using SDL2. Both Windex and SDL2 offer window management functions and OpenGL context. Why is this necessary?
Looks like leftovers. I didn't get around to removing the SDL2 code after copying the sdl example. Part of the "rough edges" caveat I mentioned in the first post. ;)
As an aside: most of the images on the original project's landing page are resampled very poorly, some saved as jpg or webp, though containing vector graphics, even PNGs look like noisy lossy recodes. All of this instills some doubts (I hope groundless) in technical competency of projects maintainers.
Presentation is important.
Some good points, although that could be whatever hosting setup they're using. It looks lime Samsung supports it, so maybe someone is doing for them, etc. Still it's a bit of a factor.
While I hope it'll make a good backend for Figuro there's some possible blockers. There were some comments from others about the quality of aliasing on opengl. I've found potential issues with some paths not clearing, but that could be due to wrapper issues.
It may be possible to use it as just a gpu accelerated image renderer with support for masking and shadows. In that case I can keep using Pixie for generating images.
Rive would probably be a higher quality backend, especially with its feathering. I might understand enough about opengl now to figure out setting up their renderer. I might try that if thorvg doesn't pan out.
Version 0.3.0 is out.
It includes a number of fixes, a lot less overhead, etc. It's fairly usable now. It does appear to be doing anti-aliasing in OpenGL mode, which is good.
I had to add an upstream PR to add shadow effects to their C API. I don't know if that'll get accepted.
Unfortunately the performance for shadow rendering struggles the same as Boxy does. So adding a few hundred items just brings the FPS down.
That means it probably won't make a good Figuro backend, although I might try it as just and accelerated image renderer later. Meanwhile I've got some ideas to try since shadows seem to be a persistent pain.