shape: added duplicate api.

Changes:
1. New shape->duplicate(Shape) api.
2. New example: testDuplicate
3. Added capi binding for duploicate api
4. Added capi duplication test in testCapi.c

Description:

Added implementation of duplicate api. For now it supports stroke
properties and shape properties (fill color, path) duplication.

TODO:
Implement gradient properties duplication
This commit is contained in:
Michal Szczecinski 2020-09-10 12:55:08 +02:00 committed by Hermet Park
parent be93b17563
commit 538db6e881
13 changed files with 242 additions and 8 deletions

View file

@ -92,6 +92,8 @@ public:
Result transform(const Matrix& m) noexcept;
Result bounds(float* x, float* y, float* w, float* h) const noexcept;
virtual std::unique_ptr<Paint> duplicate() const noexcept = 0;
_TVG_DECLARE_ACCESSOR();
_TVG_DECLARE_PRIVATE(Paint);
};
@ -248,6 +250,7 @@ public:
StrokeJoin strokeJoin() const noexcept;
static std::unique_ptr<Shape> gen() noexcept;
std::unique_ptr<Paint> duplicate() const noexcept override;
_TVG_DECLARE_PRIVATE(Shape);
};
@ -271,6 +274,7 @@ public:
Result viewbox(float* x, float* y, float* w, float* h) const noexcept;
static std::unique_ptr<Picture> gen() noexcept;
std::unique_ptr<Paint> duplicate() const noexcept override;
_TVG_DECLARE_PRIVATE(Picture);
};
@ -293,6 +297,7 @@ public:
Result reserve(uint32_t size) noexcept;
static std::unique_ptr<Scene> gen() noexcept;
std::unique_ptr<Paint> duplicate() const noexcept override;
_TVG_DECLARE_PRIVATE(Scene);
};

View file

@ -120,7 +120,7 @@ TVG_EXPORT Tvg_Result tvg_paint_scale(Tvg_Paint* paint, float factor);
TVG_EXPORT Tvg_Result tvg_paint_rotate(Tvg_Paint* paint, float degree);
TVG_EXPORT Tvg_Result tvg_paint_translate(Tvg_Paint* paint, float x, float y);
TVG_EXPORT Tvg_Result tvg_paint_transform(Tvg_Paint* paint, const Tvg_Matrix* m);
TVG_EXPORT Tvg_Paint* tvg_paint_duplicate(Tvg_Paint* paint);
/************************************************************************/
/* Shape API */

View file

@ -177,6 +177,14 @@ TVG_EXPORT Tvg_Result tvg_paint_transform(Tvg_Paint* paint, const Tvg_Matrix* m)
}
TVG_EXPORT Tvg_Paint* tvg_paint_duplicate(Tvg_Paint* paint)
{
if (!paint) return NULL;
return (Tvg_Paint*) reinterpret_cast<Paint*>(paint)->duplicate().release();
}
/************************************************************************/
/* Shape API */
/************************************************************************/

View file

@ -63,3 +63,10 @@ Result Picture::viewbox(float* x, float* y, float* w, float* h) const noexcept
if (IMPL->viewbox(x, y, w, h)) return Result::Success;
return Result::InsufficientCondition;
}
std::unique_ptr<Paint> Picture::duplicate() const noexcept
{
//TODO: implement
return nullptr;
}

View file

@ -58,3 +58,10 @@ Result Scene::reserve(uint32_t size) noexcept
return Result::Success;
}
std::unique_ptr<Paint> Scene::duplicate() const noexcept
{
//TODO: implement
return nullptr;
}

View file

@ -49,6 +49,14 @@ unique_ptr<Shape> Shape::gen() noexcept
}
unique_ptr<Paint> Shape::duplicate() const noexcept
{
auto shape = Shape::gen();
shape->pImpl->duplicate(IMPL);
return shape;
}
Result Shape::reset() noexcept
{
IMPL->path->reset();

View file

@ -162,6 +162,46 @@ struct Shape::Impl
return true;
}
void duplicate(Shape::Impl *s)
{
if (memcmp(color, s->color, sizeof(color))) {
memcpy(color, s->color, sizeof(color));
flag = RenderUpdateFlag::Color;
}
if (s->path) {
path = new ShapePath();
path->cmdCnt = s->path->cmdCnt;
path->ptsCnt = s->path->ptsCnt;
path->reservedCmdCnt = s->path->reservedCmdCnt;
path->reservedPtsCnt = s->path->reservedPtsCnt;
path->cmds = static_cast<PathCommand*>(malloc(sizeof(PathCommand) * path->reservedCmdCnt));
path->pts = static_cast<Point*>(malloc(sizeof(Point) * path->reservedPtsCnt));
memcpy(path->cmds, s->path->cmds, sizeof(PathCommand) * s->path->cmdCnt);
memcpy(path->pts, s->path->pts, sizeof(Point) * s->path->ptsCnt);
flag = RenderUpdateFlag::Path;
}
if (s->stroke) {
stroke = new ShapeStroke();
strokeCap(s->stroke->cap);
strokeColor(s->stroke->color[0], s->stroke->color[1],
s->stroke->color[2], s->stroke->color[3]);
strokeJoin(s->stroke->join);
strokeWidth(s->stroke->width);
if (s->stroke->dashPattern && s->stroke->dashCnt > 0) {
strokeDash(s->stroke->dashPattern, s->stroke->dashCnt);
}
}
//TODO: add fill
}
};
#endif //_TVG_SHAPE_IMPL_H_

View file

@ -38,7 +38,6 @@ struct ShapePath
uint32_t ptsCnt = 0;
uint32_t reservedPtsCnt = 0;
~ShapePath()
{
if (cmds) free(cmds);

View file

@ -21,4 +21,5 @@ all:
gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testArc testArc.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testMultiCanvas testMultiCanvas.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testDuplicate testDuplicate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
gcc -o testCapi testCapi.c -g `pkg-config --cflags --libs elementary thorvg`

View file

@ -136,6 +136,17 @@ void testCapi()
printf("(%.2lf, %.2lf)\n", pts[i].x, pts[i].y);
}
//Origin paint for duplicated
Tvg_Paint* org = tvg_shape_new();
tvg_shape_append_rect(org, 550, 10, 100, 100, 0, 0);
tvg_shape_set_stroke_width(org, 3);
tvg_shape_set_stroke_color(org, 255, 0, 0, 255);
tvg_shape_set_fill_color(org, 0, 255, 0, 255);
//Duplicated paint test - should copy rectangle parameters from origin
Tvg_Paint* dup = tvg_paint_duplicate(org);
tvg_canvas_push(canvas, dup);
tvg_canvas_draw(canvas);
tvg_canvas_sync(canvas);

148
test/testDuplicate.cpp Normal file
View file

@ -0,0 +1,148 @@
#include "testCommon.h"
/************************************************************************/
/* Drawing Commands */
/************************************************************************/
void tvgDrawCmds(tvg::Canvas* canvas)
{
if (!canvas) return;
//Prepare first shape, which will not be drawn
auto shape1 = tvg::Shape::gen();
shape1->appendRect(10, 10, 200, 200, 0, 0);
shape1->appendRect(220, 10, 100, 100, 0, 0);
shape1->stroke(3);
shape1->stroke(0, 255, 0, 255);
float dashPattern[2] = {4, 4};
shape1->stroke(dashPattern, 2);
shape1->fill(255, 0, 0, 255);
//Create second shape and duplicate parameters
auto shape2 = shape1->duplicate();
//Create third shape, duplicate from first and add some new parameters
auto shape3 = shape1->duplicate();
//Get access to valid derived class type
tvg::Shape* shapePtr = reinterpret_cast<tvg::Shape*>(shape3.get());
//move shape3 to new postion to don't cover second shape
shape3->translate(0, 220);
//append new paths
shapePtr->appendRect(340, 10, 100, 100, 0, 0);
shapePtr->fill(0, 0, 255, 255);
//TODO: test gradient
canvas->push(move(shape2));
canvas->push(move(shape3));
}
/************************************************************************/
/* 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;
}