Commit graph

194 commits

Author SHA1 Message Date
Hermet Park
54528b6ac9 renderer: introduce a ThorVG Text interface.
Introduced New APIs under the experimental tags.

- Result Text::font(const char* name, float size, const char* style = nullptr);
- Result Text::text(const char* text);
- Result Text::fill(uint8_t r, uint8_t g, uint8_t b);
- static Result Text::load(const std::string& path);
- static Result Text::unload(const std::string& path);
- static Text::std::unique_ptr<Text> gen();
- static Text::uint32_t identifier()

@Issue: https://github.com/thorvg/thorvg/issues/969
2024-01-02 20:34:11 +09:00
Hermet Park
e53ee5881f renderer/loader: support ttf loader.
Applied 2 more internal LoaderMgr interfaces for
gobally manage the font data resources.

The next function is introduced for lookup the existing loader
with the font name (key)
- static LoaderMgr::LoadModule* loader(const char* key);

The next function is introduced to free the existing loader
with the loader source(file path)
- static bool retrieve(const string& path);

Additionally implements the base loader to bind the ttf loader.
2024-01-02 20:34:11 +09:00
Hermet Park
03c53d3227 loader/ttf: introduce a new sfnt(scalable font) loader.
ttf is an industry standard format that is the most widely used
in the products. Now thorvg supports the basic features of
the font to supplement the text drawing.

The implementation is followed the ttf spec,
the covered features are:

- horizontal layouting with kerning.
- utf8 -> utf32 converted glyph drawing.

To use the feature, please enable ttf loader:
$meson -Dloaders="ttf_beta, ..."

@Issue: https://github.com/thorvg/thorvg/issues/969
2024-01-02 20:34:11 +09:00
Hermet Park
49d26691e5 common: Revise internal loader interfaces.
We are introducing the FontLoader, which slightly differs
from the ImageLoader in terms of features. To adequately
support both, we have separated the loader functionalities
into FontLoader and ImageLoader. This allows us to optimally
adapt the LoadModule for each case.
2024-01-02 20:34:11 +09:00
Hermet Park
6ef979f2a0 sw_engine/fill: fix a linear filling scaling issue.
The condition is not valid,
Let it draw the fill as it's requested.

Issue: https://github.com/thorvg/thorvg/issues/1834
2024-01-02 20:34:11 +09:00
Sergii Liebodkin
5ba19a8a7f wg_engine: shape bbox based rendering (optimization)
Before the current changes, all surfaces were painted using a full-screen overlay, no matter how large the object was rendered. This approach is redundant and required reorganization. At the moment, all objects are rendered using an overlay equal to the box of the object itself, which reduces the cost of filling the surface.
Also surfaces and images were divided into different entities, which reduces the pressure on memory.
Also geometry data for rendering and geometry data for calculations in system memory were logically separated.
2024-01-02 20:34:11 +09:00
Sergii Liebodkin
4164b36c8a wg_engine: Added shape opacity value usage
[issues 1479: Opacity](#1479)

Usage example:

    // prepare a shape (Rectangle + Rectangle + Circle + Circle) with opacity
    auto shape1 = tvg::Shape::gen();
    shape1->appendRect(0, 0, 200, 200);                //x, y, w, h
    shape1->appendRect(100, 100, 300, 300, 100, 100);  //x, y, w, h, rx, ry
    shape1->appendCircle(400, 400, 100, 100);          //cx, cy, radiusW, radiusH
    shape1->appendCircle(400, 500, 170, 100);          //cx, cy, radiusW, radiusH
    shape1->fill(255, 255, 0);                         //r, g, b
    shape1->opacity(128)                               //opacity
    canvas->push(std::move(shape1));
2024-01-02 20:34:11 +09:00
Sergii Liebodkin
003464b7e5 wg_engine: refactor context handles
New approach provide:
- instance, adaptor, device and default queue
- device capabilitieas
- command buffer executor
- error handling
2024-01-02 20:34:11 +09:00
Sergii Liebodkin
e797cf63f4 wg_engine: refactor render targets handling
For further development of features, we need to create off-screen buffers that will allow us to implement functionality related to composition and blending, as well as for loading data to system memory from the framebuffer. Separating the framebuffer into a separate entity allows you to create several instances of them, switch between them, and blend them according to given rules.

For current time we have only a single render target instance, that have a handle to drawing into surface surface, like a native window.

New approach allows:
- offscreen rendering
- render pass handling
- switching between render targets
- ability to render images, strokes and shapes into independent render targets
2024-01-02 20:34:11 +09:00
RuiwenTang
d3169ea8fe gl_engine: fix wrong scissor value cause content not fully rendered 2024-01-02 20:34:11 +09:00
Hermet Park
2efdae710d renderer: minor optimization.
reduce the binary size.
2024-01-02 20:34:11 +09:00
RuiwenTang
c8833e970d gl_engine: optimize framebuffer creation and save some runtime memory
since the framebuffer will draw back to parent RenderPass, it can be
reused in next compose rendering.

So instead of create framebuffer every time when beginCompose is called, we
trying to reuse the framebuffer created before in the same stack level
2024-01-02 20:34:11 +09:00
Hermet Park
a6378fc673 wg_engine: apply tvg coding style. 2024-01-02 20:34:11 +09:00
Sergii Liebodkin
9742cfe293 wg_engine: pipelines and bind groups refactoring
- shader and system types synchronized
- pipelens and bind groups description separated
- pipelines description simplified
2024-01-02 20:34:11 +09:00
Hermet Park
f173b45e04 renderer/picture: fixed a regression
reverted a wrong change from the previous code refactoring
in 5643348472
2024-01-02 20:34:11 +09:00
Hermet Park
74a7c45214 common: clean up the code. 2024-01-02 20:34:11 +09:00
Hermet Park
bbf3cec2cc common/array: code refactoring.
Use a default constructor with reservation.
2024-01-02 20:34:10 +09:00
Hermet Park
79facf3656 renderer/scheduler: --binary size by 2.2kb
replace the stl with own lightweight data structures.
2024-01-02 20:34:10 +09:00
Hermet Park
f594806dd3 renderer/shape: Apply the magic number kappa to achieve rounded corners.
The magic number kappa (0.552284), which is associated with the bezier curve,
has been introduced. This formula is supposed to be applied to the rounded corners
of the rectangle to ensure consistent drawing results.

Issue: https://github.com/thorvg/thorvg/issues/1824
2024-01-02 20:34:10 +09:00
Hermet Park
c0a1f82033 renderer/loader: optimization++
removed the internal unique_ptr usage to reduce the binary size(-553)
2024-01-02 20:34:10 +09:00
Sergii Liebodkin
cb737f174c [Issues 1811: Compiller shadowing warning](https://github.com/thorvg/thorvg/issues/1811)
Godot CI compilation issue fixed
2024-01-02 20:34:10 +09:00
RuiwenTang
269537a411 gl_engine: support advance compose method 2024-01-02 20:34:10 +09:00
Hermet Park
f64ee28079 Loaders: Introduced a loader cache.
The loader cache is applied to conserve memory.

If the input data is already present in loaders,
the loader cache will promptly return the active loader.

This results in a lot of memory savings for the duplicated resources.

binary diff: -400 bytes
2024-01-02 20:34:10 +09:00
Hermet Park
8cc8cf3b02 common: Move the list to the gl_engine side.
Unfortunately, the usage of this list is not intuitive,
so can be confusing. Placed it only for gl.
2024-01-02 20:34:10 +09:00
Hermet Park
1fbdf7bbb6 renderer, loader: minor code refactoring.
- sync with its file name
- remove unnecessary section comments
- compact binary size (-300)
- private Task::run() methods from the loaders
2024-01-02 20:34:10 +09:00
Sergii Liebodkin
51e98eebdb Add support for textures color space formats
[Issues 1479: pictures](https://github.com/thorvg/thorvg/issues/1479)

Formats supported:
    ABGR8888
    ARGB8888
    ABGR8888S
    ARGB8888S
2024-01-02 20:34:10 +09:00
Hermet Park
b8b8188879 sw_engine: fixed a bug where strokes were not showing.
Basic shapes were trimmed entirely when they were outside of the canvas,
even if they had a big enough stroke to be partially on the canvas.

This fixes the issue.

Issue: https://github.com/thorvg/thorvg/issues/1785
2024-01-02 20:34:10 +09:00
Sergii Liebodkin
c5b642e3e7 wg_engine: introduced images drawing support
[issues 1479: pictures](https://github.com/thorvg/thorvg/issues/1479)

    auto picture = tvg::Picture::gen();
    picture->load("images/test.png");
    picture->translate(0, 0);
    picture->size(100, 100);
    picture->opacity(255);
    canvas->push(std::move(picture));
2023-12-26 18:36:45 +09:00
Hermet Park
f58895a04a gl_engine/renderer: skip sync if nothing should be done.
update by 66305f3e6d
2023-12-26 18:33:33 +09:00
Hermet Park
27843d2557 savers: provides a background setting.
Allow users to set a custom background with a saver.

API:
- Result Saver::background(std::unique_ptr<Paint> paint);
2023-12-26 18:30:06 +09:00
Hermet Park
39022851b7 sw_engine: ++null safety 2023-12-26 18:23:54 +09:00
Hermet Park
042693ccfe renderer/loader: code refactoring
Move the raw image loading interface to the RawImageLoader.
it is only valid for this component.
2023-12-26 18:23:25 +09:00
Sergii Liebodkin
bad02c7de0 Added ability to draw solid strokes with dashes
[issues 1479: Shape](https://github.com/thorvg/thorvg/issues/1479)

In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html)

Usage example:

    // init glfw
    glfwInit();

    // create a windowed mode window and its opengl context
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr);

    // get window size
    int width{}, height{};
    glfwGetWindowSize(window, &width, &height);

    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    //Test for Stroke Dash for Arc, Circle, Rect
    auto shape = tvg::Shape::gen();
    shape->appendArc(70, 600, 160, 10, 30, true);
    shape->appendCircle(70, 700, 20, 60);
    shape->appendRect(130, 710, 100, 40);
    shape->strokeFill(255, 0, 0);
    shape->strokeWidth(5);
    shape->strokeJoin(tvg::StrokeJoin::Round);
    shape->strokeCap(tvg::StrokeCap::Round);
    float dashPattern[2] = {20, 10};
    shape->strokeDash(dashPattern, 2);
    if (canvas_wg->push(std::move(shape)) != tvg::Result::Success) return;

    while (!glfwWindowShouldClose(window)) {
        // webgpu
        canvas_wg->draw();
        canvas_wg->sync();

        // pull events
        glfwPollEvents();
    }

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
    glfwDestroyWindow(window);
    glfwTerminate();
2023-12-26 18:18:48 +09:00
Sergii Liebodkin
41ea198a5e Added ability to draw solid strokes
[issues 1479: Shape](https://github.com/thorvg/thorvg/issues/1479)

In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html)

Usage example:

    // init glfw
    glfwInit();

    // create a windowed mode window and its opengl context
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr);

    // get window size
    int width{}, height{};
    glfwGetWindowSize(window, &width, &height);

    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    //Test for Stroke Dash for Arc, Circle, Rect
    auto shape = tvg::Shape::gen();
    shape->appendArc(70, 600, 160, 10, 30, true);
    shape->appendCircle(70, 700, 20, 60);
    shape->appendRect(130, 710, 100, 40);
    shape->strokeFill(255, 0, 0);
    shape->strokeWidth(5);
    shape->strokeJoin(tvg::StrokeJoin::Round);
    shape->strokeCap(tvg::StrokeCap::Round);
    if (canvas_wg->push(std::move(shape)) != tvg::Result::Success) return;

    while (!glfwWindowShouldClose(window)) {
        // webgpu
        canvas_wg->draw();
        canvas_wg->sync();

        // pull events
        glfwPollEvents();
    }

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
    glfwDestroyWindow(window);
    glfwTerminate();
2023-12-26 18:18:42 +09:00
Hermet Park
875b623c95 binding/wasm: updated save features
- removed the compression option
- added an animation save function.
2023-12-26 18:17:41 +09:00
RuiwenTang
f3a155bce8 gl_engine: fix memory out of bounds error in GlGpuBuffer
If buffer data is larger than memory alignment, need to make sure there
is enough memory in current stage buffer
2023-12-26 18:17:41 +09:00
Hermet Park
b9504ca9c2 renderer: maintain consistency in the logging domain. 2023-12-26 18:17:41 +09:00
JunsuChoi
a20216045a saver GifSaver: Introduce GifSaver for animation
Add save() API that takes tvg::Animation as a parameter.
This API uses gif.h to create each animation frame as a gif frame.
Gif creation do not support threads because they must be added sequentially.
Please see example/GifSaver.cpp

ex)
auto animation = tvg::Animation::gen();
auto picture = animation->picture();
picture->load(EXAMPLE_DIR"/walker.json");
auto saver = tvg::Saver::gen();
saver->save(std::move(animation), EXAMPLE_DIR"/test.gif");
saver->sync();

New API:
Result Saver::save(std::unique_ptr<Animation> animation, const std::string& path, uint32_t quality = 100, uint32_t fps = 0);

Issue: https://github.com/thorvg/thorvg/issues/1712
2023-12-26 18:17:38 +09:00
Hermet Park
fba98c8cbf renderer: ++safety
these member values can be accesssed without update() call.
2023-12-26 18:06:07 +09:00
Hermet Park
37a01b8735 portability: addressed all compilation warnings from MSVC 2023-12-26 18:05:36 +09:00
Hermet Park
c8a8bb5af4 renderer/paint: added a blend update flag.
Keep track of the update changes accurately.
We can utilize this value change in the backend engine.
2023-12-26 18:05:22 +09:00
Hermet Park
c18643f9b6 renderer: revise the internal paints structure.
Get rid of the polymorphism function table,
use the switch directly instead.

We profiled, both binary & performance is better than before.

Tested on a local machine (single thread):
- Lottie: 2ms improved
- Binary: -0.5kb
2023-12-26 18:01:57 +09:00
Hermet Park
37fdfaf3d9 renderer/shape: enable returning count values only 2023-12-26 17:53:37 +09:00
Hermet Park
240d540091 canvas/paint: ++exception handling
enhanced reference count verification
to prevent unintentional deletion of used composition targets.
2023-12-26 17:53:25 +09:00
SergeyLebedkin
4f0fbc459c wg_engine: Added a feature to draw multiple radial gradient filled shapes 2023-12-26 17:51:59 +09:00
Hermet Park
0832a188fe animation/lottie: updated the frame count unit.
replace the frame count unit from the int32_t to float
since animations could smoothly interpolate key-frames.

This notificably improve the animation smoothness in Lottie

Beta API changes:
Result Animation::frame(uint32_t no) -> Result Animation::frame(float no)
uint32_t Animation::curFrame() const -> float Animation::curFrame() const
uint32_t Animation::totalFrame() const -> float Animation::totalFrame() const
2023-12-26 17:51:53 +09:00
RuiwenTang
2038818e16 gl_engine: use raw pointer to pass and hold GlRenderTask 2023-12-26 17:51:46 +09:00
Sergii Liebodkin
db1f171d2a wg_engine: Added ability to draw multiple linear gradient filled shapes
[issues 1479: LinearGradient](thorvg#1479)

In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html)

Usage example:

    // init glfw
    glfwInit();

    // create a windowed mode window and its opengl context
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr);

    // get window size
    int width{}, height{};
    glfwGetWindowSize(window, &width, &height);

    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    // gradient color stops
    tvg::Fill::ColorStop colorStops[2];
    colorStops[0] = {0, 0, 0, 0, 255};
    colorStops[1] = {1, 255, 255, 255, 255};
    // linear gradient
    auto fill = tvg::LinearGradient::gen();
    fill->linear(0, 0, 400, 400);
    fill->colorStops(colorStops, 2);
    // prepare rectangle
    auto shape1 = tvg::Shape::gen();
    shape1->appendRect(0, 0, 400, 400); //x, y, w, h
    shape1->fill(std::move(fill));
    canvas_wg->push(std::move(shape1));

    // gradient color stops
    tvg::Fill::ColorStop colorStops2[3];
    colorStops2[0] = { 0, 255, 0, 0, 255 };
    colorStops2[1] = { 0.5, 255, 255, 0, 255 };
    colorStops2[2] = { 1, 255, 255, 255, 255 };
    // linear gradient
    auto fill2 = tvg::LinearGradient::gen();
    fill2->linear(400, 200, 400, 600);
    fill2->colorStops(colorStops2, 3);
    // prepare circle
    auto shape2 = tvg::Shape::gen();
    shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH
    shape2->fill(std::move(fill2));
    canvas_wg->push(std::move(shape2));

    // gradient color stops
    tvg::Fill::ColorStop colorStops3[4];
    colorStops3[0] = { 0, 0, 127, 0, 127 };
    colorStops3[1] = { 0.25, 0, 170, 170, 170 };
    colorStops3[2] = { 0.5, 200, 0, 200, 200 };
    colorStops3[3] = { 1, 255, 255, 255, 255 };
    // linear gradient
    auto fill3 = tvg::LinearGradient::gen();
    fill3->linear(450, 600, 750, 600);
    fill3->colorStops(colorStops3, 4);
    // prepare ellipse
    auto shape3 = tvg::Shape::gen();
    shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH
    shape3->fill(std::move(fill3));
    canvas_wg->push(std::move(shape3));

    while (!glfwWindowShouldClose(window)) {
        // webgpu
        canvas_wg->draw();
        canvas_wg->sync();

        // pull events
        glfwPollEvents();
    }

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
    glfwDestroyWindow(window);
    glfwTerminate();
2023-12-26 17:51:39 +09:00
Hermet Park
97ac3194b4 sw_engine/raster: optimized the scaled image rasterization
Unified common logic for scaled image raster operations,
Avoid on-spot pixel computation as possible.

Tested on local machine (single thread)

Lottie: 0.057s -> 0.053s (-0.004s)
2023-12-26 17:51:23 +09:00
Sergii Liebodkin
938b69688d wg_engine: Added ability to draw multiple solid color filled shapes
[issues 1479: Shape](https://github.com/thorvg/thorvg/issues/1479)

In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html)

Usage example:

    // init glfw
    glfwInit();

    // create a windowed mode window and its opengl context
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr);

    // get window size
    int width{}, height{};
    glfwGetWindowSize(window, &width, &height);

    // init engine webgpu
    tvg::Initializer::init(tvg::CanvasEngine::Wg, 0);

    // create wg canvas
    auto canvasWg = tvg::WgCanvas::gen();
    canvas_wg->target(glfwGetWin32Window(window), width, height);

    // prepare a shape (Rectangle + Rectangle + Circle + Circle)
    auto shape1 = tvg::Shape::gen();
    shape1->appendRect(0, 0, 200, 200);                //x, y, w, h
    shape1->appendRect(100, 100, 300, 300, 100, 100);  //x, y, w, h, rx, ry
    shape1->appendCircle(400, 400, 100, 100);          //cx, cy, radiusW, radiusH
    shape1->appendCircle(400, 500, 170, 100);          //cx, cy, radiusW, radiusH
    shape1->fill(255, 255, 0);                         //r, g, b

    canvas_wg->push(std::move(shape1));

    while (!glfwWindowShouldClose(window)) {
        // webgpu
        canvas_wg->draw();
        canvas_wg->sync();

        // pull events
        glfwPollEvents();
    }

    // terminate engine and window
    tvg::Initializer::term(tvg::CanvasEngine::Wg);
    glfwDestroyWindow(window);
    glfwTerminate();
2023-12-26 17:51:17 +09:00