common: Introduced Accessor for traversing the scene-tree.

Basically, this Accessor is a utility to debug the Scene structure,
by traversing the scene-tree by users.

You can search specific nodes to read the property information,
figure out the structure of the scene tree and its size.

We actually don't recommend you to touch the property unless you really
know the each paint's position and role because it's not visible, difficult to
understand its anatomy.

Also, You must underatnd that modifying the nodes of the scene will be going
well with both the art-design structure and the prorgram logic.

In this first version, Accessor only supports for the Picture class.

@example:

auto picture = tvg::Picture::gen();
picture->load("test.svg");

//The callback function from lambda expression.
//This function will be called for every paint nodes of the tree.
auto f = [](const tvg::Paint* paint) -> bool
{
    if (paint->identifier() == Shape::identifier()) {
        //override properties?
        uint8_t r, g, b, a;
        paint->fillColor(&r, &g, &b, &a);
        paint->fill(r / 2, g / 2, b / 2, a);
    }

    //You can return false, to stop traversing immediately.
    return true;
};

auto accessor = tvg::Accessor::gen();

picture = accessor->access(move(picture), f);

...

@Issue: https://github.com/Samsung/thorvg/issues/693
This commit is contained in:
Hermet Park 2021-12-23 11:34:31 +09:00 committed by Hermet Park
parent 9915d41164
commit 100d98d82e
5 changed files with 295 additions and 0 deletions

View file

@ -50,6 +50,7 @@ protected: \
friend Canvas; \
friend Scene; \
friend Picture; \
friend Accessor; \
friend IteratorAccessor
@ -61,6 +62,7 @@ class IteratorAccessor;
class Scene;
class Picture;
class Canvas;
class Accessor;
/**
* @defgroup ThorVG ThorVG
@ -1533,6 +1535,49 @@ public:
_TVG_DECLARE_PRIVATE(Saver);
};
/**
* @class Accessor
*
* @brief The Accessor is a utility class to debug the Scene structure by traversing the scene-tree.
*
* The Accessor helps you search specific nodes to read the property information, figure out the structure of the scene tree and its size.
*
* @warning We strongly warn you not to change the paints of a scene unless you really know the design-structure.
*
* @BETA_API
*/
class TVG_EXPORT Accessor final
{
public:
~Accessor();
/**
* @brief Access the Picture scene stree nodes.
*
* @param[in] picture The picture node to traverse the internal scene-tree.
* @param[in] func The callback function calling for every paint nodes of the Picture.
*
* @return Return the given @p picture instance.
*
* @note The bitmap based picture might not have the scene-tree.
*
* @BETA_API
*/
std::unique_ptr<Picture> access(std::unique_ptr<Picture> picture, bool(*func)(const Paint* paint)) noexcept;
/**
* @brief Creates a new Accessor object.
*
* @return A new Accessor object.
*
* @BETA_API
*/
static std::unique_ptr<Accessor> gen() noexcept;
_TVG_DECLARE_PRIVATE(Accessor);
};
/** @}*/
} //namespace

164
src/examples/Accessor.cpp Normal file
View file

@ -0,0 +1,164 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "Common.h"
/************************************************************************/
/* Drawing Commands */
/************************************************************************/
void tvgDrawCmds(tvg::Canvas* canvas)
{
if (!canvas) return;
//load the tvg file
auto picture = tvg::Picture::gen();
if (picture->load(EXAMPLE_DIR"/favorite_on.svg") != tvg::Result::Success) return;
picture->size(WIDTH, HEIGHT);
auto accessor = tvg::Accessor::gen();
//The callback function from lambda expression.
//This function will be called for every paint nodes of the picture tree.
auto f = [](const tvg::Paint* paint) -> bool
{
if (paint->identifier() == tvg::Shape::identifier()) {
auto shape = (tvg::Shape*) paint;
//override color?
uint8_t r, g, b, a;
shape->fillColor(&r, &g, &b, &a);
if (r == 255 && g == 180 && b == 0)
shape->fill(0, 0, 255, a);
}
//You can return false, to stop traversing immediately.
return true;
};
picture = accessor->access(move(picture), f);
canvas->push(move(picture));
}
/************************************************************************/
/* Sw Engine Test Code */
/************************************************************************/
static unique_ptr<tvg::SwCanvas> swCanvas;
void tvgSwTest(uint32_t* buffer)
{
//Create a Canvas
swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare
internal data asynchronously for coming rendering.
Canvas keeps this shape node unless user call canvas->clear() */
tvgDrawCmds(swCanvas.get());
}
void drawSwView(void* data, Eo* obj)
{
if (swCanvas->draw() == tvg::Result::Success) {
swCanvas->sync();
}
}
/************************************************************************/
/* GL Engine Test Code */
/************************************************************************/
static unique_ptr<tvg::GlCanvas> glCanvas;
void initGLview(Evas_Object *obj)
{
static constexpr auto BPP = 4;
//Create a Canvas
glCanvas = tvg::GlCanvas::gen();
glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT);
/* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare
internal data asynchronously for coming rendering.
Canvas keeps this shape node unless user call canvas->clear() */
tvgDrawCmds(glCanvas.get());
}
void drawGLview(Evas_Object *obj)
{
auto gl = elm_glview_gl_api_get(obj);
gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl->glClear(GL_COLOR_BUFFER_BIT);
if (glCanvas->draw() == tvg::Result::Success) {
glCanvas->sync();
}
}
/************************************************************************/
/* Main Code */
/************************************************************************/
int main(int argc, char **argv)
{
tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw;
if (argc > 1) {
if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl;
}
//Initialize ThorVG Engine
if (tvgEngine == tvg::CanvasEngine::Sw) {
cout << "tvg engine: software" << endl;
} else {
cout << "tvg engine: opengl" << endl;
}
//Threads Count
auto threads = std::thread::hardware_concurrency();
//Initialize ThorVG Engine
if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) {
elm_init(argc, argv);
if (tvgEngine == tvg::CanvasEngine::Sw) {
createSwView();
} else {
createGlView();
}
elm_run();
elm_shutdown();
//Terminate ThorVG Engine
tvg::Initializer::term(tvgEngine);
} else {
cout << "engine is not supported" << endl;
}
return 0;
}

View file

@ -1,6 +1,7 @@
examples_dep = dependency('elementary', required : true)
source_file = [
'Accessor.cpp',
'AnimateMasking.cpp',
'Arc.cpp',
'Async.cpp',

View file

@ -25,6 +25,7 @@ source_file = [
'tvgSceneImpl.h',
'tvgShapeImpl.h',
'tvgTaskScheduler.h',
'tvgAccessor.cpp',
'tvgBezier.cpp',
'tvgCanvas.cpp',
'tvgFill.cpp',

84
src/lib/tvgAccessor.cpp Normal file
View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "tvgIteratorAccessor.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
static bool accessChildren(Iterator* it, bool(*func)(const Paint* paint), IteratorAccessor& itrAccessor)
{
while (auto child = it->next()) {
//Access the child
if (!func(child)) return false;
//Access the children of the child
if (auto it2 = itrAccessor.iterator(child)) {
if (!accessChildren(it2, func, itrAccessor)) {
delete(it2);
return false;
}
delete(it2);
}
}
return true;
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
unique_ptr<Picture> Accessor::access(unique_ptr<Picture> picture, bool(*func)(const Paint* paint)) noexcept
{
auto p = picture.get();
if (!p || !func) return picture;
//Use the Preorder Tree-Search
//Root
if (!func(p)) return picture;
//Children
IteratorAccessor itrAccessor;
if (auto it = itrAccessor.iterator(p)) {
accessChildren(it, func, itrAccessor);
delete(it);
}
return picture;
}
Accessor::~Accessor()
{
}
Accessor::Accessor()
{
}
unique_ptr<Accessor> Accessor::gen() noexcept
{
return unique_ptr<Accessor>(new Accessor);
}