mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
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:
parent
be93b17563
commit
538db6e881
13 changed files with 242 additions and 8 deletions
|
@ -92,6 +92,8 @@ public:
|
||||||
Result transform(const Matrix& m) noexcept;
|
Result transform(const Matrix& m) noexcept;
|
||||||
Result bounds(float* x, float* y, float* w, float* h) const 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_ACCESSOR();
|
||||||
_TVG_DECLARE_PRIVATE(Paint);
|
_TVG_DECLARE_PRIVATE(Paint);
|
||||||
};
|
};
|
||||||
|
@ -248,6 +250,7 @@ public:
|
||||||
StrokeJoin strokeJoin() const noexcept;
|
StrokeJoin strokeJoin() const noexcept;
|
||||||
|
|
||||||
static std::unique_ptr<Shape> gen() noexcept;
|
static std::unique_ptr<Shape> gen() noexcept;
|
||||||
|
std::unique_ptr<Paint> duplicate() const noexcept override;
|
||||||
|
|
||||||
_TVG_DECLARE_PRIVATE(Shape);
|
_TVG_DECLARE_PRIVATE(Shape);
|
||||||
};
|
};
|
||||||
|
@ -271,6 +274,7 @@ public:
|
||||||
Result viewbox(float* x, float* y, float* w, float* h) const noexcept;
|
Result viewbox(float* x, float* y, float* w, float* h) const noexcept;
|
||||||
|
|
||||||
static std::unique_ptr<Picture> gen() noexcept;
|
static std::unique_ptr<Picture> gen() noexcept;
|
||||||
|
std::unique_ptr<Paint> duplicate() const noexcept override;
|
||||||
|
|
||||||
_TVG_DECLARE_PRIVATE(Picture);
|
_TVG_DECLARE_PRIVATE(Picture);
|
||||||
};
|
};
|
||||||
|
@ -293,6 +297,7 @@ public:
|
||||||
Result reserve(uint32_t size) noexcept;
|
Result reserve(uint32_t size) noexcept;
|
||||||
|
|
||||||
static std::unique_ptr<Scene> gen() noexcept;
|
static std::unique_ptr<Scene> gen() noexcept;
|
||||||
|
std::unique_ptr<Paint> duplicate() const noexcept override;
|
||||||
|
|
||||||
_TVG_DECLARE_PRIVATE(Scene);
|
_TVG_DECLARE_PRIVATE(Scene);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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_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_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_Result tvg_paint_transform(Tvg_Paint* paint, const Tvg_Matrix* m);
|
||||||
|
TVG_EXPORT Tvg_Paint* tvg_paint_duplicate(Tvg_Paint* paint);
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* Shape API */
|
/* Shape API */
|
||||||
|
|
|
@ -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 */
|
/* Shape API */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
|
@ -71,4 +71,4 @@ Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept
|
||||||
{
|
{
|
||||||
if (IMPL->bounds(x, y, w, h)) return Result::Success;
|
if (IMPL->bounds(x, y, w, h)) return Result::Success;
|
||||||
return Result::InsufficientCondition;
|
return Result::InsufficientCondition;
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,4 +177,4 @@ namespace tvg
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //_TVG_PAINT_H_
|
#endif //_TVG_PAINT_H_
|
||||||
|
|
|
@ -62,4 +62,11 @@ Result Picture::viewbox(float* x, float* y, float* w, float* h) const noexcept
|
||||||
{
|
{
|
||||||
if (IMPL->viewbox(x, y, w, h)) return Result::Success;
|
if (IMPL->viewbox(x, y, w, h)) return Result::Success;
|
||||||
return Result::InsufficientCondition;
|
return Result::InsufficientCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<Paint> Picture::duplicate() const noexcept
|
||||||
|
{
|
||||||
|
//TODO: implement
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -57,4 +57,11 @@ Result Scene::reserve(uint32_t size) noexcept
|
||||||
IMPL->paints.reserve(size);
|
IMPL->paints.reserve(size);
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<Paint> Scene::duplicate() const noexcept
|
||||||
|
{
|
||||||
|
//TODO: implement
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
Result Shape::reset() noexcept
|
||||||
{
|
{
|
||||||
IMPL->path->reset();
|
IMPL->path->reset();
|
||||||
|
@ -402,4 +410,4 @@ StrokeJoin Shape::strokeJoin() const noexcept
|
||||||
if (!IMPL->stroke) return StrokeJoin::Bevel;
|
if (!IMPL->stroke) return StrokeJoin::Bevel;
|
||||||
|
|
||||||
return IMPL->stroke->join;
|
return IMPL->stroke->join;
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,6 +162,46 @@ struct Shape::Impl
|
||||||
|
|
||||||
return true;
|
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_
|
#endif //_TVG_SHAPE_IMPL_H_
|
||||||
|
|
|
@ -38,7 +38,6 @@ struct ShapePath
|
||||||
uint32_t ptsCnt = 0;
|
uint32_t ptsCnt = 0;
|
||||||
uint32_t reservedPtsCnt = 0;
|
uint32_t reservedPtsCnt = 0;
|
||||||
|
|
||||||
|
|
||||||
~ShapePath()
|
~ShapePath()
|
||||||
{
|
{
|
||||||
if (cmds) free(cmds);
|
if (cmds) free(cmds);
|
||||||
|
|
|
@ -21,4 +21,5 @@ all:
|
||||||
gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
|
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 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 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`
|
gcc -o testCapi testCapi.c -g `pkg-config --cflags --libs elementary thorvg`
|
||||||
|
|
|
@ -135,6 +135,17 @@ void testCapi()
|
||||||
for(int i=0; i < ptsCnt; ++i) {
|
for(int i=0; i < ptsCnt; ++i) {
|
||||||
printf("(%.2lf, %.2lf)\n", pts[i].x, pts[i].y);
|
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_draw(canvas);
|
||||||
tvg_canvas_sync(canvas);
|
tvg_canvas_sync(canvas);
|
||||||
|
|
148
test/testDuplicate.cpp
Normal file
148
test/testDuplicate.cpp
Normal 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;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue